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:
Jürg Lehni 2016-01-26 21:37:27 +01:00
parent 9ad63a7231
commit b71ffdbe71
9 changed files with 76 additions and 96 deletions

View file

@ -122,7 +122,6 @@
var image = document.createElement('img');
image.onload = function () {
handleImage(image);
view.update();
};
image.src = event.target.result;
};

View file

@ -273,8 +273,6 @@
// var nup = unite(pathA, pathB);
// console.timeEnd('unite');
// // nup.style = booleanStyle;
// view.update();
}
var booleanStyle = {
@ -307,7 +305,6 @@
var boolPathU = _p1U.unite(_p2U);
console.timeEnd('Union');
boolPathU.style = booleanStyle;
view.update();
}
if (operations.intersection) {
@ -318,7 +315,6 @@
var boolPathI = _p1I.intersect(_p2I);
console.timeEnd('Intersection');
boolPathI.style = booleanStyle;
view.update();
}
if (operations.subtraction) {
@ -329,7 +325,6 @@
var boolPathS = _p1S.subtract(_p2S);
console.timeEnd('Subtraction');
boolPathS.style = booleanStyle;
view.update();
}
if (operations.exclusion) {
@ -340,7 +335,6 @@
var boolPathE = _p1E.exclude(_p2E);
console.timeEnd('Exclusion');
boolPathE.style = booleanStyle;
view.update();
}
if (operations.division) {
@ -352,7 +346,6 @@
console.timeEnd('Division');
disperse(boolPathD);
boolPathD.style = booleanStyle;
view.update();
}
}

View file

@ -482,8 +482,6 @@ Base.exports.PaperScript = (function() {
});
if (res.onFrame)
view.setOnFrame(res.onFrame);
// Automatically update view at the end.
view.update();
}
return compiled;
}

View file

@ -134,8 +134,6 @@ var Key = new function() {
paper = scope;
// Call the onKeyDown or onKeyUp handler if present
tool.emit(type, new KeyEvent(down, key, character, event));
if (view)
view.update();
}
}

View file

@ -230,9 +230,6 @@ var Raster = Item.extend(/** @lends Raster# */{
if (view && that.responds(type)) {
paper = view._scope;
that.emit(type, new Event(event));
// TODO: Request a redraw in the next animation frame from
// update() instead!
view.update();
}
}

View file

@ -88,7 +88,13 @@ var Project = PaperScopeItem.extend(/** @lends Project# */{
*/
_changed: function(flags, item) {
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;
var view = this._view;
if (view && !view._requested)
view.requestUpdate();
}
// 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

View file

@ -558,7 +558,6 @@ new function() {
view = scope.project && scope.getView();
if (onLoad)
onLoad.call(this, item);
view.update();
}
if (isRoot) {

View file

@ -119,13 +119,11 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
* event hanlders for interaction, animation and load events, this method is
* 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}
*/
update: function(force) {
update: function() {
var project = this._project;
if (!project || !force && !project._needsUpdate)
if (!project || !project._needsUpdate)
return false;
var ctx = this._context,
size = this._viewSize;

View file

@ -160,18 +160,73 @@ var View = Base.extend(Emitter, /** @lends View# */{
_time: 0,
_count: 0,
_requestFrame: function() {
var that = this;
DomEvent.requestAnimationFrame(function() {
that._requested = false;
// Do we need to stop due to a call to the frame event's uninstall()
if (!that._animate)
return;
// Request next frame already before handling the current frame
that._requestFrame();
that._handleFrame();
}, this._element);
this._requested = true;
/**
* 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: '#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() {
@ -193,8 +248,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
if (this._stats)
this._stats.update();
this._handlingFrame = false;
// Automatically update view on each frame.
this.update();
},
_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.
* Used only by Matrix for now.
@ -317,7 +356,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
delta: delta
});
this._changed();
this.update();
this.requestUpdate();
},
/**
@ -539,49 +578,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
this.translate(Point.read(arguments).negate());
}
}), /** @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: invalidate(rect)
// 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'))
|| mouse.down && responds('mouseup'))
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) {