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:
|
||||
|
||||
* `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
|
||||
* Some performance fixes and code size optimizations
|
||||
* Better support for font families with spaces inside (like `Font Awesome 5`).
|
||||
* 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
|
||||
|
108
konva.js
108
konva.js
@ -8,7 +8,7 @@
|
||||
* Konva JavaScript Framework v6.0.0
|
||||
* http://konvajs.org/
|
||||
* Licensed under the MIT
|
||||
* Date: Tue Jun 09 2020
|
||||
* Date: Wed Jun 10 2020
|
||||
*
|
||||
* Original work Copyright (C) 2011 - 2013 by Eric Rowell (KineticJS)
|
||||
* Modified work Copyright (C) 2014 - present by Anton Lavrenov (Konva)
|
||||
@ -301,8 +301,17 @@
|
||||
var Transform = /** @class */ (function () {
|
||||
function Transform(m) {
|
||||
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];
|
||||
}
|
||||
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
|
||||
* @method
|
||||
@ -314,6 +323,14 @@
|
||||
Transform.prototype.copy = function () {
|
||||
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
|
||||
* @method
|
||||
@ -325,7 +342,7 @@
|
||||
var m = this.m;
|
||||
return {
|
||||
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 () {
|
||||
return {
|
||||
x: this.m[4],
|
||||
y: this.m[5]
|
||||
y: this.m[5],
|
||||
};
|
||||
};
|
||||
/**
|
||||
@ -491,7 +508,7 @@
|
||||
scaleX: 0,
|
||||
scaleY: 0,
|
||||
skewX: 0,
|
||||
skewY: 0
|
||||
skewY: 0,
|
||||
};
|
||||
// Apply the QR-like decomposition.
|
||||
if (a != 0 || b != 0) {
|
||||
@ -666,7 +683,7 @@
|
||||
white: [255, 255, 255],
|
||||
whitesmoke: [245, 245, 245],
|
||||
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 = [];
|
||||
/**
|
||||
* @namespace Util
|
||||
@ -789,7 +806,7 @@
|
||||
return {
|
||||
r: (bigint >> 16) & 255,
|
||||
g: (bigint >> 8) & 255,
|
||||
b: bigint & 255
|
||||
b: bigint & 255,
|
||||
};
|
||||
},
|
||||
/**
|
||||
@ -833,7 +850,7 @@
|
||||
return {
|
||||
r: rgb[0],
|
||||
g: rgb[1],
|
||||
b: rgb[2]
|
||||
b: rgb[2],
|
||||
};
|
||||
}
|
||||
else if (color[0] === HASH) {
|
||||
@ -846,7 +863,7 @@
|
||||
return {
|
||||
r: parseInt(rgb[1], 10),
|
||||
g: parseInt(rgb[2], 10),
|
||||
b: parseInt(rgb[3], 10)
|
||||
b: parseInt(rgb[3], 10),
|
||||
};
|
||||
}
|
||||
else {
|
||||
@ -854,7 +871,7 @@
|
||||
return {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0
|
||||
b: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -879,7 +896,7 @@
|
||||
r: c[0],
|
||||
g: c[1],
|
||||
b: c[2],
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
},
|
||||
// Parse rgb(n, n, n)
|
||||
@ -891,7 +908,7 @@
|
||||
r: parts[0],
|
||||
g: parts[1],
|
||||
b: parts[2],
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -904,7 +921,7 @@
|
||||
r: parts[0],
|
||||
g: parts[1],
|
||||
b: parts[2],
|
||||
a: parts[3]
|
||||
a: parts[3],
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -915,7 +932,7 @@
|
||||
r: parseInt(str.slice(1, 3), 16),
|
||||
g: parseInt(str.slice(3, 5), 16),
|
||||
b: parseInt(str.slice(5, 7), 16),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -926,7 +943,7 @@
|
||||
r: parseInt(str[1] + str[1], 16),
|
||||
g: parseInt(str[2] + str[2], 16),
|
||||
b: parseInt(str[3] + str[3], 16),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -948,7 +965,7 @@
|
||||
r: Math.round(val),
|
||||
g: Math.round(val),
|
||||
b: Math.round(val),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
if (l < 0.5) {
|
||||
@ -985,7 +1002,7 @@
|
||||
r: Math.round(rgb[0]),
|
||||
g: Math.round(rgb[1]),
|
||||
b: Math.round(rgb[2]),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -1145,13 +1162,13 @@
|
||||
for (n = 0; n < startArray.length; n += 2) {
|
||||
start.push({
|
||||
x: startArray[n],
|
||||
y: startArray[n + 1]
|
||||
y: startArray[n + 1],
|
||||
});
|
||||
}
|
||||
for (n = 0; n < endArray.length; n += 2) {
|
||||
end.push({
|
||||
x: endArray[n],
|
||||
y: endArray[n + 1]
|
||||
y: endArray[n + 1],
|
||||
});
|
||||
}
|
||||
var newStart = [];
|
||||
@ -1206,7 +1223,7 @@
|
||||
else {
|
||||
return evt.changedTouches[0].identifier;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function _formatValue(val) {
|
||||
@ -2660,9 +2677,16 @@
|
||||
Node.prototype.getChildren = function () {
|
||||
return emptyChildren;
|
||||
};
|
||||
/** @lends Konva.Node.prototype */
|
||||
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);
|
||||
}
|
||||
else {
|
||||
@ -2671,8 +2695,12 @@
|
||||
};
|
||||
Node.prototype._getCache = function (attr, privateGetter) {
|
||||
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 (cache === undefined) {
|
||||
if (invalid) {
|
||||
cache = privateGetter.call(this);
|
||||
this._cache.set(attr, cache);
|
||||
}
|
||||
@ -3934,12 +3962,13 @@
|
||||
}
|
||||
else {
|
||||
// try to use a cached value
|
||||
at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform();
|
||||
if (this.parent) {
|
||||
// transform will be cached
|
||||
at = this.parent.getAbsoluteTransform().copy();
|
||||
this.parent.getAbsoluteTransform().copyInto(at);
|
||||
}
|
||||
else {
|
||||
at = new Transform();
|
||||
at.reset();
|
||||
}
|
||||
var transformsEnabled = this.transformsEnabled();
|
||||
if (transformsEnabled === 'all') {
|
||||
@ -3948,6 +3977,7 @@
|
||||
else if (transformsEnabled === 'position') {
|
||||
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
||||
}
|
||||
at.dirty = false;
|
||||
return at;
|
||||
}
|
||||
};
|
||||
@ -4009,7 +4039,9 @@
|
||||
return this._getCache(TRANSFORM, this._getTransform);
|
||||
};
|
||||
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) {
|
||||
m.translate(x, y);
|
||||
}
|
||||
@ -4025,6 +4057,7 @@
|
||||
if (offsetX !== 0 || offsetY !== 0) {
|
||||
m.translate(-1 * offsetX, -1 * offsetY);
|
||||
}
|
||||
m.dirty = false;
|
||||
return m;
|
||||
};
|
||||
/**
|
||||
@ -5465,7 +5498,8 @@
|
||||
}
|
||||
if (cachedSceneCanvas) {
|
||||
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);
|
||||
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;
|
||||
if (cachedHitCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
}
|
||||
@ -5490,9 +5525,8 @@
|
||||
}
|
||||
return this;
|
||||
};
|
||||
// TODO: create ClipContainer
|
||||
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;
|
||||
if (hasClip) {
|
||||
context.save();
|
||||
@ -7101,7 +7135,8 @@
|
||||
// if node is cached we just need to draw from cache
|
||||
if (cachedCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
return this;
|
||||
@ -7158,7 +7193,8 @@
|
||||
}
|
||||
if (cachedHitCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
return this;
|
||||
@ -7291,7 +7327,6 @@
|
||||
* // set hit stroke width always equals to scene stroke width
|
||||
* shape.hitStrokeWidth('auto');
|
||||
*/
|
||||
// TODO: probably we should deprecate it
|
||||
Factory.addGetterSetter(Shape, 'strokeHitEnabled', true, getBooleanValidator());
|
||||
/**
|
||||
* **deprecated, use hitStrokeWidth instead!** get/set strokeHitEnabled property. Useful for performance optimization.
|
||||
@ -8512,14 +8547,6 @@
|
||||
}
|
||||
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
|
||||
* method for determining if a point intersects a shape or not
|
||||
@ -15791,7 +15818,6 @@
|
||||
* transformer.padding(10);
|
||||
*/
|
||||
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
||||
// TODO: that property is deprecated
|
||||
Factory.addGetterSetter(Transformer, 'node');
|
||||
/**
|
||||
* 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) {
|
||||
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);
|
||||
context.restore();
|
||||
} else {
|
||||
@ -365,7 +366,8 @@ export abstract class Container<ChildType extends Node> extends Node<
|
||||
|
||||
if (cachedHitCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
} else {
|
||||
@ -373,10 +375,8 @@ export abstract class Container<ChildType extends Node> extends Node<
|
||||
}
|
||||
return this;
|
||||
}
|
||||
// TODO: create ClipContainer
|
||||
_drawChildren(drawMethod, canvas, top) {
|
||||
var layer = this.getLayer(),
|
||||
context = canvas && canvas.getContext(),
|
||||
var context = canvas && canvas.getContext(),
|
||||
clipWidth = this.clipWidth(),
|
||||
clipHeight = this.clipHeight(),
|
||||
clipFunc = this.clipFunc(),
|
||||
|
@ -310,15 +310,6 @@ export abstract class Layer extends Container<Group | Shape> {
|
||||
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
|
||||
* 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;
|
||||
}
|
||||
|
||||
/** @lends Konva.Node.prototype */
|
||||
_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);
|
||||
} else {
|
||||
this._cache.clear();
|
||||
@ -252,8 +260,13 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
_getCache(attr: string, privateGetter: Function) {
|
||||
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 (cache === undefined) {
|
||||
if (invalid) {
|
||||
cache = privateGetter.call(this);
|
||||
this._cache.set(attr, cache);
|
||||
}
|
||||
@ -1690,11 +1703,12 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
return at;
|
||||
} else {
|
||||
// try to use a cached value
|
||||
at = this._cache.get(ABSOLUTE_TRANSFORM) || new Transform();
|
||||
if (this.parent) {
|
||||
// transform will be cached
|
||||
at = this.parent.getAbsoluteTransform().copy();
|
||||
this.parent.getAbsoluteTransform().copyInto(at);
|
||||
} else {
|
||||
at = new Transform();
|
||||
at.reset();
|
||||
}
|
||||
var transformsEnabled = this.transformsEnabled();
|
||||
if (transformsEnabled === 'all') {
|
||||
@ -1702,6 +1716,7 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
} else if (transformsEnabled === 'position') {
|
||||
at.translate(this.x() - this.offsetX(), this.y() - this.offsetY());
|
||||
}
|
||||
at.dirty = false;
|
||||
return at;
|
||||
}
|
||||
}
|
||||
@ -1766,8 +1781,10 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
return this._getCache(TRANSFORM, this._getTransform) as Transform;
|
||||
}
|
||||
_getTransform(): Transform {
|
||||
var m = new Transform(),
|
||||
x = this.x(),
|
||||
var m: Transform = this._cache.get(TRANSFORM) || new Transform();
|
||||
m.reset();
|
||||
|
||||
var x = this.x(),
|
||||
y = this.y(),
|
||||
rotation = Konva.getAngle(this.rotation()),
|
||||
scaleX = this.scaleX(),
|
||||
@ -1793,6 +1810,8 @@ export abstract class Node<Config extends NodeConfig = NodeConfig> {
|
||||
m.translate(-1 * offsetX, -1 * offsetY);
|
||||
}
|
||||
|
||||
m.dirty = false;
|
||||
|
||||
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 (cachedCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
return this;
|
||||
@ -647,7 +649,10 @@ export class Shape<Config extends ShapeConfig = ShapeConfig> extends Node<
|
||||
|
||||
if (cachedHitCanvas) {
|
||||
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);
|
||||
context.restore();
|
||||
return this;
|
||||
@ -874,7 +879,6 @@ Factory.addGetterSetter(
|
||||
* shape.hitStrokeWidth('auto');
|
||||
*/
|
||||
|
||||
// TODO: probably we should deprecate it
|
||||
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) {
|
||||
Collection.prototype[methodName] = function() {
|
||||
Collection.prototype[methodName] = function () {
|
||||
var len = this.length,
|
||||
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;
|
||||
for (var methodName in prot) {
|
||||
Collection._mapMethod(methodName);
|
||||
@ -83,7 +83,7 @@ Collection.prototype = [] as any;
|
||||
* shape.setX(10);
|
||||
* });
|
||||
*/
|
||||
Collection.prototype.each = function(func) {
|
||||
Collection.prototype.each = function (func) {
|
||||
for (var n = 0; n < this.length; n++) {
|
||||
func(this[n], n);
|
||||
}
|
||||
@ -93,7 +93,7 @@ Collection.prototype.each = function(func) {
|
||||
* @method
|
||||
* @name Konva.Collection#toArray
|
||||
*/
|
||||
Collection.prototype.toArray = function() {
|
||||
Collection.prototype.toArray = function () {
|
||||
var arr = [],
|
||||
len = this.length,
|
||||
n;
|
||||
@ -130,9 +130,18 @@ Collection.prototype.toArray = function() {
|
||||
*/
|
||||
export class Transform {
|
||||
m: Array<number>;
|
||||
dirty = false;
|
||||
constructor(m = [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
|
||||
* @method
|
||||
@ -144,6 +153,14 @@ export class Transform {
|
||||
copy() {
|
||||
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
|
||||
* @method
|
||||
@ -155,7 +172,7 @@ export class Transform {
|
||||
var m = this.m;
|
||||
return {
|
||||
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() {
|
||||
return {
|
||||
x: this.m[4],
|
||||
y: this.m[5]
|
||||
y: this.m[5],
|
||||
};
|
||||
}
|
||||
/**
|
||||
@ -334,7 +351,7 @@ export class Transform {
|
||||
scaleX: 0,
|
||||
scaleY: 0,
|
||||
skewX: 0,
|
||||
skewY: 0
|
||||
skewY: 0,
|
||||
};
|
||||
|
||||
// Apply the QR-like decomposition.
|
||||
@ -525,7 +542,7 @@ var OBJECT_ARRAY = '[object Array]',
|
||||
white: [255, 255, 255],
|
||||
whitesmoke: [245, 245, 245],
|
||||
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: Array<Function> = [];
|
||||
@ -592,10 +609,10 @@ export const Util = {
|
||||
requestAnimFrame(callback: Function) {
|
||||
animQueue.push(callback);
|
||||
if (animQueue.length === 1) {
|
||||
requestAnimationFrame(function() {
|
||||
requestAnimationFrame(function () {
|
||||
const queue = animQueue;
|
||||
animQueue = [];
|
||||
queue.forEach(function(cb) {
|
||||
queue.forEach(function (cb) {
|
||||
cb();
|
||||
});
|
||||
});
|
||||
@ -646,7 +663,7 @@ export const Util = {
|
||||
_urlToImage(url: string, callback: Function) {
|
||||
// if arg is a string, then it's a data url
|
||||
var imageObj = new glob.Image();
|
||||
imageObj.onload = function() {
|
||||
imageObj.onload = function () {
|
||||
callback(imageObj);
|
||||
};
|
||||
imageObj.src = url;
|
||||
@ -660,7 +677,7 @@ export const Util = {
|
||||
return {
|
||||
r: (bigint >> 16) & 255,
|
||||
g: (bigint >> 8) & 255,
|
||||
b: bigint & 255
|
||||
b: bigint & 255,
|
||||
};
|
||||
},
|
||||
/**
|
||||
@ -704,7 +721,7 @@ export const Util = {
|
||||
return {
|
||||
r: rgb[0],
|
||||
g: rgb[1],
|
||||
b: rgb[2]
|
||||
b: rgb[2],
|
||||
};
|
||||
} else if (color[0] === HASH) {
|
||||
// hex
|
||||
@ -715,14 +732,14 @@ export const Util = {
|
||||
return {
|
||||
r: parseInt(rgb[1], 10),
|
||||
g: parseInt(rgb[2], 10),
|
||||
b: parseInt(rgb[3], 10)
|
||||
b: parseInt(rgb[3], 10),
|
||||
};
|
||||
} else {
|
||||
// default
|
||||
return {
|
||||
r: 0,
|
||||
g: 0,
|
||||
b: 0
|
||||
b: 0,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -749,7 +766,7 @@ export const Util = {
|
||||
r: c[0],
|
||||
g: c[1],
|
||||
b: c[2],
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
},
|
||||
// Parse rgb(n, n, n)
|
||||
@ -761,7 +778,7 @@ export const Util = {
|
||||
r: parts[0],
|
||||
g: parts[1],
|
||||
b: parts[2],
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -774,7 +791,7 @@ export const Util = {
|
||||
r: parts[0],
|
||||
g: parts[1],
|
||||
b: parts[2],
|
||||
a: parts[3]
|
||||
a: parts[3],
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -785,7 +802,7 @@ export const Util = {
|
||||
r: parseInt(str.slice(1, 3), 16),
|
||||
g: parseInt(str.slice(3, 5), 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),
|
||||
g: parseInt(str[2] + str[2], 16),
|
||||
b: parseInt(str[3] + str[3], 16),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -821,7 +838,7 @@ export const Util = {
|
||||
r: Math.round(val),
|
||||
g: Math.round(val),
|
||||
b: Math.round(val),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
|
||||
@ -861,7 +878,7 @@ export const Util = {
|
||||
r: Math.round(rgb[0]),
|
||||
g: Math.round(rgb[1]),
|
||||
b: Math.round(rgb[2]),
|
||||
a: 1
|
||||
a: 1,
|
||||
};
|
||||
}
|
||||
},
|
||||
@ -1016,7 +1033,7 @@ export const Util = {
|
||||
_getProjectionToLine(pt: Vector2d, line, isClosed) {
|
||||
var pc = Util.cloneObject(pt);
|
||||
var dist = Number.MAX_VALUE;
|
||||
line.forEach(function(p1, i) {
|
||||
line.forEach(function (p1, i) {
|
||||
if (!isClosed && i === line.length - 1) {
|
||||
return;
|
||||
}
|
||||
@ -1052,18 +1069,18 @@ export const Util = {
|
||||
for (n = 0; n < startArray.length; n += 2) {
|
||||
start.push({
|
||||
x: startArray[n],
|
||||
y: startArray[n + 1]
|
||||
y: startArray[n + 1],
|
||||
});
|
||||
}
|
||||
for (n = 0; n < endArray.length; n += 2) {
|
||||
end.push({
|
||||
x: endArray[n],
|
||||
y: endArray[n + 1]
|
||||
y: endArray[n + 1],
|
||||
});
|
||||
}
|
||||
|
||||
var newStart = [];
|
||||
end.forEach(function(point) {
|
||||
end.forEach(function (point) {
|
||||
var pr = Util._getProjectionToLine(point, start, isClosed);
|
||||
newStart.push(pr.x);
|
||||
newStart.push(pr.y);
|
||||
@ -1118,5 +1135,5 @@ export const Util = {
|
||||
} else {
|
||||
return evt.changedTouches[0].identifier;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
@ -1531,7 +1531,6 @@ Factory.addGetterSetter(Transformer, 'ignoreStroke', false);
|
||||
*/
|
||||
Factory.addGetterSetter(Transformer, 'padding', 0, getNumberValidator());
|
||||
|
||||
// TODO: that property is deprecated
|
||||
Factory.addGetterSetter(Transformer, 'node');
|
||||
|
||||
/**
|
||||
|
@ -10,7 +10,8 @@
|
||||
</head>
|
||||
<body>
|
||||
<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 defer="defer">
|
||||
var lastTime = 0;
|
||||
@ -28,7 +29,7 @@
|
||||
var maxY = height - 10;
|
||||
var minY = 0;
|
||||
|
||||
var startBunnyCount = 2000;
|
||||
var startBunnyCount = 4000;
|
||||
var isAdding = false;
|
||||
var count = 0;
|
||||
var container;
|
||||
@ -37,6 +38,8 @@
|
||||
var amount = 10;
|
||||
var counter;
|
||||
|
||||
Konva.pixelRatio = 1;
|
||||
|
||||
var stage = new Konva.Stage({
|
||||
container: 'container',
|
||||
width: width - 10,
|
||||
@ -132,27 +135,35 @@
|
||||
|
||||
for (var i = 0; i < bunnys.length; i++) {
|
||||
var bunny = bunnys[i];
|
||||
bunny.setX(bunny.getX() + bunny.speedX);
|
||||
bunny.setY(bunny.getY() + bunny.speedY);
|
||||
var pos = {
|
||||
x: bunny.x(),
|
||||
y: bunny.y(),
|
||||
};
|
||||
pos.x = pos.x + bunny.speedX;
|
||||
pos.y = pos.y + bunny.speedY;
|
||||
bunny.speedY += gravity;
|
||||
if (bunny.getX() > maxX - wabbitTexture.width) {
|
||||
if (pos.x > maxX - wabbitTexture.width) {
|
||||
bunny.speedX *= -1;
|
||||
bunny.setX(maxX - wabbitTexture.width);
|
||||
} else if (bunny.getX() < minX) {
|
||||
pos.x = maxX - wabbitTexture.width;
|
||||
} else if (pos.x < minX) {
|
||||
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.setY(maxY - wabbitTexture.height);
|
||||
pos.y = maxY - wabbitTexture.height;
|
||||
if (Math.random() > 0.5) {
|
||||
bunny.speedY -= Math.random() * 6;
|
||||
}
|
||||
} else if (bunny.getY() < minY) {
|
||||
} else if (pos.y < minY) {
|
||||
bunny.speedY = 0;
|
||||
bunny.setY(minY);
|
||||
pos.y = minY;
|
||||
}
|
||||
bunny.position({
|
||||
x: pos.x,
|
||||
y: pos.y,
|
||||
});
|
||||
}
|
||||
layer.draw();
|
||||
requestAnimationFrame(update);
|
||||
|
@ -27,7 +27,7 @@
|
||||
var maxY = height - 10;
|
||||
var minY = 0;
|
||||
|
||||
var startBunnyCount = 10;
|
||||
var startBunnyCount = 4000;
|
||||
var isAdding = false;
|
||||
var count = 0;
|
||||
var container;
|
||||
@ -140,7 +140,10 @@
|
||||
bunny.speedY = 0;
|
||||
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
|
||||
assert.notEqual(circle._cache.get('transform'), undefined);
|
||||
circle.setX(100);
|
||||
assert.equal(circle._cache.get('transform'), undefined);
|
||||
assert.equal(circle._cache.get('transform').dirty, true);
|
||||
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