Skip to content

Fix animation frames #138

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 97 additions & 17 deletions src/Elm/Kernel/Browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,41 +96,121 @@ var _Browser_document = __Debugger_document || F4(function(impl, flagDecoder, de
// ANIMATION


var _Browser_cancelAnimationFrame =
typeof cancelAnimationFrame !== 'undefined'
? cancelAnimationFrame
: function(id) { clearTimeout(id); };
var _Browser_requestAnimationFrame_queue = {};
var _Browser_inAnimationFrame = false;
var _Browser_pendingAnimationFrame = false;
var _Browser_requestAnimationFrame_id = 0;

var _Browser_requestAnimationFrame =
function _Browser_cancelAnimationFrame(id)
{
delete _Browser_requestAnimationFrame_queue[id];
}

function _Browser_requestAnimationFrame(callback)
{
var id = _Browser_requestAnimationFrame_id;
_Browser_requestAnimationFrame_id++;
_Browser_requestAnimationFrame_queue[id] = callback;
if (!_Browser_pendingAnimationFrame)
{
_Browser_pendingAnimationFrame = true;
_Browser_requestAnimationFrame_raw(function() {
_Browser_pendingAnimationFrame = false;
_Browser_inAnimationFrame = true;
var maxId = _Browser_requestAnimationFrame_id;
for (var id2 in _Browser_requestAnimationFrame_queue)
{
if (id2 >= maxId)
{
break;
}
var callback = _Browser_requestAnimationFrame_queue[id2];
delete _Browser_requestAnimationFrame_queue[id2];
callback();
}
_Browser_inAnimationFrame = false;
});
}
return id;
}

var _Browser_requestAnimationFrame_raw =
typeof requestAnimationFrame !== 'undefined'
? requestAnimationFrame
: function(callback) { return setTimeout(callback, 1000 / 60); };

// Whether `draw` is currently running. `draw` can cause side effects:
// If the user renders a custom element, they can dispatch an event in
// its `connectedCallback`, which happens synchronously. That causes
// `update` to run while we’re in the middle of drawing, which then
// causes another call to the returned function below. We can’t start
// another draw before the first one is finished.
// Another thing you can do in `connectedCallback`, is to initialize
// another Elm app. Even different app instances can conflict with each other,
// since they all use the same `_VirtualDom_renderCount` variable.
var _Browser_drawing = false;
var _Browser_drawSync_queue = [];

function _Browser_makeAnimator(model, draw)
{
draw(model);
// Whether we have already requested an animation frame for drawing.
var pendingFrame = false;

var state = __4_NO_REQUEST;
// Whether we have already requested to draw right after the current draw has finished.
var pendingSync = false;

function drawHelp()
{
// If we’re already drawing, wait until that draw is done.
if (_Browser_drawing)
{
if (!pendingSync)
{
pendingSync = true;
_Browser_drawSync_queue.push(drawHelp);
}
return;
}

pendingFrame = false;
pendingSync = false;
_Browser_drawing = true;
draw(model);
_Browser_drawing = false;

while (_Browser_drawSync_queue.length > 0)
{
var callback = _Browser_drawSync_queue.shift();
callback();
}
}

function updateIfNeeded()
{
state = state === __4_EXTRA_REQUEST
? __4_NO_REQUEST
: ( _Browser_requestAnimationFrame(updateIfNeeded), draw(model), __4_EXTRA_REQUEST );
if (pendingFrame)
{
drawHelp();
}
}

drawHelp();

return function(nextModel, isSync)
{
model = nextModel;

isSync
? ( draw(model),
state === __4_PENDING_REQUEST && (state = __4_EXTRA_REQUEST)
)
: ( state === __4_NO_REQUEST && _Browser_requestAnimationFrame(updateIfNeeded),
state = __4_PENDING_REQUEST
);
// When using `Browser.Events.onAnimationFrame` we already are
// in an animation frame, so draw straight away. Otherwise we’ll
// be drawing one frame late all the time.
if (isSync || _Browser_inAnimationFrame)
{
drawHelp();
}
else if (!pendingFrame)
{
pendingFrame = true;
_Browser_requestAnimationFrame(updateIfNeeded);
}
};
}

Expand Down