mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-07 13:22:07 -05:00
Implement caching of drawn Canvas Path objects for better performance.
Already supported on recent Chrome and Safari.
This commit is contained in:
parent
f07f4ac977
commit
5630b7e415
2 changed files with 42 additions and 17 deletions
|
@ -57,6 +57,13 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
||||||
this.addChildren(Array.isArray(arg) ? arg : arguments);
|
this.addChildren(Array.isArray(arg) ? arg : arguments);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_changed: function _changed(flags) {
|
||||||
|
_changed.base.call(this, flags);
|
||||||
|
// Delete cached native Path
|
||||||
|
if (flags & (/*#=*/ ChangeFlag.HIERARCHY | /*#=*/ ChangeFlag.GEOMETRY))
|
||||||
|
delete this._currentPath;
|
||||||
|
},
|
||||||
|
|
||||||
insertChildren: function insertChildren(index, items, _preserve) {
|
insertChildren: function insertChildren(index, items, _preserve) {
|
||||||
// Pass on 'path' for _type, to make sure that only paths are added as
|
// Pass on 'path' for _type, to make sure that only paths are added as
|
||||||
// children.
|
// children.
|
||||||
|
@ -218,10 +225,17 @@ var CompoundPath = PathItem.extend(/** @lends CompoundPath# */{
|
||||||
// Return early if the compound path doesn't have any children:
|
// Return early if the compound path doesn't have any children:
|
||||||
if (children.length === 0)
|
if (children.length === 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (this._currentPath) {
|
||||||
|
ctx.currentPath = this._currentPath;
|
||||||
|
} else {
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
param = param.extend({ compound: true });
|
param = param.extend({ compound: true });
|
||||||
for (var i = 0, l = children.length; i < l; i++)
|
for (var i = 0, l = children.length; i < l; i++)
|
||||||
children[i].draw(ctx, param);
|
children[i].draw(ctx, param);
|
||||||
|
this._currentPath = ctx.currentPath;
|
||||||
|
}
|
||||||
|
|
||||||
if (!param.clip) {
|
if (!param.clip) {
|
||||||
this._setStyles(ctx);
|
this._setStyles(ctx);
|
||||||
var style = this._style;
|
var style = this._style;
|
||||||
|
|
|
@ -115,15 +115,16 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
_changed: function _changed(flags) {
|
_changed: function _changed(flags) {
|
||||||
_changed.base.call(this, flags);
|
_changed.base.call(this, flags);
|
||||||
if (flags & /*#=*/ ChangeFlag.GEOMETRY) {
|
if (flags & /*#=*/ ChangeFlag.GEOMETRY) {
|
||||||
|
// Delete cached native Path
|
||||||
|
delete (this._compound ? this._parent : this)._currentPath;
|
||||||
delete this._length;
|
delete this._length;
|
||||||
// Clockwise state becomes undefined as soon as geometry changes.
|
// Clockwise state becomes undefined as soon as geometry changes.
|
||||||
delete this._clockwise;
|
delete this._clockwise;
|
||||||
// Curves are no longer valid
|
// Curves are no longer valid
|
||||||
if (this._curves) {
|
if (this._curves) {
|
||||||
for (var i = 0, l = this._curves.length; i < l; i++) {
|
for (var i = 0, l = this._curves.length; i < l; i++)
|
||||||
this._curves[i]._changed(/*#=*/ Change.GEOMETRY);
|
this._curves[i]._changed(/*#=*/ Change.GEOMETRY);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else if (flags & /*#=*/ ChangeFlag.STROKE) {
|
} else if (flags & /*#=*/ ChangeFlag.STROKE) {
|
||||||
// TODO: We could preserve the purely geometric bounds that are not
|
// TODO: We could preserve the purely geometric bounds that are not
|
||||||
// affected by stroke: _bounds.bounds and _bounds.handleBounds
|
// affected by stroke: _bounds.bounds and _bounds.handleBounds
|
||||||
|
@ -1997,7 +1998,8 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
return {
|
return {
|
||||||
_draw: function(ctx, param) {
|
_draw: function(ctx, param) {
|
||||||
var clip = param.clip,
|
var clip = param.clip,
|
||||||
compound = param.compound;
|
// Also mark this Path as _compound so _changed() knows about it
|
||||||
|
compound = this._compound = param.compound;
|
||||||
if (!compound)
|
if (!compound)
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
|
|
||||||
|
@ -2015,29 +2017,38 @@ var Path = PathItem.extend(/** @lends Path# */{
|
||||||
return dashArray[((i % dashLength) + dashLength) % dashLength];
|
return dashArray[((i % dashLength) + dashLength) % dashLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Prepare the canvas path if we have any situation that requires it
|
// CompoundPath collects its own _currentPath
|
||||||
// to be defined.
|
if (!compound && this._currentPath) {
|
||||||
|
ctx.currentPath = this._currentPath;
|
||||||
|
} else {
|
||||||
|
// Prepare the canvas path if we have any situation that
|
||||||
|
// requires it to be defined.
|
||||||
if (hasFill || hasStroke && !dashLength || compound || clip)
|
if (hasFill || hasStroke && !dashLength || compound || clip)
|
||||||
drawSegments(ctx, this);
|
drawSegments(ctx, this);
|
||||||
|
|
||||||
if (this._closed)
|
if (this._closed)
|
||||||
ctx.closePath();
|
ctx.closePath();
|
||||||
|
if (!compound)
|
||||||
|
this._currentPath = ctx.currentPath;
|
||||||
|
}
|
||||||
|
|
||||||
if (!clip && !compound && (hasFill || hasStroke)) {
|
if (!clip && !compound && (hasFill || hasStroke)) {
|
||||||
// If the path is part of a compound path or doesn't have a fill
|
// If the path is part of a compound path or doesn't have a fill
|
||||||
// or stroke, there is no need to continue.
|
// or stroke, there is no need to continue.
|
||||||
this._setStyles(ctx);
|
this._setStyles(ctx);
|
||||||
// If shadowColor is defined, clear it after fill, so it won't
|
|
||||||
// be applied to both fill and stroke. If the path is only
|
|
||||||
// stroked, we don't have to clear it.
|
|
||||||
if (hasFill) {
|
if (hasFill) {
|
||||||
ctx.fill(style.getWindingRule());
|
ctx.fill(style.getWindingRule());
|
||||||
|
// If shadowColor is defined, clear it after fill, so it
|
||||||
|
// won't be applied to both fill and stroke. If the path is
|
||||||
|
// only stroked, we don't have to clear it.
|
||||||
ctx.shadowColor = 'rgba(0,0,0,0)';
|
ctx.shadowColor = 'rgba(0,0,0,0)';
|
||||||
}
|
}
|
||||||
if (hasStroke) {
|
if (hasStroke) {
|
||||||
if (dashLength) {
|
if (dashLength) {
|
||||||
// We cannot use the path created by drawSegments above
|
// We cannot use the path created by drawSegments above
|
||||||
// Use CurveFlatteners to draw dashed paths:
|
// Use CurveFlatteners to draw dashed paths:
|
||||||
|
// NOTE: We don't cache this path in another currentPath
|
||||||
|
// since browsers that support currentPath also support
|
||||||
|
// native dashes.
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
var flattener = new PathFlattener(this),
|
var flattener = new PathFlattener(this),
|
||||||
length = flattener.length,
|
length = flattener.length,
|
||||||
|
|
Loading…
Reference in a new issue