mirror of
https://github.com/konvajs/konva.git
synced 2025-04-05 20:48:28 +08:00
performance optimizations
This commit is contained in:
parent
43b23e9559
commit
1d8388eead
@ -5,11 +5,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|||||||
|
|
||||||
## Not released:
|
## Not released:
|
||||||
|
|
||||||
* `inherit` option is removed from `visible` and `listening`. They now just have boolean values `true` or `false`. If you do `group.listeng(false);` then whole group and all its children will be removed from the hitgraph (and they will not listen to events);
|
* `inherit` option is removed from `visible` and `listening`. They now just have boolean values `true` or `false`. If you do `group.listening(false);` then whole group and all its children will be removed from the hitgraph (and they will not listen to events);
|
||||||
* `layer.hitGraphEnabled()` is deprecated. Just use `layer.listening(false)` instead
|
* `layer.hitGraphEnabled()` is deprecated. Just use `layer.listening(false)` instead
|
||||||
* Some performance fixes and code size optimizations
|
* Some performance fixes and code size optimizations
|
||||||
* Better support for font families with spaces inside (like `Font Awesome 5`).
|
* Better support for font families with spaces inside (like `Font Awesome 5`).
|
||||||
* Fix possible `dblclick` and `dbltap` triggers
|
* Fix possible `dblclick` and `dbltap` triggers
|
||||||
|
* Deprecate `Konva.FastLayer`. Use `new Konva.Layer({ listening: false });` instead.
|
||||||
|
* Up to 20% performance boost for many moving nodes.
|
||||||
|
|
||||||
|
|
||||||
## 6.0.0 - 2020-05-08
|
## 6.0.0 - 2020-05-08
|
||||||
|
108
konva.js
108
konva.js
@ -8,7 +8,7 @@
|
|||||||
* Konva JavaScript Framework v6.0.0
|
* Konva JavaScript Framework v6.0.0
|
||||||
* http://konvajs.org/
|
* http://konvajs.org/
|
||||||
* Licensed under the MIT
|
* Licensed under the MIT
|
||||||
* Date: Tue Jun 09 2020
|
* Date: Wed Jun 10 2020
|
||||||
*
|
*
|
||||||
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
|
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
|
||||||
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
|
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
|
||||||
@ -301,8 +301,17 @@
|
|||||||
var Transform = /** @class */ (function () {
|
var Transform = /** @class */ (function () {
|
||||||
function Transform(m) {
|
function Transform(m) {
|
||||||
if (m === void 0) { m = [1, 0, 0, 1, 0, 0]; }
|
if (m === void 0) { m = [1, 0, 0, 1, 0, 0]; }
|
||||||
|
this.dirty = false;
|
||||||
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
||||||
}
|
}
|
||||||
|
Transform.prototype.reset = function () {
|
||||||
|
this.m[0] = 1;
|
||||||
|
this.m[1] = 0;
|
||||||
|
this.m[2] = 0;
|
||||||
|
this.m[3] = 1;
|
||||||
|
this.m[4] = 0;
|
||||||
|
this.m[5] = 0;
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Copy Konva.Transform object
|
* Copy Konva.Transform object
|
||||||
* @method
|
* @method
|
||||||
@ -314,6 +323,14 @@
|
|||||||
Transform.prototype.copy = function () {
|
Transform.prototype.copy = function () {
|
||||||
return new Transform(this.m);
|
return new Transform(this.m);
|
||||||
};
|
};
|
||||||
|
Transform.prototype.copyInto = function (tr) {
|
||||||
|
tr.m[0] = this.m[0];
|
||||||
|
tr.m[1] = this.m[1];
|
||||||
|
tr.m[2] = this.m[2];
|
||||||
|
tr.m[3] = this.m[3];
|
||||||
|
tr.m[4] = this.m[4];
|
||||||
|
tr.m[5] = this.m[5];
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* Transform point
|
* Transform point
|
||||||
* @method
|
* @method
|
||||||
@ -325,7 +342,7 @@
|
|||||||
var m = this.m;
|
var m = this.m;
|
||||||
return {
|
return {
|
||||||
x: m[0] * point.x + m[2] * point.y + m[4],
|
x: m[0] * point.x + m[2] * point.y + m[4],
|
||||||
y: m[1] * point.x + m[3] * point.y + m[5]
|
y: m[1] * point.x + m[3] * point.y + m[5],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -385,7 +402,7 @@
|
|||||||
Transform.prototype.getTranslation = function () {
|
Transform.prototype.getTranslation = function () {
|
||||||
return {
|
return {
|
||||||
x: this.m[4],
|
x: this.m[4],
|
||||||
y: this.m[5]
|
y: this.m[5],
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -491,7 +508,7 @@
|
|||||||
scaleX: 0,
|
scaleX: 0,
|
||||||
scaleY: 0,
|
scaleY: 0,
|
||||||
skewX: 0,
|
skewX: 0,
|
||||||
skewY: 0
|
skewY: 0,
|
||||||
};
|
};
|
||||||
// Apply the QR-like decomposition.
|
// Apply the QR-like decomposition.
|
||||||
if (a != 0 || b != 0) {
|
if (a != 0 || b != 0) {
|
||||||
@ -666,7 +683,7 @@
|
|||||||
white: [255, 255, 255],
|
white: [255, 255, 255],
|
||||||
whitesmoke: [245, 245, 245],
|
whitesmoke: [245, 245, 245],
|
||||||
yellow: [255, 255, 0],
|
yellow: [255, 255, 0],
|
||||||
yellowgreen: [154, 205, 5]
|
yellowgreen: [154, 205, 5],
|
||||||
}, RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/, animQueue = [];
|
}, RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/, animQueue = [];
|
||||||
/**
|
/**
|
||||||
* @namespace Util
|
* @namespace Util
|
||||||
@ -789,7 +806,7 @@
|
|||||||
return {
|
return {
|
||||||
r: (bigint >> 16) & 255,
|
r: (bigint >> 16) & 255,
|
||||||
g: (bigint >> 8) & 255,
|
g: (bigint >> 8) & 255,
|
||||||
b: bigint & 255
|
b: bigint & 255,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -833,7 +850,7 @@
|
|||||||
return {
|
return {
|
||||||
r: rgb[0],
|
r: rgb[0],
|
||||||
g: rgb[1],
|
g: rgb[1],
|
||||||
b: rgb[2]
|
b: rgb[2],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else if (color[0] === HASH) {
|
else if (color[0] === HASH) {
|
||||||
@ -846,7 +863,7 @@
|
|||||||
return {
|
return {
|
||||||
r: parseInt(rgb[1], 10),
|
r: parseInt(rgb[1], 10),
|
||||||
g: parseInt(rgb[2], 10),
|
g: parseInt(rgb[2], 10),
|
||||||
b: parseInt(rgb[3], 10)
|
b: parseInt(rgb[3], 10),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -854,7 +871,7 @@
|
|||||||
return {
|
return {
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 0,
|
g: 0,
|
||||||
b: 0
|
b: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -879,7 +896,7 @@
|
|||||||
r: c[0],
|
r: c[0],
|
||||||
g: c[1],
|
g: c[1],
|
||||||
b: c[2],
|
b: c[2],
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Parse rgb(n, n, n)
|
// Parse rgb(n, n, n)
|
||||||
@ -891,7 +908,7 @@
|
|||||||
r: parts[0],
|
r: parts[0],
|
||||||
g: parts[1],
|
g: parts[1],
|
||||||
b: parts[2],
|
b: parts[2],
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -904,7 +921,7 @@
|
|||||||
r: parts[0],
|
r: parts[0],
|
||||||
g: parts[1],
|
g: parts[1],
|
||||||
b: parts[2],
|
b: parts[2],
|
||||||
a: parts[3]
|
a: parts[3],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -915,7 +932,7 @@
|
|||||||
r: parseInt(str.slice(1, 3), 16),
|
r: parseInt(str.slice(1, 3), 16),
|
||||||
g: parseInt(str.slice(3, 5), 16),
|
g: parseInt(str.slice(3, 5), 16),
|
||||||
b: parseInt(str.slice(5, 7), 16),
|
b: parseInt(str.slice(5, 7), 16),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -926,7 +943,7 @@
|
|||||||
r: parseInt(str[1] + str[1], 16),
|
r: parseInt(str[1] + str[1], 16),
|
||||||
g: parseInt(str[2] + str[2], 16),
|
g: parseInt(str[2] + str[2], 16),
|
||||||
b: parseInt(str[3] + str[3], 16),
|
b: parseInt(str[3] + str[3], 16),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -948,7 +965,7 @@
|
|||||||
r: Math.round(val),
|
r: Math.round(val),
|
||||||
g: Math.round(val),
|
g: Math.round(val),
|
||||||
b: Math.round(val),
|
b: Math.round(val),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (l < 0.5) {
|
if (l < 0.5) {
|
||||||
@ -985,7 +1002,7 @@
|
|||||||
r: Math.round(rgb[0]),
|
r: Math.round(rgb[0]),
|
||||||
g: Math.round(rgb[1]),
|
g: Math.round(rgb[1]),
|
||||||
b: Math.round(rgb[2]),
|
b: Math.round(rgb[2]),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1145,13 +1162,13 @@
|
|||||||
for (n = 0; n < startArray.length; n += 2) {
|
for (n = 0; n < startArray.length; n += 2) {
|
||||||
start.push({
|
start.push({
|
||||||
x: startArray[n],
|
x: startArray[n],
|
||||||
y: startArray[n + 1]
|
y: startArray[n + 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (n = 0; n < endArray.length; n += 2) {
|
for (n = 0; n < endArray.length; n += 2) {
|
||||||
end.push({
|
end.push({
|
||||||
x: endArray[n],
|
x: endArray[n],
|
||||||
y: endArray[n + 1]
|
y: endArray[n + 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var newStart = [];
|
var newStart = [];
|
||||||
@ -1206,7 +1223,7 @@
|
|||||||
else {
|
else {
|
||||||
return evt.changedTouches[0].identifier;
|
return evt.changedTouches[0].identifier;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function _formatValue(val) {
|
function _formatValue(val) {
|
||||||
@ -2660,9 +2677,16 @@
|
|||||||
Node.prototype.getChildren = function () {
|
Node.prototype.getChildren = function () {
|
||||||
return emptyChildren;
|
return emptyChildren;
|
||||||
};
|
};
|
||||||
/** @lends Konva.Node.prototype */
|
|
||||||
Node.prototype._clearCache = function (attr) {
|
Node.prototype._clearCache = function (attr) {
|
||||||
if (attr) {
|
// if we want to clear transform cache
|
||||||
|
// we don't really need to remove it from the cache
|
||||||
|
// but instead mark as "dirty"
|
||||||
|
// so we don't need to create a new instance next time
|
||||||
|
if ((attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM) &&
|
||||||
|
this._cache.get(attr)) {
|
||||||
|
this._cache.get(attr).dirty = true;
|
||||||
|
}
|
||||||
|
else if (attr) {
|
||||||
this._cache.delete(attr);
|
this._cache.delete(attr);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -2671,8 +2695,12 @@
|
|||||||
};
|
};
|
||||||
Node.prototype._getCache = function (attr, privateGetter) {
|
Node.prototype._getCache = function (attr, privateGetter) {
|
||||||
var cache = this._cache.get(attr);
|
var cache = this._cache.get(attr);
|
||||||
|
// for transform the cache can be NOT empty
|
||||||
|
// but we still need to recalculate it if it is dirty
|
||||||
|
var isTransform = attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM;
|
||||||
|
var invalid = cache === undefined || (isTransform && cache.dirty === true);
|
||||||
// if not cached, we need to set it using the private getter method.
|
// if not cached, we need to set it using the private getter method.
|
||||||
if (cache === undefined) {
|
if (invalid) {
|
||||||
cache = privateGetter.call(this);
|
cache = privateGetter.call(this);
|
||||||
this._cache.set(attr, cache);
|
this._cache.set(attr, cache);
|
||||||
}
|
}
|
||||||
@ -3934,12 +3962,13 @@
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// try to use a cached value
|
// try to use a cached value
|
||||||
|
at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform();
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
// transform will be cached
|
// transform will be cached
|
||||||
at = this.parent.getAbsoluteTransform().copy();
|
this.parent.getAbsoluteTransform().copyInto(at);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
at = new Transform();
|
at.reset();
|
||||||
}
|
}
|
||||||
var transformsEnabled = this.transformsEnabled();
|
var transformsEnabled = this.transformsEnabled();
|
||||||
if (transformsEnabled === 'all') {
|
if (transformsEnabled === 'all') {
|
||||||
@ -3948,6 +3977,7 @@
|
|||||||
else if (transformsEnabled === 'position') {
|
else if (transformsEnabled === 'position') {
|
||||||
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
||||||
}
|
}
|
||||||
|
at.dirty = false;
|
||||||
return at;
|
return at;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -4009,7 +4039,9 @@
|
|||||||
return this._getCache(TRANSFORM, this._getTransform);
|
return this._getCache(TRANSFORM, this._getTransform);
|
||||||
};
|
};
|
||||||
Node.prototype._getTransform = function () {
|
Node.prototype._getTransform = function () {
|
||||||
var m = new Transform(), x = this.x(), y = this.y(), rotation = Konva.getAngle(this.rotation()), scaleX = this.scaleX(), scaleY = this.scaleY(), skewX = this.skewX(), skewY = this.skewY(), offsetX = this.offsetX(), offsetY = this.offsetY();
|
var m = this._cache.get(TRANSFORM) || new Transform();
|
||||||
|
m.reset();
|
||||||
|
var x = this.x(), y = this.y(), rotation = Konva.getAngle(this.rotation()), scaleX = this.scaleX(), scaleY = this.scaleY(), skewX = this.skewX(), skewY = this.skewY(), offsetX = this.offsetX(), offsetY = this.offsetY();
|
||||||
if (x !== 0 || y !== 0) {
|
if (x !== 0 || y !== 0) {
|
||||||
m.translate(x, y);
|
m.translate(x, y);
|
||||||
}
|
}
|
||||||
@ -4025,6 +4057,7 @@
|
|||||||
if (offsetX !== 0 || offsetY !== 0) {
|
if (offsetX !== 0 || offsetY !== 0) {
|
||||||
m.translate(-1 * offsetX, -1 * offsetY);
|
m.translate(-1 * offsetX, -1 * offsetY);
|
||||||
}
|
}
|
||||||
|
m.dirty = false;
|
||||||
return m;
|
return m;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
@ -5465,7 +5498,8 @@
|
|||||||
}
|
}
|
||||||
if (cachedSceneCanvas) {
|
if (cachedSceneCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedSceneCanvas(context);
|
this._drawCachedSceneCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
@ -5481,7 +5515,8 @@
|
|||||||
var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas), context = canvas && canvas.getContext(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
|
var layer = this.getLayer(), canvas = can || (layer && layer.hitCanvas), context = canvas && canvas.getContext(), cachedCanvas = this._getCanvasCache(), cachedHitCanvas = cachedCanvas && cachedCanvas.hit;
|
||||||
if (cachedHitCanvas) {
|
if (cachedHitCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedHitCanvas(context);
|
this._drawCachedHitCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
}
|
}
|
||||||
@ -5490,9 +5525,8 @@
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
// TODO: create ClipContainer
|
|
||||||
Container.prototype._drawChildren = function (drawMethod, canvas, top) {
|
Container.prototype._drawChildren = function (drawMethod, canvas, top) {
|
||||||
var layer = this.getLayer(), context = canvas && canvas.getContext(), clipWidth = this.clipWidth(), clipHeight = this.clipHeight(), clipFunc = this.clipFunc(), hasClip = (clipWidth && clipHeight) || clipFunc;
|
var context = canvas && canvas.getContext(), clipWidth = this.clipWidth(), clipHeight = this.clipHeight(), clipFunc = this.clipFunc(), hasClip = (clipWidth && clipHeight) || clipFunc;
|
||||||
var selfCache = top === this;
|
var selfCache = top === this;
|
||||||
if (hasClip) {
|
if (hasClip) {
|
||||||
context.save();
|
context.save();
|
||||||
@ -7101,7 +7135,8 @@
|
|||||||
// if node is cached we just need to draw from cache
|
// if node is cached we just need to draw from cache
|
||||||
if (cachedCanvas) {
|
if (cachedCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedSceneCanvas(context);
|
this._drawCachedSceneCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
return this;
|
return this;
|
||||||
@ -7158,7 +7193,8 @@
|
|||||||
}
|
}
|
||||||
if (cachedHitCanvas) {
|
if (cachedHitCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedHitCanvas(context);
|
this._drawCachedHitCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
return this;
|
return this;
|
||||||
@ -7291,7 +7327,6 @@
|
|||||||
* // set hit stroke width always equals to scene stroke width
|
* // set hit stroke width always equals to scene stroke width
|
||||||
* shape.hitStrokeWidth('auto');
|
* shape.hitStrokeWidth('auto');
|
||||||
*/
|
*/
|
||||||
// TODO: probably we should deprecate it
|
|
||||||
Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator());
|
Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator());
|
||||||
/**
|
/**
|
||||||
* **deprecated, use hitStrokeWidth instead!** get/set strokeHitEnabled property. Useful for performance optimization.
|
* **deprecated, use hitStrokeWidth instead!** get/set strokeHitEnabled property. Useful for performance optimization.
|
||||||
@ -8512,14 +8547,6 @@
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
// the apply transform method is handled by the Layer and FastLayer class
|
|
||||||
// because it is up to the layer to decide if an absolute or relative transform
|
|
||||||
// should be used
|
|
||||||
// TODO: remove that method
|
|
||||||
Layer.prototype._applyTransform = function (shape, context, top) {
|
|
||||||
var m = shape.getAbsoluteTransform(top).getMatrix();
|
|
||||||
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
||||||
};
|
|
||||||
/**
|
/**
|
||||||
* get visible intersection shape. This is the preferred
|
* get visible intersection shape. This is the preferred
|
||||||
* method for determining if a point intersects a shape or not
|
* method for determining if a point intersects a shape or not
|
||||||
@ -15791,7 +15818,6 @@
|
|||||||
* transformer.padding(10);
|
* transformer.padding(10);
|
||||||
*/
|
*/
|
||||||
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
||||||
// TODO: that property is deprecated
|
|
||||||
Factory.addGetterSetter(Transformer, 'node');
|
Factory.addGetterSetter(Transformer, 'node');
|
||||||
/**
|
/**
|
||||||
* get/set attached nodes of the Transformer. Transformer will adapt to their size and listen to their events
|
* get/set attached nodes of the Transformer. Transformer will adapt to their size and listen to their events
|
||||||
|
4
konva.min.js
vendored
4
konva.min.js
vendored
File diff suppressed because one or more lines are too long
@ -344,7 +344,8 @@ export abstract class Container<ChildType extends Node> extends Node<
|
|||||||
|
|
||||||
if (cachedSceneCanvas) {
|
if (cachedSceneCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedSceneCanvas(context);
|
this._drawCachedSceneCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
} else {
|
} else {
|
||||||
@ -365,7 +366,8 @@ export abstract class Container<ChildType extends Node> extends Node<
|
|||||||
|
|
||||||
if (cachedHitCanvas) {
|
if (cachedHitCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedHitCanvas(context);
|
this._drawCachedHitCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
} else {
|
} else {
|
||||||
@ -373,10 +375,8 @@ export abstract class Container<ChildType extends Node> extends Node<
|
|||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
// TODO: create ClipContainer
|
|
||||||
_drawChildren(drawMethod, canvas, top) {
|
_drawChildren(drawMethod, canvas, top) {
|
||||||
var layer = this.getLayer(),
|
var context = canvas && canvas.getContext(),
|
||||||
context = canvas && canvas.getContext(),
|
|
||||||
clipWidth = this.clipWidth(),
|
clipWidth = this.clipWidth(),
|
||||||
clipHeight = this.clipHeight(),
|
clipHeight = this.clipHeight(),
|
||||||
clipFunc = this.clipFunc(),
|
clipFunc = this.clipFunc(),
|
||||||
|
@ -310,15 +310,6 @@ export abstract class Layer extends Container<Group | Shape> {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the apply transform method is handled by the Layer and FastLayer class
|
|
||||||
// because it is up to the layer to decide if an absolute or relative transform
|
|
||||||
// should be used
|
|
||||||
// TODO: remove that method
|
|
||||||
_applyTransform(shape, context, top) {
|
|
||||||
var m = shape.getAbsoluteTransform(top).getMatrix();
|
|
||||||
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get visible intersection shape. This is the preferred
|
* get visible intersection shape. This is the preferred
|
||||||
* method for determining if a point intersects a shape or not
|
* method for determining if a point intersects a shape or not
|
||||||
|
33
src/Node.ts
33
src/Node.ts
@ -241,9 +241,17 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
return emptyChildren;
|
return emptyChildren;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @lends Konva.Node.prototype */
|
|
||||||
_clearCache(attr?: string) {
|
_clearCache(attr?: string) {
|
||||||
if (attr) {
|
// if we want to clear transform cache
|
||||||
|
// we don't really need to remove it from the cache
|
||||||
|
// but instead mark as "dirty"
|
||||||
|
// so we don't need to create a new instance next time
|
||||||
|
if (
|
||||||
|
(attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM) &&
|
||||||
|
this._cache.get(attr)
|
||||||
|
) {
|
||||||
|
(this._cache.get(attr) as Transform).dirty = true;
|
||||||
|
} else if (attr) {
|
||||||
this._cache.delete(attr);
|
this._cache.delete(attr);
|
||||||
} else {
|
} else {
|
||||||
this._cache.clear();
|
this._cache.clear();
|
||||||
@ -252,8 +260,13 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
_getCache(attr: string, privateGetter: Function) {
|
_getCache(attr: string, privateGetter: Function) {
|
||||||
var cache = this._cache.get(attr);
|
var cache = this._cache.get(attr);
|
||||||
|
|
||||||
|
// for transform the cache can be NOT empty
|
||||||
|
// but we still need to recalculate it if it is dirty
|
||||||
|
var isTransform = attr === TRANSFORM || attr === ABSOLUTE_TRANSFORM;
|
||||||
|
var invalid = cache === undefined || (isTransform && cache.dirty === true);
|
||||||
|
|
||||||
// if not cached, we need to set it using the private getter method.
|
// if not cached, we need to set it using the private getter method.
|
||||||
if (cache === undefined) {
|
if (invalid) {
|
||||||
cache = privateGetter.call(this);
|
cache = privateGetter.call(this);
|
||||||
this._cache.set(attr, cache);
|
this._cache.set(attr, cache);
|
||||||
}
|
}
|
||||||
@ -1690,11 +1703,12 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
return at;
|
return at;
|
||||||
} else {
|
} else {
|
||||||
// try to use a cached value
|
// try to use a cached value
|
||||||
|
at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform();
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
// transform will be cached
|
// transform will be cached
|
||||||
at = this.parent.getAbsoluteTransform().copy();
|
this.parent.getAbsoluteTransform().copyInto(at);
|
||||||
} else {
|
} else {
|
||||||
at = new Transform();
|
at.reset();
|
||||||
}
|
}
|
||||||
var transformsEnabled = this.transformsEnabled();
|
var transformsEnabled = this.transformsEnabled();
|
||||||
if (transformsEnabled === 'all') {
|
if (transformsEnabled === 'all') {
|
||||||
@ -1702,6 +1716,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
} else if (transformsEnabled === 'position') {
|
} else if (transformsEnabled === 'position') {
|
||||||
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
||||||
}
|
}
|
||||||
|
at.dirty = false;
|
||||||
return at;
|
return at;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1766,8 +1781,10 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
return this._getCache(TRANSFORM, this._getTransform) as Transform;
|
return this._getCache(TRANSFORM, this._getTransform) as Transform;
|
||||||
}
|
}
|
||||||
_getTransform(): Transform {
|
_getTransform(): Transform {
|
||||||
var m = new Transform(),
|
var m: Transform = this._cache.get(TRANSFORM) || new Transform();
|
||||||
x = this.x(),
|
m.reset();
|
||||||
|
|
||||||
|
var x = this.x(),
|
||||||
y = this.y(),
|
y = this.y(),
|
||||||
rotation = Konva.getAngle(this.rotation()),
|
rotation = Konva.getAngle(this.rotation()),
|
||||||
scaleX = this.scaleX(),
|
scaleX = this.scaleX(),
|
||||||
@ -1793,6 +1810,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
|||||||
m.translate(-1 * offsetX, -1 * offsetY);
|
m.translate(-1 * offsetX, -1 * offsetY);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m.dirty = false;
|
||||||
|
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
10
src/Shape.ts
10
src/Shape.ts
@ -567,7 +567,9 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
|
|||||||
// if node is cached we just need to draw from cache
|
// if node is cached we just need to draw from cache
|
||||||
if (cachedCanvas) {
|
if (cachedCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
|
||||||
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
this._drawCachedSceneCanvas(context);
|
this._drawCachedSceneCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
return this;
|
return this;
|
||||||
@ -647,7 +649,10 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
|
|||||||
|
|
||||||
if (cachedHitCanvas) {
|
if (cachedHitCanvas) {
|
||||||
context.save();
|
context.save();
|
||||||
layer._applyTransform(this, context, top);
|
|
||||||
|
var m = this.getAbsoluteTransform(top).getMatrix();
|
||||||
|
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||||
|
|
||||||
this._drawCachedHitCanvas(context);
|
this._drawCachedHitCanvas(context);
|
||||||
context.restore();
|
context.restore();
|
||||||
return this;
|
return this;
|
||||||
@ -874,7 +879,6 @@ Factory.addGetterSetter(
|
|||||||
* shape.hitStrokeWidth('auto');
|
* shape.hitStrokeWidth('auto');
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: probably we should deprecate it
|
|
||||||
Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator());
|
Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
71
src/Util.ts
71
src/Util.ts
@ -49,7 +49,7 @@ export class Collection<Child extends Node> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static _mapMethod(methodName: any) {
|
static _mapMethod(methodName: any) {
|
||||||
Collection.prototype[methodName] = function() {
|
Collection.prototype[methodName] = function () {
|
||||||
var len = this.length,
|
var len = this.length,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ export class Collection<Child extends Node> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static mapMethods = function(constructor: Function) {
|
static mapMethods = function (constructor: Function) {
|
||||||
var prot = constructor.prototype;
|
var prot = constructor.prototype;
|
||||||
for (var methodName in prot) {
|
for (var methodName in prot) {
|
||||||
Collection._mapMethod(methodName);
|
Collection._mapMethod(methodName);
|
||||||
@ -83,7 +83,7 @@ Collection.prototype = [] as any;
|
|||||||
* shape.setX(10);
|
* shape.setX(10);
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
Collection.prototype.each = function(func) {
|
Collection.prototype.each = function (func) {
|
||||||
for (var n = 0; n < this.length; n++) {
|
for (var n = 0; n < this.length; n++) {
|
||||||
func(this[n], n);
|
func(this[n], n);
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ Collection.prototype.each = function(func) {
|
|||||||
* @method
|
* @method
|
||||||
* @name Konva.Collection#toArray
|
* @name Konva.Collection#toArray
|
||||||
*/
|
*/
|
||||||
Collection.prototype.toArray = function() {
|
Collection.prototype.toArray = function () {
|
||||||
var arr = [],
|
var arr = [],
|
||||||
len = this.length,
|
len = this.length,
|
||||||
n;
|
n;
|
||||||
@ -130,9 +130,18 @@ Collection.prototype.toArray = function() {
|
|||||||
*/
|
*/
|
||||||
export class Transform {
|
export class Transform {
|
||||||
m: Array<number>;
|
m: Array<number>;
|
||||||
|
dirty = false;
|
||||||
constructor(m = [1, 0, 0, 1, 0, 0]) {
|
constructor(m = [1, 0, 0, 1, 0, 0]) {
|
||||||
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
this.m = (m && m.slice()) || [1, 0, 0, 1, 0, 0];
|
||||||
}
|
}
|
||||||
|
reset() {
|
||||||
|
this.m[0] = 1;
|
||||||
|
this.m[1] = 0;
|
||||||
|
this.m[2] = 0;
|
||||||
|
this.m[3] = 1;
|
||||||
|
this.m[4] = 0;
|
||||||
|
this.m[5] = 0;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Copy Konva.Transform object
|
* Copy Konva.Transform object
|
||||||
* @method
|
* @method
|
||||||
@ -144,6 +153,14 @@ export class Transform {
|
|||||||
copy() {
|
copy() {
|
||||||
return new Transform(this.m);
|
return new Transform(this.m);
|
||||||
}
|
}
|
||||||
|
copyInto(tr: Transform) {
|
||||||
|
tr.m[0] = this.m[0];
|
||||||
|
tr.m[1] = this.m[1];
|
||||||
|
tr.m[2] = this.m[2];
|
||||||
|
tr.m[3] = this.m[3];
|
||||||
|
tr.m[4] = this.m[4];
|
||||||
|
tr.m[5] = this.m[5];
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* Transform point
|
* Transform point
|
||||||
* @method
|
* @method
|
||||||
@ -155,7 +172,7 @@ export class Transform {
|
|||||||
var m = this.m;
|
var m = this.m;
|
||||||
return {
|
return {
|
||||||
x: m[0] * point.x + m[2] * point.y + m[4],
|
x: m[0] * point.x + m[2] * point.y + m[4],
|
||||||
y: m[1] * point.x + m[3] * point.y + m[5]
|
y: m[1] * point.x + m[3] * point.y + m[5],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -215,7 +232,7 @@ export class Transform {
|
|||||||
getTranslation() {
|
getTranslation() {
|
||||||
return {
|
return {
|
||||||
x: this.m[4],
|
x: this.m[4],
|
||||||
y: this.m[5]
|
y: this.m[5],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
@ -334,7 +351,7 @@ export class Transform {
|
|||||||
scaleX: 0,
|
scaleX: 0,
|
||||||
scaleY: 0,
|
scaleY: 0,
|
||||||
skewX: 0,
|
skewX: 0,
|
||||||
skewY: 0
|
skewY: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Apply the QR-like decomposition.
|
// Apply the QR-like decomposition.
|
||||||
@ -525,7 +542,7 @@ var OBJECT_ARRAY = '[object Array]',
|
|||||||
white: [255, 255, 255],
|
white: [255, 255, 255],
|
||||||
whitesmoke: [245, 245, 245],
|
whitesmoke: [245, 245, 245],
|
||||||
yellow: [255, 255, 0],
|
yellow: [255, 255, 0],
|
||||||
yellowgreen: [154, 205, 5]
|
yellowgreen: [154, 205, 5],
|
||||||
},
|
},
|
||||||
RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/,
|
RGB_REGEX = /rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)/,
|
||||||
animQueue: Array<Function> = [];
|
animQueue: Array<Function> = [];
|
||||||
@ -592,10 +609,10 @@ export const Util = {
|
|||||||
requestAnimFrame(callback: Function) {
|
requestAnimFrame(callback: Function) {
|
||||||
animQueue.push(callback);
|
animQueue.push(callback);
|
||||||
if (animQueue.length === 1) {
|
if (animQueue.length === 1) {
|
||||||
requestAnimationFrame(function() {
|
requestAnimationFrame(function () {
|
||||||
const queue = animQueue;
|
const queue = animQueue;
|
||||||
animQueue = [];
|
animQueue = [];
|
||||||
queue.forEach(function(cb) {
|
queue.forEach(function (cb) {
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -646,7 +663,7 @@ export const Util = {
|
|||||||
_urlToImage(url: string, callback: Function) {
|
_urlToImage(url: string, callback: Function) {
|
||||||
// if arg is a string, then it's a data url
|
// if arg is a string, then it's a data url
|
||||||
var imageObj = new glob.Image();
|
var imageObj = new glob.Image();
|
||||||
imageObj.onload = function() {
|
imageObj.onload = function () {
|
||||||
callback(imageObj);
|
callback(imageObj);
|
||||||
};
|
};
|
||||||
imageObj.src = url;
|
imageObj.src = url;
|
||||||
@ -660,7 +677,7 @@ export const Util = {
|
|||||||
return {
|
return {
|
||||||
r: (bigint >> 16) & 255,
|
r: (bigint >> 16) & 255,
|
||||||
g: (bigint >> 8) & 255,
|
g: (bigint >> 8) & 255,
|
||||||
b: bigint & 255
|
b: bigint & 255,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
@ -704,7 +721,7 @@ export const Util = {
|
|||||||
return {
|
return {
|
||||||
r: rgb[0],
|
r: rgb[0],
|
||||||
g: rgb[1],
|
g: rgb[1],
|
||||||
b: rgb[2]
|
b: rgb[2],
|
||||||
};
|
};
|
||||||
} else if (color[0] === HASH) {
|
} else if (color[0] === HASH) {
|
||||||
// hex
|
// hex
|
||||||
@ -715,14 +732,14 @@ export const Util = {
|
|||||||
return {
|
return {
|
||||||
r: parseInt(rgb[1], 10),
|
r: parseInt(rgb[1], 10),
|
||||||
g: parseInt(rgb[2], 10),
|
g: parseInt(rgb[2], 10),
|
||||||
b: parseInt(rgb[3], 10)
|
b: parseInt(rgb[3], 10),
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// default
|
// default
|
||||||
return {
|
return {
|
||||||
r: 0,
|
r: 0,
|
||||||
g: 0,
|
g: 0,
|
||||||
b: 0
|
b: 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -749,7 +766,7 @@ export const Util = {
|
|||||||
r: c[0],
|
r: c[0],
|
||||||
g: c[1],
|
g: c[1],
|
||||||
b: c[2],
|
b: c[2],
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
// Parse rgb(n, n, n)
|
// Parse rgb(n, n, n)
|
||||||
@ -761,7 +778,7 @@ export const Util = {
|
|||||||
r: parts[0],
|
r: parts[0],
|
||||||
g: parts[1],
|
g: parts[1],
|
||||||
b: parts[2],
|
b: parts[2],
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -774,7 +791,7 @@ export const Util = {
|
|||||||
r: parts[0],
|
r: parts[0],
|
||||||
g: parts[1],
|
g: parts[1],
|
||||||
b: parts[2],
|
b: parts[2],
|
||||||
a: parts[3]
|
a: parts[3],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -785,7 +802,7 @@ export const Util = {
|
|||||||
r: parseInt(str.slice(1, 3), 16),
|
r: parseInt(str.slice(1, 3), 16),
|
||||||
g: parseInt(str.slice(3, 5), 16),
|
g: parseInt(str.slice(3, 5), 16),
|
||||||
b: parseInt(str.slice(5, 7), 16),
|
b: parseInt(str.slice(5, 7), 16),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -796,7 +813,7 @@ export const Util = {
|
|||||||
r: parseInt(str[1] + str[1], 16),
|
r: parseInt(str[1] + str[1], 16),
|
||||||
g: parseInt(str[2] + str[2], 16),
|
g: parseInt(str[2] + str[2], 16),
|
||||||
b: parseInt(str[3] + str[3], 16),
|
b: parseInt(str[3] + str[3], 16),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -821,7 +838,7 @@ export const Util = {
|
|||||||
r: Math.round(val),
|
r: Math.round(val),
|
||||||
g: Math.round(val),
|
g: Math.round(val),
|
||||||
b: Math.round(val),
|
b: Math.round(val),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -861,7 +878,7 @@ export const Util = {
|
|||||||
r: Math.round(rgb[0]),
|
r: Math.round(rgb[0]),
|
||||||
g: Math.round(rgb[1]),
|
g: Math.round(rgb[1]),
|
||||||
b: Math.round(rgb[2]),
|
b: Math.round(rgb[2]),
|
||||||
a: 1
|
a: 1,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -1016,7 +1033,7 @@ export const Util = {
|
|||||||
_getProjectionToLine(pt: Vector2d, line, isClosed) {
|
_getProjectionToLine(pt: Vector2d, line, isClosed) {
|
||||||
var pc = Util.cloneObject(pt);
|
var pc = Util.cloneObject(pt);
|
||||||
var dist = Number.MAX_VALUE;
|
var dist = Number.MAX_VALUE;
|
||||||
line.forEach(function(p1, i) {
|
line.forEach(function (p1, i) {
|
||||||
if (!isClosed && i === line.length - 1) {
|
if (!isClosed && i === line.length - 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1052,18 +1069,18 @@ export const Util = {
|
|||||||
for (n = 0; n < startArray.length; n += 2) {
|
for (n = 0; n < startArray.length; n += 2) {
|
||||||
start.push({
|
start.push({
|
||||||
x: startArray[n],
|
x: startArray[n],
|
||||||
y: startArray[n + 1]
|
y: startArray[n + 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
for (n = 0; n < endArray.length; n += 2) {
|
for (n = 0; n < endArray.length; n += 2) {
|
||||||
end.push({
|
end.push({
|
||||||
x: endArray[n],
|
x: endArray[n],
|
||||||
y: endArray[n + 1]
|
y: endArray[n + 1],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var newStart = [];
|
var newStart = [];
|
||||||
end.forEach(function(point) {
|
end.forEach(function (point) {
|
||||||
var pr = Util._getProjectionToLine(point, start, isClosed);
|
var pr = Util._getProjectionToLine(point, start, isClosed);
|
||||||
newStart.push(pr.x);
|
newStart.push(pr.x);
|
||||||
newStart.push(pr.y);
|
newStart.push(pr.y);
|
||||||
@ -1118,5 +1135,5 @@ export const Util = {
|
|||||||
} else {
|
} else {
|
||||||
return evt.changedTouches[0].identifier;
|
return evt.changedTouches[0].identifier;
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
@ -1531,7 +1531,6 @@ Factory.addGetterSetter(Transformer, 'ignoreStroke', false);
|
|||||||
*/
|
*/
|
||||||
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
||||||
|
|
||||||
// TODO: that property is deprecated
|
|
||||||
Factory.addGetterSetter(Transformer, 'node');
|
Factory.addGetterSetter(Transformer, 'node');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="container"></div>
|
<div id="container"></div>
|
||||||
<script src="../../konva.js"></script>
|
<script src="../../konva.min.js"></script>
|
||||||
|
<!-- <script src="https://unpkg.com/konva@6.0.0/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">
|
||||||
var lastTime = 0;
|
var lastTime = 0;
|
||||||
@ -28,7 +29,7 @@
|
|||||||
var maxY = height - 10;
|
var maxY = height - 10;
|
||||||
var minY = 0;
|
var minY = 0;
|
||||||
|
|
||||||
var startBunnyCount = 2000;
|
var startBunnyCount = 4000;
|
||||||
var isAdding = false;
|
var isAdding = false;
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var container;
|
var container;
|
||||||
@ -37,6 +38,8 @@
|
|||||||
var amount = 10;
|
var amount = 10;
|
||||||
var counter;
|
var counter;
|
||||||
|
|
||||||
|
Konva.pixelRatio = 1;
|
||||||
|
|
||||||
var stage = new Konva.Stage({
|
var stage = new Konva.Stage({
|
||||||
container: 'container',
|
container: 'container',
|
||||||
width: width - 10,
|
width: width - 10,
|
||||||
@ -132,27 +135,35 @@
|
|||||||
|
|
||||||
for (var i = 0; i < bunnys.length; i++) {
|
for (var i = 0; i < bunnys.length; i++) {
|
||||||
var bunny = bunnys[i];
|
var bunny = bunnys[i];
|
||||||
bunny.setX(bunny.getX() + bunny.speedX);
|
var pos = {
|
||||||
bunny.setY(bunny.getY() + bunny.speedY);
|
x: bunny.x(),
|
||||||
|
y: bunny.y(),
|
||||||
|
};
|
||||||
|
pos.x = pos.x + bunny.speedX;
|
||||||
|
pos.y = pos.y + bunny.speedY;
|
||||||
bunny.speedY += gravity;
|
bunny.speedY += gravity;
|
||||||
if (bunny.getX() > maxX - wabbitTexture.width) {
|
if (pos.x > maxX - wabbitTexture.width) {
|
||||||
bunny.speedX *= -1;
|
bunny.speedX *= -1;
|
||||||
bunny.setX(maxX - wabbitTexture.width);
|
pos.x = maxX - wabbitTexture.width;
|
||||||
} else if (bunny.getX() < minX) {
|
} else if (pos.x < minX) {
|
||||||
bunny.speedX *= -1;
|
bunny.speedX *= -1;
|
||||||
bunny.setX(minX);
|
pos.x = minX;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bunny.getY() > maxY - wabbitTexture.height) {
|
if (pos.y > maxY - wabbitTexture.height) {
|
||||||
bunny.speedY *= -0.85;
|
bunny.speedY *= -0.85;
|
||||||
bunny.setY(maxY - wabbitTexture.height);
|
pos.y = maxY - wabbitTexture.height;
|
||||||
if (Math.random() > 0.5) {
|
if (Math.random() > 0.5) {
|
||||||
bunny.speedY -= Math.random() * 6;
|
bunny.speedY -= Math.random() * 6;
|
||||||
}
|
}
|
||||||
} else if (bunny.getY() < minY) {
|
} else if (pos.y < minY) {
|
||||||
bunny.speedY = 0;
|
bunny.speedY = 0;
|
||||||
bunny.setY(minY);
|
pos.y = minY;
|
||||||
}
|
}
|
||||||
|
bunny.position({
|
||||||
|
x: pos.x,
|
||||||
|
y: pos.y,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
layer.draw();
|
layer.draw();
|
||||||
requestAnimationFrame(update);
|
requestAnimationFrame(update);
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
var maxY = height - 10;
|
var maxY = height - 10;
|
||||||
var minY = 0;
|
var minY = 0;
|
||||||
|
|
||||||
var startBunnyCount = 10;
|
var startBunnyCount = 4000;
|
||||||
var isAdding = false;
|
var isAdding = false;
|
||||||
var count = 0;
|
var count = 0;
|
||||||
var container;
|
var container;
|
||||||
@ -140,7 +140,10 @@
|
|||||||
bunny.speedY = 0;
|
bunny.speedY = 0;
|
||||||
bunny.y = (minY);
|
bunny.y = (minY);
|
||||||
}
|
}
|
||||||
ctx.drawImage(wabbitTexture, bunny.x, bunny.y);
|
ctx.save();
|
||||||
|
ctx.transform(1, 0, 0, 1, bunny.x, bunny.y);
|
||||||
|
ctx.drawImage(wabbitTexture, 0, 0);
|
||||||
|
ctx.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -138,9 +138,9 @@ suite('Node', function () {
|
|||||||
// transform cache
|
// transform cache
|
||||||
assert.notEqual(circle._cache.get('transform'), undefined);
|
assert.notEqual(circle._cache.get('transform'), undefined);
|
||||||
circle.setX(100);
|
circle.setX(100);
|
||||||
assert.equal(circle._cache.get('transform'), undefined);
|
assert.equal(circle._cache.get('transform').dirty, true);
|
||||||
layer.draw();
|
layer.draw();
|
||||||
assert.notEqual(circle._cache.get('transform'), undefined);
|
assert.equal(circle._cache.get('transform').dirty, false);
|
||||||
});
|
});
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
Loading…
Reference in New Issue
Block a user