Detect if html5 canvas is paused - javascript

i am developing a game with HTML5 canvas and JavaScript.
To time the game, i take the system milliseconds from now, subtract the system milliseconds from when the last frame occurred, which leaves me with the milliseconds the last frame took to render.
This works fine, but if i open a new tab in Firefox, the canvas seems to get paused by Firefox, and when i come back, the current system time is many seconds later then the system time the last frame occurred and everything jumps, because its movement is relative to the last frame time.
I need some way to either detect, that the canvas is not running at the moment, or that Firefox (and of course other browsers) has switchted to another tab, so i can pause my game, and when returning, update the 'last frame time' to prevent jumps.
Any ideas?

You could also use the window onblur event to detect when the tab is changed.

That's just one cause of clock jump. You're still vulnerable to forced process sleep, high system load, computer sleep mode, hibernation, and a dozen other scenarios.
You need to cap the time delta. In my projects (hobby games), I've found 80ms to be a functional maximum.
(Also, collision detection is much harder without a cap.)

Related

Video, memory management problems in Internet Explorer and Edge from many videos on page causing them to display dark/black and/or not play

We have a page that contains 77 or so video thumbnails. When a video thumbnail is hovered over, video starts playing within the thumbnail space.
A problem occurs after many (8 to 60 depending on the system/browser) of them get hovered over. The video starts playing incorrectly, or not playing. Basically the flat/redundant areas turn all dark. In Edge, this corrects itself after a second or two, but for our client this is very undesirable behavior.
We made an improvement by pausing each video on mouse out by calling pause(), removing the src attribute, and then calling load() on the element with an empty src attribute, like so:
function pauseVideo(e) {
$('video', this).get(0).pause();
$('video', this).get(0).removeAttribute('src');
$('video', this).get(0).load();
}
This clears up some memory, but the issue still occurs, though more of the videos can play before the problem becomes apparent.
I does appear to have something to do with memory, and exposes what appears to us to be a memory leak within the Microsoft browsers. Each video increases memory usage, and the memory never gets cleared, as it seems to in Chrome and Firefox. The problem usually occurs when memory usage approaches somewhere between 600mb to 1gb (depending on system) in the task manager. (Chrome always sits around ~500-550 megabytes.
Firefox sits around ~700-800 megabytes.)
We noticed some variance on when the behavior starts to occur that depends on video cards, but the issue always become present at some point.
All of these videos are showed in multiple places on the page. So one thing I was wondering was if it is possible to share video memory between elements.
There are a couple other issues that may be related. In IE the videos go completely black, and their dimensions change onscreen which can change the page layout.
Here is a related issue, but it is not a duplicate, as it doesn't not provide a question or solution about having to facilitate 80 or so videos on one page: How to properly unload/destroy a VIDEO element
We're testing on IE version 11.228.17134.0 and Edge version 42.17134.1.0, both currently the latest.
The desired functionality originally was for the videos to pause on the frame when the user moused off the video, but right now appears we wont be able to do that if we have to unload the video.
I will be adding more information about this issue throughout the day as it becomes available.
Our team has a script that detects if DOM elements are within the viewable area on the page, e.i. not scrolled above the top or below the bottom. As the user scrolls, the script adds/removes a class, and dispatches custom events for each element that has the behavior added. I was able to leverage this system to pause, remove, and dispose (garbage collect) video elements that are not in view, and then, repopulate them as they come back into view, with the original properties stored in an array of objects associated with each video/thumbnail.
This disposes the video. The function must be called with .call(), like: disposeVideo.call(videoElement);
var disposeVideo = function () {
this.pause();
delete(this);
$(this).remove();
}
It's odd that though delete(this) is a hack, and shouldn't work in any browser, it appears to work in all browsers, according to comments I've read around this issue, and my findings in IE/Edge.
On IE (not Edge) this has a side effect of slowing down page scrolling. This is caused by the our in-view checking applied to 80 items on the page, or if it is to do with re-downloading posters (thumbnail images) and video, because it does appear to not be effectively caching these assets to be immediately (re)available to the renderer.
Another side effect (also in IE) related to the above, is that as you scroll the videos appear blank until assets are re-downloaded. We're opting to use images layered behind the videos in favor of using the poster attribute for the videos elements that get removed. This way there will never be blank video thumbnails onscreen.
Update: It is possible that having two or more video elements onscreen can cause the problem. We resorted to only showing one (which worked 100%) but did not try to determine a likely maximum number of video elements.

HTML5 canvas not showing redrawn content during mouse drags

I have a circuit simulator that redraws as you drag things around on an HTML5 canvas.
I've noticed that, sometimes, it fails to redraw during drags. It holds the last drawn frame until I stop moving the mouse, then starts showing updated content.
At first I thought this might be some kind of issue with the code I use the throttle the draws below 60fps. Maybe timer events were being swamped out by higher priority UI events or something like that. But I profiled the code in Chrome, and the profiler confirms the draw code is being called and finishing in a reasonable amount of time.
Here's a screenshot from an example profile I collected while dragging with the issue happening. Note the draw code finishing within 5ms, with plenty of idle time:
So mostly I'm stumped and need ideas of what to check.
What are some common reasons for redraws not to show when they are being triggered by user actions?
Use requestAnimationFrame instead of setTimeout.
During my testing (Chrome, Windows 10), I found that if I just spun the mouse wheel up and down quickly then I could prevent setTimeout callbacks from running until I stopped. That makes setTimeout a really bad idea when it comes to canvas animations. I switched the throttling code to using a requestAnimationFrame cycle, that just kept rescheduling itself until the cooldown period was over, and lag decreased noticeably.
Check for other draw loops.
I noticed that the profiler's stack trace is showing the wrong redraw code. The program had a dialog that contains a canvas that sometimes needs to animate. That code was spamming requestAnimationFrame despite the dialog not showing. Somehow this was interfering with the main draw loop, though I don't know exactly why. All the draws were happening in the hidden dialog.
Once I fixed the dialog code spamming requestAnimationFrame, the pause-while-dragging issue disappeared.

createjs ipad low performance

the situation is as follows: there is an HTML5 game. The game is quite heavy in terms of the javascript code, graphics and sounds – approximately 30 MB. All the animation is created by means of createjs. In the game I use 2 canvases one over the other; the control buttons are between the canvases (the buttons are created by means of the standard button elements).
One canvas is the main one and most of the animation is implemented on this canvas; the second canvas is used when it is necessary to show the animation over the control buttons. Initially, the size of each canvas was 970px x 740px. All the animation worked perfectly in desktop browsers as well as in Chrome and FireFox in Android. However, in the mobile Safari browser the animation worked very slowly.
Then I reduced the size of the canvases by 30 % (accordingly to the graph on the sprite sheets). As a result, Safari started working more efficiently on an ipad. The animation of the lower canvas stopped hanging but only unless the extra animation was launched on the upper canvas. Then everything got slow again. I don’t apply WebGL because I have to use both bitmap and the vector graphics. Who knows how to improve the situation in this case so as to prevent the FPS from falling, could you help me, please?
There is another funny thing: if you minimize the browser and then maximize it again, the game starts working faster from time to time.

While redrawing/panning the page in safari ipad/Iphone timer is not decreasing

I am facing one issue that in safari browser while dragging/moving the screening the javascript timer is not getting decreased. I have placed an alert message at the beginning of the function and I found that the function itself is not getting called.
So I am under such an impression that while repainting the screen in safari iphone/ ipad no javascript will work. Is it single threaded? how to achieve in safari ipad/iphone screen dragging and timer at the same time?
In Android while doing the same timer is actually getting decreased but not getting repainted. i.e. if for 15 seconds if I will drag the screen and the start time is 1.59 then while dragging it will show the time 1:59, but after stopping the dragging time automatically getting decreased by 15 seconds i.e. 1:44.
While investigating further I come across below document in developers.apple.com
"panning doesn’t generate any events until the user stops panning"
https://developer.apple.com/library/archive/documentation/AppleApplications/Reference/SafariWebContent/HandlingEvents/HandlingEvents.html
So now I think if We can create timer without events? Can I know the time-interval for which user is panning?
How to achieve the same Android experience in safari iphone/ipad?

Animating a DIV with JavaScript renders artifacts on Chrome

As an experiment, I am trying to replicate the Sprite functionality of AS3 in JavaScript without using the canvas object. I thought that using absolutely positioned divs and manipulating their css properties would be a no brainer, however in Chrome the animation introduces strange artifacts (seemingly because of redraw issues).
I can not find what I am doing wrong? The code is, in fact, quite simple. Here are some points that I tried which didn't help:
Using relatively positioned divs (as opposed to absolutely positioned.)
Using margins (as opposed to top & left properties.)
Appending objects directly to body (as opposed to appending to a container div.)
Using setTimeout (as opposed to requestAnimationFrame)
You can see a simplified fiddle here: http://jsfiddle.net/BVJYJ/2/
EDIT: http://jsfiddle.net/BVJYJ/4/
And here you can see the artifacts on my browser:
This may be a bug in my setup (Windows 7 64 bit, Chrome 21.0.1180.75). No other browsers exhibit this behaviour. I'd greatly appreciate if someone could comment on what I could be doing wrong. I'm more curious about the reason behind this rather than a workaround btw. That said, every explanation is welcome. :)
EDIT: There was a bug in the sample code which resulted in using setTimeout even when I was under the impression that RAF was used. requestAnimationFrame solves the issue with basic transformation but the issue remains with CSS transformations such as rotation.
I had the same problem with my liteAccordion plugin. It can be fixed by setting the backface visibility to hidden on the element you're animating, as you can see here: http://jsfiddle.net/ZPQBp/1/
Some research shows that setTimeout could cause issues due to various reasons. You really should use requestAnimationFrame:
Timers are not accurate to the millisecond. Here are some common timer
resolutions1:
Internet Explorer 8 and earlier have a timer resolution of 15.625ms
Internet Explorer 9 and later have a timer resolution of 4ms. Firefox
and Safari have a timer resolution of ~10ms.
Chrome has a timer resolution of 4ms.
Internet Explorer prior to version 9 has a timer resolution of 15.625
ms1, so any value between 0 and 15 could be either 0 or 15 but
nothing else. Internet Explorer 9 improved timer resolution to 4 ms,
but that’s still not very specific when it comes to animations.
Chrome’s timer resolution is 4ms while Firefox and Safari’s is 10ms.
So even if you set your interval for optimum display, you’re still
only getting close to the timing you want.
Reference: http://www.nczonline.net/blog/2011/05/03/better-javascript-animations-with-requestanimationframe/
Also
setTimeout doesn’t take into account what else is happening in the
browser. The page could be hidden behind a tab, hogging your CPU when
it doesn’t need to, or the animation itself could have been scrolled
off the page making the update call again unnecessary. Chrome does
throttle setInterval and setTimeout to 1fps in hidden tabs, but this
isn’t to be relied upon for all browsers.
Secondly, setTimeout only updates the screen when it wants to, not
when the computer is able to. That means your poor browser has to
juggle redrawing the animation whilst redrawing the whole screen, and
if your animation frame rate is not in synchronised with the redrawing
of your screen, it could take up more processing power. That means
higher CPU usage and your computer’s fan kicking in, or draining the
battery on your mobile device. Nicolas Zakas does an excellent job
explaining the impact timer resolution has on animation in a related
article.
Reference: http://creativejs.com/resources/requestanimationframe/
It has something to do with subpixel positioning. If you round off to the nearest pixel you won't see those rendering errors:
thisRef.block.style.left = Math.round((x + (mouseX - ox - x) * .125)) + "px";
thisRef.block.style.top = Math.round((y + (mouseY - oy - y) * .125)) + "px";

Categories