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. All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/). 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 - 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 ## 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)) { if (!layerHash.hasOwnProperty(key)) {
continue; continue;
} }
layerHash[key].draw(); layerHash[key].batchDraw();
} }
} }
static _animationLoop() { static _animationLoop() {

View File

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

View File

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

View File

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

View File

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

View File

@@ -36,6 +36,22 @@ export interface ImageConfig extends ShapeConfig {
* imageObj.src = '/path/to/image.jpg' * imageObj.src = '/path/to/image.jpg'
*/ */
export class Image extends Shape<ImageConfig> { 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() { _useBufferCanvas() {
return super._useBufferCanvas(true); return super._useBufferCanvas(true);
} }

View File

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

View File

@@ -44,6 +44,7 @@
import './unit/Shape-test.ts'; import './unit/Shape-test.ts';
import './unit/Node-test.ts'; import './unit/Node-test.ts';
import './unit/Node-cache-test.ts'; import './unit/Node-cache-test.ts';
import './unit/AutoDraw-test.ts';
// SHAPES // SHAPES
import './unit/Rect-test.ts'; 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); 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 // reset some data
beforeEach(function () { beforeEach(function () {
Konva.inDblClickWindow = false; Konva['inDblClickWindow'] = false;
}); });
export const isNode = typeof global.document === 'undefined'; 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?) { 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?) { 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?) { export function compareLayers(layer1: Layer, layer2: Layer, tol?, secondTol?) {
compareLayerAndCanvas(layer1, layer2.getCanvasElement(), tol, secondTol); compareLayerAndCanvas(
layer1,
layer2.getNativeCanvasElement(),
tol,
secondTol
);
} }
export function createCanvas() { export function createCanvas() {
@@ -152,7 +157,7 @@ export function showHit(layer) {
getContainer().appendChild(canvas); getContainer().appendChild(canvas);
} }
Konva.UA.mobile = false; Konva['UA'].mobile = false;
export function simulateMouseDown(stage, pos) { export function simulateMouseDown(stage, pos) {
var top = isNode ? 0 : stage.content.getBoundingClientRect().top; var top = isNode ? 0 : stage.content.getBoundingClientRect().top;