This commit is contained in:
Anton Lavrenov 2021-05-04 08:57:03 -05:00
parent ca1de3a351
commit 1c6bc48c83
15 changed files with 22753 additions and 11759 deletions

View File

@ -3,7 +3,15 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## **NOT RELEASED V8**
- All updates on canvas will do automatic redraw with `layer.batchDraw()`. This features is configurable with `Konva.autoDrawEnbaled` property.
- Full migration to ES modules package, commonjs code is removed
- `konva-node` is merged into `konva` npm package. One package works for both environments.
- Fix `TextPath` recalculations on `fontSize` change
- `Konva.Collection` is removed. `container.children` is a simple array now. `container.find()` will return also a simple array instead of `Konva.Collection()`.
- Better typescript support. Now every module has its own `*.d.ts` file.
- New method `layer.getNativeCanvasElement()`
## 7.2.5

25012
konva.js

File diff suppressed because it is too large Load Diff

9256
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -236,7 +236,7 @@ export class Animation {
if (!layerHash.hasOwnProperty(key)) {
continue;
}
layerHash[key].draw();
layerHash[key].batchDraw();
}
}
static _animationLoop() {

View File

@ -133,6 +133,7 @@ export abstract class Container<
this._fire('add', {
child: child,
});
this._requestDraw();
// chainable
return this;
}
@ -324,6 +325,7 @@ export abstract class Container<
this.children?.forEach(function (child, n) {
child.index = n;
});
this._requestDraw();
}
drawScene(can?: SceneCanvas, top?: Node) {
var layer = this.getLayer(),

View File

@ -97,7 +97,16 @@ export const Konva = {
},
enableTrace: false,
_pointerEventsEnabled: false,
autoDrawEnabled: false,
/**
* Should Konva automatically update canvas on any changes. Default is true.
* @property autoDrawEnabled
* @default true
* @name autoDrawEnabled
* @memberof Konva
* @example
* Konva.autoDrawEnabled = true;
*/
autoDrawEnabled: true,
/**
* Should we enable hit detection while dragging? For performance reasons, by default it is false.
* But on some rare cases you want to see hit graph and check intersections. Just set it to true.

View File

@ -88,7 +88,7 @@ export class Layer extends Container<Group | Shape> {
* @method
* @name Konva.Layer#getCanvas
*/
getCanvasElement() {
getNativeCanvasElement() {
return this.canvas._canvas;
}
/**
@ -136,15 +136,15 @@ export class Layer extends Container<Group | Shape> {
super.setZIndex(index);
var stage = this.getStage();
if (stage && stage.content) {
stage.content.removeChild(this.getCanvasElement());
stage.content.removeChild(this.getNativeCanvasElement());
if (index < stage.children.length - 1) {
stage.content.insertBefore(
this.getCanvasElement(),
this.getNativeCanvasElement(),
stage.children[index + 1].getCanvas()._canvas
);
} else {
stage.content.appendChild(this.getCanvasElement());
stage.content.appendChild(this.getNativeCanvasElement());
}
}
return this;
@ -153,8 +153,8 @@ export class Layer extends Container<Group | Shape> {
Node.prototype.moveToTop.call(this);
var stage = this.getStage();
if (stage && stage.content) {
stage.content.removeChild(this.getCanvasElement());
stage.content.appendChild(this.getCanvasElement());
stage.content.removeChild(this.getNativeCanvasElement());
stage.content.appendChild(this.getNativeCanvasElement());
}
return true;
}
@ -167,15 +167,15 @@ export class Layer extends Container<Group | Shape> {
if (!stage || !stage.content) {
return false;
}
stage.content.removeChild(this.getCanvasElement());
stage.content.removeChild(this.getNativeCanvasElement());
if (this.index < stage.children.length - 1) {
stage.content.insertBefore(
this.getCanvasElement(),
this.getNativeCanvasElement(),
stage.children[this.index + 1].getCanvas()._canvas
);
} else {
stage.content.appendChild(this.getCanvasElement());
stage.content.appendChild(this.getNativeCanvasElement());
}
return true;
}
@ -186,9 +186,9 @@ export class Layer extends Container<Group | Shape> {
if (stage) {
var children = stage.children;
if (stage.content) {
stage.content.removeChild(this.getCanvasElement());
stage.content.removeChild(this.getNativeCanvasElement());
stage.content.insertBefore(
this.getCanvasElement(),
this.getNativeCanvasElement(),
children[this.index + 1].getCanvas()._canvas
);
}
@ -204,9 +204,9 @@ export class Layer extends Container<Group | Shape> {
if (stage) {
var children = stage.children;
if (stage.content) {
stage.content.removeChild(this.getCanvasElement());
stage.content.removeChild(this.getNativeCanvasElement());
stage.content.insertBefore(
this.getCanvasElement(),
this.getNativeCanvasElement(),
children[1].getCanvas()._canvas
);
}
@ -219,7 +219,7 @@ export class Layer extends Container<Group | Shape> {
return this;
}
remove() {
var _canvas = this.getCanvasElement();
var _canvas = this.getNativeCanvasElement();
Node.prototype.remove.call(this);

View File

@ -303,6 +303,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
clearCache() {
this._cache.delete(CANVAS);
this._clearSelfAndDescendantCache();
this._requestDraw();
return this;
}
/**
@ -463,6 +464,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
y: y,
});
this._requestDraw();
return this;
}
@ -2219,6 +2222,12 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
}
return this;
}
_requestDraw() {
if (Konva.autoDrawEnabled) {
const drawNode = this.getLayer() || this.getStage();
drawNode?.batchDraw();
}
}
_setAttr(key, val, skipFire = false) {
var oldVal = this.attrs[key];
if (oldVal === val && !Util.isObject(val)) {
@ -2232,10 +2241,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
if (this._shouldFireChangeEvents) {
this._fireChangeEvent(key, oldVal, val);
}
if (Konva.autoDrawEnabled) {
const drawNode = this.getLayer() || this.getStage();
drawNode?.batchDraw();
}
this._requestDraw();
}
_setComponentAttr(key, component, val) {
var oldVal;

View File

@ -1069,7 +1069,7 @@ export class Stage extends Container<Layer> {
* @return {Konva.Stage} this
*/
batchDraw() {
this.children.forEach(function (layer) {
this.getChildren().forEach(function (layer) {
layer.batchDraw();
});
return this;

View File

@ -36,6 +36,22 @@ export interface ImageConfig extends ShapeConfig {
* imageObj.src = '/path/to/image.jpg'
*/
export class Image extends Shape<ImageConfig> {
constructor(attrs: ImageConfig) {
super(attrs);
this.on('imageChange.konva', (e) => {
this._setImageLoad();
});
this._setImageLoad();
}
_setImageLoad() {
const image = this.image();
if (image && image['addEventListener']) {
image['addEventListener']('load', () => {
this._requestDraw();
});
}
}
_useBufferCanvas() {
return super._useBufferCanvas(true);
}

View File

@ -11,12 +11,13 @@
<body>
<div id="container"></div>
<!-- this line for dev version -->
<script src="../../"></script>
<script src="../../src/index.ts"></script>
<!-- this line for old version -->
<!-- <script src="https://unpkg.com/konva@7.0.3/konva.min.js"></script> -->
<script src="http://www.html5canvastutorials.com/lib/stats/stats.js"></script>
<script defer="defer">
Konva.isUnminified = false;
// Konva.autoDrawEnabled = trye;
var lastTime = 0;
var width = window.innerWidth;
@ -189,7 +190,10 @@
y: pos.y,
});
}
layer.draw();
if (!Konva.autoDrawEnabled) {
layer.draw();
}
requestAnimationFrame(update);
stats.end();
}

View File

@ -44,6 +44,7 @@
import './unit/Shape-test.ts';
import './unit/Node-test.ts';
import './unit/Node-cache-test.ts';
import './unit/AutoDraw-test.ts';
// SHAPES
import './unit/Rect-test.ts';

137
test/unit/AutoDraw-test.ts Normal file
View File

@ -0,0 +1,137 @@
import { assert } from 'chai';
import { addStage, isNode, Konva } from './utis';
describe('AutoDraw', function () {
// ======================================================
it('schedule draw on shape add/change/remove', function () {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
let callCount = 0;
layer.batchDraw = function () {
callCount += 1;
Konva.Layer.prototype.batchDraw.call(this);
return layer;
};
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle);
assert.equal(callCount, 1);
circle.radius(50);
assert.equal(callCount, 2);
circle.destroy();
assert.equal(callCount, 3);
});
// ======================================================
it('schedule draw on order change', function () {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle);
var circle2 = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle2);
let callCount = 0;
layer.batchDraw = function () {
callCount += 1;
Konva.Layer.prototype.batchDraw.call(this);
return layer;
};
circle.moveToTop();
assert.equal(callCount, 1);
});
// ======================================================
it('schedule draw on cache', function () {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var circle = new Konva.Circle({
x: stage.width() / 2,
y: stage.height() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
name: 'myCircle',
});
layer.add(circle);
let callCount = 0;
layer.batchDraw = function () {
callCount += 1;
Konva.Layer.prototype.batchDraw.call(this);
return layer;
};
circle.cache();
assert.equal(callCount, 1);
circle.clearCache();
assert.equal(callCount, 2);
});
// ======================================================
it.only('redraw for images', function (done) {
// don't test on node, because of specific url access
if (isNode) {
return;
}
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
const { src } = document.getElementById(
'darth-vader.jpg'
) as HTMLImageElement;
const img = new Image();
img.src = src;
const image = new Konva.Image({
image: img,
});
layer.add(image);
let callCount = 0;
layer.batchDraw = function () {
callCount += 1;
Konva.Layer.prototype.batchDraw.call(this);
return layer;
};
img.onload = () => {
assert.equal(callCount, 1);
done();
};
});
});

View File

@ -302,7 +302,7 @@ describe('Layer', function () {
stage.add(layer);
assert(layer.getCanvasElement().style.display === 'none');
assert(layer.getNativeCanvasElement().style.display === 'none');
});
// ======================================================

View File

@ -15,7 +15,7 @@ import { Stage } from '../../src/Stage';
// reset some data
beforeEach(function () {
Konva.inDblClickWindow = false;
Konva['inDblClickWindow'] = false;
});
export const isNode = typeof global.document === 'undefined';
@ -120,7 +120,7 @@ export function compareCanvases(canvas1, canvas2, tol?, secondTol?) {
}
export function compareLayerAndCanvas(layer: Layer, canvas, tol?, secondTol?) {
compareCanvases(layer.getCanvasElement(), canvas, tol, secondTol);
compareCanvases(layer.getNativeCanvasElement(), canvas, tol, secondTol);
}
export function cloneAndCompareLayer(layer: Layer, tol?, secondTol?) {
@ -131,7 +131,12 @@ export function cloneAndCompareLayer(layer: Layer, tol?, secondTol?) {
}
export function compareLayers(layer1: Layer, layer2: Layer, tol?, secondTol?) {
compareLayerAndCanvas(layer1, layer2.getCanvasElement(), tol, secondTol);
compareLayerAndCanvas(
layer1,
layer2.getNativeCanvasElement(),
tol,
secondTol
);
}
export function createCanvas() {
@ -152,7 +157,7 @@ export function showHit(layer) {
getContainer().appendChild(canvas);
}
Konva.UA.mobile = false;
Konva['UA'].mobile = false;
export function simulateMouseDown(stage, pos) {
var top = isNode ? 0 : stage.content.getBoundingClientRect().top;