mirror of
https://github.com/Hopiu/fabric.js.git
synced 2026-05-05 04:14:54 +00:00
Memoize transform and use transform for rendering (#4418)
* done * done removed dist * added some test
This commit is contained in:
parent
3244f6c0ae
commit
40f16a9b4e
6 changed files with 105 additions and 32 deletions
|
|
@ -482,14 +482,14 @@
|
|||
*/
|
||||
isTargetTransparent: function (target, x, y) {
|
||||
var ctx = this.contextCache,
|
||||
originalColor = target.selectionBackgroundColor;
|
||||
originalColor = target.selectionBackgroundColor, v = this.viewportTransform;
|
||||
|
||||
target.selectionBackgroundColor = '';
|
||||
|
||||
this.clearContext(ctx);
|
||||
|
||||
ctx.save();
|
||||
ctx.transform.apply(ctx, this.viewportTransform);
|
||||
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
|
||||
target.render(ctx);
|
||||
ctx.restore();
|
||||
|
||||
|
|
|
|||
|
|
@ -42,6 +42,16 @@
|
|||
*/
|
||||
aCoords: null,
|
||||
|
||||
/**
|
||||
* storage for object transform matrix
|
||||
*/
|
||||
ownMatrixCache: null,
|
||||
|
||||
/**
|
||||
* storage for object full transform matrix
|
||||
*/
|
||||
matrixCache: null,
|
||||
|
||||
/**
|
||||
* return correct set of coordinates for intersection
|
||||
*/
|
||||
|
|
@ -437,6 +447,15 @@
|
|||
return fabric.iMatrix.concat();
|
||||
},
|
||||
|
||||
transformMatrixKey: function(skipGroup) {
|
||||
var sep = '_', prefix = '';
|
||||
if (!skipGroup && this.group) {
|
||||
prefix = this.group.transformMatrixKey(skipGroup) + sep;
|
||||
};
|
||||
return prefix + this.top + sep + this.left + sep + this.scaleX + sep + this.scaleY +
|
||||
sep + this.skewX + sep + this.skewY + sep + this.angle + sep + this.flipX + sep + this.flipY;
|
||||
},
|
||||
|
||||
/**
|
||||
* calculate trasform Matrix that represent current transformation from
|
||||
* object properties.
|
||||
|
|
@ -444,22 +463,38 @@
|
|||
* @return {Array} matrix Transform Matrix for the object
|
||||
*/
|
||||
calcTransformMatrix: function(skipGroup) {
|
||||
if (skipGroup) {
|
||||
return this.calcOwnMatrix();
|
||||
}
|
||||
var key = this.transformMatrixKey(), cache = this.matrixCache || (this.matrixCache = {});
|
||||
if (cache.key === key) {
|
||||
return cache.value;
|
||||
}
|
||||
var matrix = this.calcOwnMatrix();
|
||||
if (this.group) {
|
||||
matrix = multiplyMatrices(this.group.calcTransformMatrix(), matrix);
|
||||
}
|
||||
cache.key = key;
|
||||
cache.value = matrix;
|
||||
return matrix;
|
||||
},
|
||||
|
||||
calcOwnMatrix: function() {
|
||||
var key = this.transformMatrixKey(true), cache = this.ownMatrixCache || (this.ownMatrixCache = {});
|
||||
if (cache.key === key) {
|
||||
return cache.value;
|
||||
}
|
||||
var center = this.getCenterPoint(),
|
||||
translateMatrix = [1, 0, 0, 1, center.x, center.y],
|
||||
matrix = [1, 0, 0, 1, center.x, center.y],
|
||||
rotateMatrix,
|
||||
dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true),
|
||||
matrix;
|
||||
if (this.group && !skipGroup) {
|
||||
matrix = multiplyMatrices(this.group.calcTransformMatrix(), translateMatrix);
|
||||
}
|
||||
else {
|
||||
matrix = translateMatrix;
|
||||
}
|
||||
dimensionMatrix = this._calcDimensionsTransformMatrix(this.skewX, this.skewY, true);
|
||||
if (this.angle) {
|
||||
rotateMatrix = this._calcRotateMatrix();
|
||||
matrix = multiplyMatrices(matrix, rotateMatrix);
|
||||
}
|
||||
matrix = multiplyMatrices(matrix, dimensionMatrix);
|
||||
cache.key = key;
|
||||
cache.value = matrix;
|
||||
return matrix;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -266,9 +266,9 @@
|
|||
return;
|
||||
}
|
||||
if (this.canvas && this.canvas.contextTop) {
|
||||
var ctx = this.canvas.contextTop;
|
||||
var ctx = this.canvas.contextTop, v = this.canvas.viewportTransform;
|
||||
ctx.save();
|
||||
ctx.transform.apply(ctx, this.canvas.viewportTransform);
|
||||
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
|
||||
this.transform(ctx);
|
||||
this.transformMatrix && ctx.transform.apply(ctx, this.transformMatrix);
|
||||
this._clearTextArea(ctx);
|
||||
|
|
|
|||
|
|
@ -743,21 +743,16 @@
|
|||
/**
|
||||
* Transforms context when rendering an object
|
||||
* @param {CanvasRenderingContext2D} ctx Context
|
||||
* @param {Boolean} fromLeft When true, context is transformed to object's top/left corner. This is used when rendering text on Node
|
||||
*/
|
||||
transform: function(ctx, fromLeft) {
|
||||
transform: function(ctx) {
|
||||
var m;
|
||||
if (this.group && !this.group._transformDone) {
|
||||
this.group.transform(ctx);
|
||||
m = this.calcTransformMatrix();
|
||||
}
|
||||
var center = fromLeft ? this._getLeftTopCoords() : this.getCenterPoint();
|
||||
ctx.translate(center.x, center.y);
|
||||
this.angle && ctx.rotate(degreesToRadians(this.angle));
|
||||
ctx.scale(
|
||||
this.scaleX * (this.flipX ? -1 : 1),
|
||||
this.scaleY * (this.flipY ? -1 : 1)
|
||||
);
|
||||
this.skewX && ctx.transform(1, 0, Math.tan(degreesToRadians(this.skewX)), 1, 0, 0);
|
||||
this.skewY && ctx.transform(1, Math.tan(degreesToRadians(this.skewY)), 0, 1, 0, 0);
|
||||
else {
|
||||
m = this.calcOwnMatrix();
|
||||
}
|
||||
ctx.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
@ -1239,12 +1234,12 @@
|
|||
if (!filler || !filler.toLive) {
|
||||
return { offsetX: 0, offsetY: 0 };
|
||||
}
|
||||
var transform = filler.gradientTransform || filler.patternTransform;
|
||||
var t = filler.gradientTransform || filler.patternTransform;
|
||||
var offsetX = -this.width / 2 + filler.offsetX || 0,
|
||||
offsetY = -this.height / 2 + filler.offsetY || 0;
|
||||
ctx.translate(offsetX, offsetY);
|
||||
if (transform) {
|
||||
ctx.transform.apply(ctx, transform);
|
||||
if (t) {
|
||||
ctx.transform(t[0], t[1], t[2], t[3], t[4], t[5]);
|
||||
}
|
||||
return { offsetX: offsetX, offsetY: offsetY };
|
||||
},
|
||||
|
|
|
|||
|
|
@ -879,6 +879,7 @@
|
|||
* @chainable
|
||||
*/
|
||||
renderCanvas: function(ctx, objects) {
|
||||
var v = this.viewportTransform;
|
||||
if (this.isRendering) {
|
||||
fabric.util.cancelAnimFrame(this.isRendering);
|
||||
this.isRendering = 0;
|
||||
|
|
@ -893,7 +894,7 @@
|
|||
|
||||
ctx.save();
|
||||
//apply viewport transform once for all rendering process
|
||||
ctx.transform.apply(ctx, this.viewportTransform);
|
||||
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
|
||||
this._renderObjects(ctx, objects);
|
||||
ctx.restore();
|
||||
if (!this.controlsAboveOverlay && this.interactive) {
|
||||
|
|
@ -927,7 +928,7 @@
|
|||
* @param {string} property 'background' or 'overlay'
|
||||
*/
|
||||
_renderBackgroundOrOverlay: function(ctx, property) {
|
||||
var object = this[property + 'Color'];
|
||||
var object = this[property + 'Color'], v;
|
||||
if (object) {
|
||||
ctx.fillStyle = object.toLive
|
||||
? object.toLive(ctx, this)
|
||||
|
|
@ -942,8 +943,9 @@
|
|||
object = this[property + 'Image'];
|
||||
if (object) {
|
||||
if (this[property + 'Vpt']) {
|
||||
v = this.viewportTransform;
|
||||
ctx.save();
|
||||
ctx.transform.apply(ctx, this.viewportTransform);
|
||||
ctx.transform(v[0], v[1], v[2], v[3], v[4], v[5]);
|
||||
}
|
||||
object.render(ctx);
|
||||
this[property + 'Vpt'] && ctx.restore();
|
||||
|
|
|
|||
|
|
@ -356,9 +356,50 @@
|
|||
assert.ok(!cObj.isOnScreen(), 'object is completely out of viewport');
|
||||
});
|
||||
|
||||
QUnit.test('calcTransformMatrix', function(assert) {
|
||||
QUnit.test('calcTransformMatrix with no group', function(assert) {
|
||||
var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 0 });
|
||||
assert.ok(typeof cObj.calcTransformMatrix === 'function', 'calcTransformMatrix should exist');
|
||||
cObj.top = 0;
|
||||
cObj.left = 0;
|
||||
cObj.scaleX = 2;
|
||||
cObj.scaleY = 3;
|
||||
assert.deepEqual(cObj.calcTransformMatrix(), cObj.calcOwnMatrix(), 'without group matrix is same');
|
||||
});
|
||||
|
||||
QUnit.test('calcOwnMatrix', function(assert) {
|
||||
var cObj = new fabric.Object({ width: 10, height: 15, strokeWidth: 0 });
|
||||
assert.ok(typeof cObj.calcOwnMatrix === 'function', 'calcTransformMatrix should exist');
|
||||
cObj.top = 0;
|
||||
cObj.left = 0;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [1, 0, 0, 1, 5, 7.5], 'only translate matrix');
|
||||
cObj.scaleX = 2;
|
||||
cObj.scaleY = 3;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [2, 0, 0, 3, 10, 22.5], 'only translate matrix and scale');
|
||||
cObj.skewX = 45;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [2, 0, 1.9999999999999998, 3, 25, 22.5], 'translate matrix scale skewX');
|
||||
cObj.skewY = 30;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [3.1547005383792515, 1.7320508075688772, 1.9999999999999998, 3, 30.773502691896255, 31.160254037844386], 'translate matrix scale skewX skewY');
|
||||
cObj.angle = 38;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [1.4195809931249126,
|
||||
3.3071022498267006,
|
||||
-0.2709629187635314,
|
||||
3.595355211471482,
|
||||
5.065683074898075,
|
||||
43.50067533516962], 'translate matrix scale skewX skewY angle');
|
||||
cObj.flipX = true;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [-3.552294904178618,
|
||||
-0.5773529255117364,
|
||||
-3.4230059331904186,
|
||||
1.1327093101688495,
|
||||
5.065683074898075,
|
||||
43.50067533516962], 'translate matrix scale skewX skewY angle flipX');
|
||||
cObj.flipY = true;
|
||||
assert.deepEqual(cObj.calcOwnMatrix(), [-1.4195809931249126,
|
||||
-3.3071022498267006,
|
||||
0.2709629187635314,
|
||||
-3.595355211471482,
|
||||
5.065683074898075,
|
||||
43.50067533516962], 'translate matrix scale skewX skewY angle flipX flipY');
|
||||
});
|
||||
|
||||
QUnit.test('_calcDimensionsTransformMatrix', function(assert) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue