mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2024-12-29 09:22:22 -05:00
Remove all direct calls to view.update() and favor of the new view.requestUpdate()
Pure window.requestAnimationFrame() smoothness, automatic updates even when working directly from JavaScript, and no more slow-downs from onLoad events! Closes #830, #925
This commit is contained in:
parent
9ad63a7231
commit
b71ffdbe71
9 changed files with 76 additions and 96 deletions
|
@ -122,7 +122,6 @@
|
||||||
var image = document.createElement('img');
|
var image = document.createElement('img');
|
||||||
image.onload = function () {
|
image.onload = function () {
|
||||||
handleImage(image);
|
handleImage(image);
|
||||||
view.update();
|
|
||||||
};
|
};
|
||||||
image.src = event.target.result;
|
image.src = event.target.result;
|
||||||
};
|
};
|
||||||
|
|
|
@ -273,8 +273,6 @@
|
||||||
// var nup = unite(pathA, pathB);
|
// var nup = unite(pathA, pathB);
|
||||||
// console.timeEnd('unite');
|
// console.timeEnd('unite');
|
||||||
// // nup.style = booleanStyle;
|
// // nup.style = booleanStyle;
|
||||||
|
|
||||||
// view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var booleanStyle = {
|
var booleanStyle = {
|
||||||
|
@ -307,7 +305,6 @@
|
||||||
var boolPathU = _p1U.unite(_p2U);
|
var boolPathU = _p1U.unite(_p2U);
|
||||||
console.timeEnd('Union');
|
console.timeEnd('Union');
|
||||||
boolPathU.style = booleanStyle;
|
boolPathU.style = booleanStyle;
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operations.intersection) {
|
if (operations.intersection) {
|
||||||
|
@ -318,7 +315,6 @@
|
||||||
var boolPathI = _p1I.intersect(_p2I);
|
var boolPathI = _p1I.intersect(_p2I);
|
||||||
console.timeEnd('Intersection');
|
console.timeEnd('Intersection');
|
||||||
boolPathI.style = booleanStyle;
|
boolPathI.style = booleanStyle;
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operations.subtraction) {
|
if (operations.subtraction) {
|
||||||
|
@ -329,7 +325,6 @@
|
||||||
var boolPathS = _p1S.subtract(_p2S);
|
var boolPathS = _p1S.subtract(_p2S);
|
||||||
console.timeEnd('Subtraction');
|
console.timeEnd('Subtraction');
|
||||||
boolPathS.style = booleanStyle;
|
boolPathS.style = booleanStyle;
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operations.exclusion) {
|
if (operations.exclusion) {
|
||||||
|
@ -340,7 +335,6 @@
|
||||||
var boolPathE = _p1E.exclude(_p2E);
|
var boolPathE = _p1E.exclude(_p2E);
|
||||||
console.timeEnd('Exclusion');
|
console.timeEnd('Exclusion');
|
||||||
boolPathE.style = booleanStyle;
|
boolPathE.style = booleanStyle;
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operations.division) {
|
if (operations.division) {
|
||||||
|
@ -352,7 +346,6 @@
|
||||||
console.timeEnd('Division');
|
console.timeEnd('Division');
|
||||||
disperse(boolPathD);
|
disperse(boolPathD);
|
||||||
boolPathD.style = booleanStyle;
|
boolPathD.style = booleanStyle;
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -482,8 +482,6 @@ Base.exports.PaperScript = (function() {
|
||||||
});
|
});
|
||||||
if (res.onFrame)
|
if (res.onFrame)
|
||||||
view.setOnFrame(res.onFrame);
|
view.setOnFrame(res.onFrame);
|
||||||
// Automatically update view at the end.
|
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
return compiled;
|
return compiled;
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,8 +134,6 @@ var Key = new function() {
|
||||||
paper = scope;
|
paper = scope;
|
||||||
// Call the onKeyDown or onKeyUp handler if present
|
// Call the onKeyDown or onKeyUp handler if present
|
||||||
tool.emit(type, new KeyEvent(down, key, character, event));
|
tool.emit(type, new KeyEvent(down, key, character, event));
|
||||||
if (view)
|
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -230,9 +230,6 @@ var Raster = Item.extend(/** @lends Raster# */{
|
||||||
if (view && that.responds(type)) {
|
if (view && that.responds(type)) {
|
||||||
paper = view._scope;
|
paper = view._scope;
|
||||||
that.emit(type, new Event(event));
|
that.emit(type, new Event(event));
|
||||||
// TODO: Request a redraw in the next animation frame from
|
|
||||||
// update() instead!
|
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -88,7 +88,13 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
|
||||||
*/
|
*/
|
||||||
_changed: function(flags, item) {
|
_changed: function(flags, item) {
|
||||||
if (flags & /*#=*/ChangeFlag.APPEARANCE) {
|
if (flags & /*#=*/ChangeFlag.APPEARANCE) {
|
||||||
|
// Never draw changes right away. Simply mark the project as "dirty"
|
||||||
|
// and request a view update through window.requestAnimationFrame()
|
||||||
|
// (via view.requestUpdate()), which handles the smooth updates.
|
||||||
this._needsUpdate = true;
|
this._needsUpdate = true;
|
||||||
|
var view = this._view;
|
||||||
|
if (view && !view._requested)
|
||||||
|
view.requestUpdate();
|
||||||
}
|
}
|
||||||
// Have project keep track of changed items so they can be iterated.
|
// Have project keep track of changed items so they can be iterated.
|
||||||
// This can be used for example to update the SVG tree. Needs to be
|
// This can be used for example to update the SVG tree. Needs to be
|
||||||
|
|
|
@ -558,7 +558,6 @@ new function() {
|
||||||
view = scope.project && scope.getView();
|
view = scope.project && scope.getView();
|
||||||
if (onLoad)
|
if (onLoad)
|
||||||
onLoad.call(this, item);
|
onLoad.call(this, item);
|
||||||
view.update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isRoot) {
|
if (isRoot) {
|
||||||
|
|
|
@ -119,13 +119,11 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
||||||
* event hanlders for interaction, animation and load events, this method is
|
* event hanlders for interaction, animation and load events, this method is
|
||||||
* invoked for you automatically at the end.
|
* invoked for you automatically at the end.
|
||||||
*
|
*
|
||||||
* @param {Boolean} [force=false] {@true if the view should be updated even
|
|
||||||
* if no change has happened}
|
|
||||||
* @return {Boolean} {@true if the view was updated}
|
* @return {Boolean} {@true if the view was updated}
|
||||||
*/
|
*/
|
||||||
update: function(force) {
|
update: function() {
|
||||||
var project = this._project;
|
var project = this._project;
|
||||||
if (!project || !force && !project._needsUpdate)
|
if (!project || !project._needsUpdate)
|
||||||
return false;
|
return false;
|
||||||
var ctx = this._context,
|
var ctx = this._context,
|
||||||
size = this._viewSize;
|
size = this._viewSize;
|
||||||
|
|
144
src/view/View.js
144
src/view/View.js
|
@ -160,18 +160,73 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
_time: 0,
|
_time: 0,
|
||||||
_count: 0,
|
_count: 0,
|
||||||
|
|
||||||
_requestFrame: function() {
|
/**
|
||||||
var that = this;
|
* Updates the view if there are changes. Note that when using built-in
|
||||||
DomEvent.requestAnimationFrame(function() {
|
* event hanlders for interaction, animation and load events, this method is
|
||||||
that._requested = false;
|
* invoked for you automatically at the end.
|
||||||
// Do we need to stop due to a call to the frame event's uninstall()
|
*
|
||||||
if (!that._animate)
|
* @name View#update
|
||||||
return;
|
* @function
|
||||||
// Request next frame already before handling the current frame
|
* @param {Boolean} [force=false] {@true if the view should be updated even
|
||||||
that._requestFrame();
|
* if no change has happened}
|
||||||
that._handleFrame();
|
* @return {Boolean} {@true if the view was updated}
|
||||||
}, this._element);
|
*/
|
||||||
this._requested = true;
|
// update: function(force) {
|
||||||
|
// },
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the view if there are changes.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link #update()} instead.
|
||||||
|
*/
|
||||||
|
draw: '#update',
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests an update of the view if there are changes through the browser's
|
||||||
|
* requestAnimationFrame() mechanism for smooth animation. Note that when
|
||||||
|
* using built-in event handlers for interaction, animation and load events,
|
||||||
|
* updates are automatically invoked for you automatically at the end.
|
||||||
|
*
|
||||||
|
* @function
|
||||||
|
*/
|
||||||
|
requestUpdate: function() {
|
||||||
|
if (!this._requested) {
|
||||||
|
var that = this;
|
||||||
|
DomEvent.requestAnimationFrame(function() {
|
||||||
|
that._requested = false;
|
||||||
|
// Only handle frame and request next one if we don't need to
|
||||||
|
// stop, e.g. due to a call to pause(), or a request for a
|
||||||
|
// single redraw.
|
||||||
|
if (that._animate) {
|
||||||
|
// Request next frame before handling the current frame
|
||||||
|
that.requestUpdate();
|
||||||
|
that._handleFrame();
|
||||||
|
}
|
||||||
|
// Even if we're not animating, update the view now since this
|
||||||
|
// might have been a request for a single redraw after a change
|
||||||
|
that.update();
|
||||||
|
}, this._element);
|
||||||
|
this._requested = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes all animation play by adding the view to the request animation
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
play: function() {
|
||||||
|
this._animate = true;
|
||||||
|
// Request a frame handler straight away to initialize the
|
||||||
|
// sequence of onFrame calls.
|
||||||
|
this.requestUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Makes all animation pause by removing the view to the request animation
|
||||||
|
* loop.
|
||||||
|
*/
|
||||||
|
pause: function() {
|
||||||
|
this._animate = false;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleFrame: function() {
|
_handleFrame: function() {
|
||||||
|
@ -193,8 +248,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
if (this._stats)
|
if (this._stats)
|
||||||
this._stats.update();
|
this._stats.update();
|
||||||
this._handlingFrame = false;
|
this._handlingFrame = false;
|
||||||
// Automatically update view on each frame.
|
|
||||||
this.update();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_animateItem: function(item, animate) {
|
_animateItem: function(item, animate) {
|
||||||
|
@ -229,20 +282,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
_update: function() {
|
|
||||||
this._project._needsUpdate = true;
|
|
||||||
if (this._handlingFrame)
|
|
||||||
return;
|
|
||||||
if (this._animate) {
|
|
||||||
// If we're animating, call _handleFrame staight away, but without
|
|
||||||
// requesting another animation frame.
|
|
||||||
this._handleFrame();
|
|
||||||
} else {
|
|
||||||
// Otherwise simply update the view now
|
|
||||||
this.update();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Private notifier that is called whenever a change occurs in this view.
|
* Private notifier that is called whenever a change occurs in this view.
|
||||||
* Used only by Matrix for now.
|
* Used only by Matrix for now.
|
||||||
|
@ -317,7 +356,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
delta: delta
|
delta: delta
|
||||||
});
|
});
|
||||||
this._changed();
|
this._changed();
|
||||||
this.update();
|
this.requestUpdate();
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -539,49 +578,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
||||||
this.translate(Point.read(arguments).negate());
|
this.translate(Point.read(arguments).negate());
|
||||||
}
|
}
|
||||||
}), /** @lends View# */{
|
}), /** @lends View# */{
|
||||||
/**
|
|
||||||
* Makes all animation play by adding the view to the request animation
|
|
||||||
* loop.
|
|
||||||
*/
|
|
||||||
play: function() {
|
|
||||||
this._animate = true;
|
|
||||||
// Request a frame handler straight away to initialize the
|
|
||||||
// sequence of onFrame calls.
|
|
||||||
if (!this._requested)
|
|
||||||
this._requestFrame();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes all animation pause by removing the view to the request animation
|
|
||||||
* loop.
|
|
||||||
*/
|
|
||||||
pause: function() {
|
|
||||||
this._animate = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the view if there are changes. Note that when using built-in
|
|
||||||
* event hanlders for interaction, animation and load events, this method is
|
|
||||||
* invoked for you automatically at the end.
|
|
||||||
*
|
|
||||||
* @name View#update
|
|
||||||
* @function
|
|
||||||
* @param {Boolean} [force=false] {@true if the view should be updated even
|
|
||||||
* if no change has happened}
|
|
||||||
* @return {Boolean} {@true if the view was updated}
|
|
||||||
*/
|
|
||||||
// update: function(force) {
|
|
||||||
// },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the view if there are changes.
|
|
||||||
*
|
|
||||||
* @deprecated use {@link #update()} instead.
|
|
||||||
*/
|
|
||||||
draw: function() {
|
|
||||||
this.update();
|
|
||||||
},
|
|
||||||
|
|
||||||
// TODO: getInvalidBounds
|
// TODO: getInvalidBounds
|
||||||
// TODO: invalidate(rect)
|
// TODO: invalidate(rect)
|
||||||
// TODO: style: artwork / preview / raster / opaque / ink
|
// TODO: style: artwork / preview / raster / opaque / ink
|
||||||
|
@ -1186,10 +1182,6 @@ new function() { // Injection scope for mouse events on the browser
|
||||||
if (called && (!nativeMove || responds('mousedrag'))
|
if (called && (!nativeMove || responds('mousedrag'))
|
||||||
|| mouse.down && responds('mouseup'))
|
|| mouse.down && responds('mouseup'))
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
// In the end we always call update(), which only updates the view
|
|
||||||
// if anything has changed in the above calls.
|
|
||||||
this.update();
|
|
||||||
},
|
},
|
||||||
|
|
||||||
_countItemEvent: function(type, sign) {
|
_countItemEvent: function(type, sign) {
|
||||||
|
|
Loading…
Reference in a new issue