mirror of
https://github.com/scratchfoundation/paper.js.git
synced 2025-01-03 19:45:44 -05:00
Improve handling of view updates and detection of invisible documents.
Switch to the new HTML5 Page Visibility API.
This commit is contained in:
parent
80e6246016
commit
da216aa581
5 changed files with 48 additions and 54 deletions
|
@ -482,6 +482,10 @@ Base.exports.PaperScript = (function() {
|
|||
});
|
||||
if (res.onFrame)
|
||||
view.setOnFrame(res.onFrame);
|
||||
// Automatically request an update at the end. This is only needed
|
||||
// if the script does not actually produce anything yet, and the
|
||||
// used canvas contains previous content.
|
||||
view.requestUpdate();
|
||||
}
|
||||
return compiled;
|
||||
}
|
||||
|
|
|
@ -72,49 +72,28 @@ DomEvent.requestAnimationFrame = new function() {
|
|||
var nativeRequest = DomElement.getPrefixed(window, 'requestAnimationFrame'),
|
||||
requested = false,
|
||||
callbacks = [],
|
||||
focused = true,
|
||||
timer;
|
||||
|
||||
DomEvent.add(window, {
|
||||
focus: function() {
|
||||
focused = true;
|
||||
},
|
||||
blur: function() {
|
||||
focused = false;
|
||||
}
|
||||
});
|
||||
|
||||
function handleCallbacks() {
|
||||
// Checks all installed callbacks for element visibility and
|
||||
// execute if needed.
|
||||
for (var i = callbacks.length - 1; i >= 0; i--) {
|
||||
var entry = callbacks[i],
|
||||
func = entry[0],
|
||||
el = entry[1];
|
||||
if (!el || (PaperScope.getAttribute(el, 'keepalive') == 'true'
|
||||
|| focused) && DomElement.isInView(el)) {
|
||||
// Only remove from the list once the callback was called. This
|
||||
// could take a long time based on visibility. But this way we
|
||||
// are sure to keep the animation loop running.
|
||||
callbacks.splice(i, 1);
|
||||
func();
|
||||
}
|
||||
}
|
||||
if (nativeRequest) {
|
||||
if (callbacks.length) {
|
||||
// If we haven't processed all callbacks yet, we need to keep
|
||||
// the loop running, as otherwise it would die off.
|
||||
nativeRequest(handleCallbacks);
|
||||
} else {
|
||||
requested = false;
|
||||
}
|
||||
}
|
||||
// Make a local references to the current callbacks array and set
|
||||
// callbacks to a new empty array, so it can collect the functions for
|
||||
// the new requests.
|
||||
var functions = callbacks;
|
||||
callbacks = [];
|
||||
// Call the collected callback functions.
|
||||
for (var i = 0, l = functions.length; i < l; i++)
|
||||
functions[i]();
|
||||
// Now see if the above calls have collected new callbacks. Keep
|
||||
// requesting new frames as long as we have callbacks.
|
||||
requested = nativeRequest && callbacks.length;
|
||||
if (requested)
|
||||
nativeRequest(handleCallbacks);
|
||||
}
|
||||
|
||||
return function(callback, element) {
|
||||
return function(callback) {
|
||||
// Add to the list of callbacks to be called in the next animation
|
||||
// frame.
|
||||
callbacks.push([callback, element]);
|
||||
callbacks.push(callback);
|
||||
if (nativeRequest) {
|
||||
// Handle animation natively. We only need to request the frame
|
||||
// once for all collected callbacks.
|
||||
|
@ -125,7 +104,7 @@ DomEvent.requestAnimationFrame = new function() {
|
|||
} else if (!timer) {
|
||||
// Install interval timer that checks all callbacks. This
|
||||
// results in faster animations than repeatedly installing
|
||||
// timout timers.
|
||||
// timeout timers.
|
||||
timer = setInterval(handleCallbacks, 1000 / 60);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -87,13 +87,14 @@ 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._autoUpdate)
|
||||
view.requestUpdate();
|
||||
if (view) {
|
||||
// Never draw changes right away. Simply mark view as "dirty"
|
||||
// and request an update through view.requestUpdate().
|
||||
view._needsUpdate = true;
|
||||
if (!view._requested && view._autoUpdate)
|
||||
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
|
||||
|
|
|
@ -56,6 +56,8 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
this._pixelRatio = deviceRatio / backingStoreRatio;
|
||||
}
|
||||
View.call(this, project, canvas);
|
||||
// We can't be sure the canvas is clear
|
||||
this._needsUpdate = true;
|
||||
},
|
||||
|
||||
remove: function remove() {
|
||||
|
@ -128,14 +130,14 @@ var CanvasView = View.extend(/** @lends CanvasView# */{
|
|||
* @return {Boolean} {@true if the view was updated}
|
||||
*/
|
||||
update: function() {
|
||||
var project = this._project;
|
||||
if (!project || !project._needsUpdate)
|
||||
if (!this._needsUpdate)
|
||||
return false;
|
||||
var ctx = this._context,
|
||||
var project = this._project,
|
||||
ctx = this._context,
|
||||
size = this._viewSize;
|
||||
ctx.clearRect(0, 0, size.width + 1, size.height + 1);
|
||||
project.draw(ctx, this._matrix, this._pixelRatio);
|
||||
project._needsUpdate = false;
|
||||
this._needsUpdate = false;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -119,6 +119,7 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
this._itemEvents = { native: {}, virtual: {} };
|
||||
// Do not set _autoUpdate on Node.js by default:
|
||||
this._autoUpdate = !paper.agent.node;
|
||||
this._needsUpdate = false;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -198,8 +199,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
* event hanlders for interaction, animation and load events, this method is
|
||||
* invoked for you automatically at the end.
|
||||
*
|
||||
* @name View#update
|
||||
* @function
|
||||
* @return {Boolean} {@true if the view was updated}
|
||||
*/
|
||||
update: function() {
|
||||
|
@ -220,8 +219,6 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
* 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) {
|
||||
|
@ -234,13 +231,24 @@ var View = Base.extend(Emitter, /** @lends View# */{
|
|||
if (that._animate) {
|
||||
// Request next update before handling the current frame
|
||||
that.requestUpdate();
|
||||
that._handleFrame();
|
||||
var element = that._element;
|
||||
// Only keep animating if we're allowed to, based on whether
|
||||
// the document is visible and the setting of keepalive. We
|
||||
// keep requesting frame regardless though, so the animation
|
||||
// picks up again as soon as the view is visible.
|
||||
if ((!DomElement.getPrefixed(document, 'hidden')
|
||||
|| PaperScope.getAttribute(element, 'keepalive')
|
||||
=== 'true') && DomElement.isInView(element)) {
|
||||
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
|
||||
// might have been a request for a single redraw after a change.
|
||||
// NOTE: If nothing has changed (e.g. _handleFrame() wasn't
|
||||
// called above), then this does not actually do anything.
|
||||
if (that._autoUpdate)
|
||||
that.update();
|
||||
}, this._element);
|
||||
});
|
||||
this._requested = true;
|
||||
}
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue