Resized (Scale down) image jagged, smooth on redraw (not reload) - google-chrome

I scale an image down using css, but then its edges are jagged. However, if I quickly switch to another tab in chrome and then come back, it is drawn correctly. I assume that this is because of somethings that happens during redraw. Is there any way to force a redraw using jquery? I have tried adding classes, elements, and changing other attributes.

Ok, thanks to the bump, I will add my solution here. What is really happening is we are trying to force a repaint of the entire window. The following does the trick:
function reDraw(){
//hack to redraw the elements on the page to avoid choppy look of resized items
//prevent reDraw from firing too early
setTimeout(function(){$('body').hide().show(0)},66);
}
The show hide combination will force a repaint of the area affected. note that the 0 on show is needed. The 66ms delay is used because forcing a repaint immediately after applying styles (in this case, a css resize) will bypass the recalculate styles function in the browser. 66ms is aprox. 15fps so it should still appear to happen instantaneously on any screen running at 30fps (it will take two screen refreshes if all goes well). A small blip from pixelated to non-pixelated is visible on a 60fps display, but how many people pay that close attention anyway?
Anyway, that is our solution. For us, it was used on a website that is built very similar to a video game as far as animation loop and other things. Because the screen is being refreshed a lot already, we found we only needed to call the reDraw function after the resizing of a PNG, but your requirements may be different.
Note that this function can be very resource intensive, and I have observed that many browsers need to collect garbage after this so you may need to evaluate how necessary the realtime aspect is. Use sparingly.
Enjoy!
~techdude

Related

Are svg images harder to render for a browser than bitmaps?

So I am making this horizontal scroll site which has a ton of images. I planned on using svgs for the entire site, but with only 20-30 svg images of medium to high complexity used in the page, and chrome already seems to be showing som jank and high paint times for scroll (and firefox is even worse, though safari seems to do a lot better).
Scroll timeline
View the site (scroll works on mac only, windows users can use arrow keys)
My question is, if I were to use pngs instead of svgs, would it reduce the paint times and hence the jank? Why is the browser struggling with only around 20 odd svg images?
As was my doubt, the problem turned out to be something completely different. Browsers are more than capable of handling multiple vector images. But what they aren't good at (and understandably so) is at redrawing those images very often.
Problem
My long horizontal scroll site was quite wide (30,000px). I had a background-color property applied to one of lower z-index'ed div's to represent the sky throughout the scroll site. I didn't want the sky to stretch the entire 30,000px since it essentially didn't change much, and hence gave it viewport width and height, with:
position:fixed;
Not a very smart move. Turns out that this property was causing my document layer to be repainted on every frame. Initially I though it was normal for browsers to do so on scroll, since Robby Leonardi's site, which I used as reference also repainted every frame.
Solution
Thanks to this article by one of the chrome dev tools developers, I set aside conventional wisdom, and make the sky layer
position:absolute;
and stretched it the entire site width, and boom! The paint rectangles were gone. And the scroll performance was smoother than butter.
Other solutions I tried
Hiding elements not near the viewport to make painting lighter, as suggested by #philipp, but didn't yeild any appreciable difference. Also, it felt super-hacky, and it wasn't targeting the root cause of the problem.
I tried modularizing my site into scenes and using translateZ(0) hack on each scene so that only the smaller scenes get repainted instead of the document. This actually helped quite a bit, and scroll was decent. Then,
I gave all the svg images their own layer by using translateZ(0). I started getting FPS of around 60 now, but again, this wasn't the right way of doing things.
I once had a similar thing. The SVG was 10 or more times as wide as the one shown above, it contained ~20k elements and was about 3MB in size. The only Thing what brought back performance (since it was a jump and run game) was an algorithm which was able to find all elements whose bounding box overlapped the viewport. With this I could use display: none; to hide everything what is invisible.
That reduced the amout of visible elements to ~150 per frame and the game ran again fluently.
I used a balanced binary tree (avl tree) and a one dimensional range query, since the height of the viewport was always the same as the image.
Good luck!
[EDIT]
Forgot to leave something like an anwer. From my Experience are large/huge SVG Graphics a bottleneck in rendering, especially if there is a lot of scripting happening. If you do not need any Interactivity with the elements from the Graphic, so nothing than a large Background Image, I would recommend to use a Tile map, based on PNG images, that is the standard way in Jump'n'Run games with huges »worlds«, so you can gain perfomance in two Points:
Rendering is faster,
You can »lazy ajax load« tiles, depending on visibility, to prevent users to download the »whole world« at startup.
Additinally you could use something like PIXI.js to render with WebGL, what will push the performance drastically and with it comes support for Tilemaps and Spritesheets.
If you insist on the advantages of Vector Grafics (Scaling, Interactivity) than you need to find a way to hide as much elements as possible to keep the frame rate high.

HTML5 and Canvas scrolling: trick interesting or useless?

I've already read all the stuff around scrolling:
Structuring an HTML5 Canvas/JS Game
and so on:
HTML5 Canvas tutorial
The secret to silky smooth JavaScript animation
Google search "HTML5 Scrolling"
Canvas Games
Build a vertical scrolling shooter game with HTML5 canvas
Math mayem
CAAT JavaScript framework
(The latest one is impressive, but even though almost everything is done there's nothing about scrolling).
Here's what I'm thinking about, and I didn't found something valueable about that. An idea just came to my mind and I'm wondering if I should take a lot of time thinking about that and trying, or not (that's why I'm asking here actually).
I'm planning to do a game with a scrolling "à la" Mario.
The big drawback about scrolling is that you have to redraw the whole background.
I've already avoided two performance problems of the sprite / scroll: create two canvas one top of each other:
the background
the sprites
And just erase the sprites.
The problem is about the background: I'm making a full copy of the background to the "visible" canvas. (note: there's no problem about flickering because writing in JavaScript is a blocking operation and all modern browsers handle vertical synch, so no double buffering needed).
Here's an old version of what I'm writing, but you'll get the big picture:
Test HTML5
Now I'm wondering for the scrolling: what if I do a "background div" instead of a canvas, with the appropriate CSS (background image for the background), and write the tiles on the image directly, then change CSS to simulate the scrolling? Should it be faster? If so, why? Is there any good idea out there for this?
On a semi-modern+ computer with a semi-recent+ browser, the fastest thing to do is probably to take a super-long div with background images, set overflow to hidden and scroll by adjusting scrollLeft or scrollTop properties. This is MUCH faster than adjusting CSS properties as it shouldn't trigger any reflow calculation in the CSS engine. Basically, any time you touch a DOM property that could have CSS impact, the whole (or at least a lot of) of) the structure of the document needs to be re-checked and re-rendered.
You could load in chunks of the backgrounds as they get close to avoid the one giant massive image load. I don't believe there is any 100% surefire way to pull an image out of memory across browsers but removing references to it in the DOM or in your CSS probably doesn't hurt when you've scrolled far enough past a piece of your background. That way the browser's garbage collector at least has the option of clearing memory.
In pan-mobile solutions that rely on webviews (like Cordova/Phonegap), however, well that's why I arrived at this question.
I have no idea but I'm pretty sure mixing HTML and canvas is a lousy idea for performance purposes. Right now I've got a not-super-complicated android game choking on 50x50 100px tiles in a canvas element in an android web view that also has some basic HTML in the mix for stuff like controls and separating a couple other canvas elements from the rest. I basically have a birds-eye-view ship cruising around and doing scans with a cheesy radiating circle grahic that reveals elements on a map fog-of-war style. Works great in a browser. Complete disaster in the cordova app version.
I suspect the only way I'm going to realize my pan-mobile game dev dreams is to use one of the many openGL-wrapped-in-a-canvas-API solutions out there and completely ditch the HTML which I find damned convenient for UI implementation, given that the bulk of my experience is in web UI. Another general tip for web view HTML is to avoid scrolling within internal elements if you can (so just let the body handle overflow). Scrolling overflow in anything but the body didn't even work in Android 2's webviews and it still seemed to cause 4.1's views to choke on an earlier/simpler version of the app I'm working on.
My final conclusion: after many tries, including Eirk Reppen suggestion, I write directly "raw" into hidden parts of the canvas and use CSS: all webbrowsers handle already image flickering and all that stuff around, and they have already optimized everything.
So each time I've tried to "optimize", the results were worse.
It seems that webbrowsers are made to handle properly basic stuff made by beginnners... maybe because 99% of HTML content is made by beginners.
Here is a demo of scrolling an oversize canvas by changing the CSS margin, this one based on scrolling with time: https://jsfiddle.net/6othtm0c/
And this version with mouse dragging: https://jsfiddle.net/ax7n8944/
HTML:
<div id="canvasdiv" style="width: 500px; height: 250px; overflow: hidden">
<canvas id="canvas" width="10000px" height="250px"></canvas>
</div>
JS for the scroll-with-time version:
canvas = document.getElementById("canvas");
context = canvas.getContext('2d');
for (var i = 0; i < 1000; i++) {
context.beginPath();
context.arc(Math.random() * 10000, Math.random() * 250, 20.0, 0, 2 * Math.PI, false);
context.stroke();
}
var t0 = window.performance.now();
setInterval(function(){
canvas.style.marginLeft = -(window.performance.now() - t0)/5 + "px";
}, 5);
fastest scrolling is to scroll using CSS. So you draw all background once, not only visible part, but all, and hide that is not visible, and use css to scroll it (margin, or position). No redraw, only CSS changes. This work really fastest. But if all map is really huge, other custom ways can be better.

browser repaints and performance

I have a single-page app that uses a lot of CSS3 shadows. The app consists of 8 panels that represent pages. Only 1 panel is visible at a time, while the other 7 are hidden (style display:none;). The user clicks on the menu to move from panel to panel.
Google's Speed Tracer that about 75% of resources is spent on repaints. My question is this: do browser repaints affect A) only visible elements of the page or B) every element, whether visible or not?
If it's B then there's not much I can do. If it's A then I could clear the html of the hidden panels and have inner DOM elements for only the visible panel with the goal of reducing repaint time.
Let me know.
The way to answer performance questions is to perform benchmarks. If you want to know how much performance overhead there is to display:none elements, do the following:
Test 1: Load the page with all the display:none elements, measure the repaint speed.
Test 2: Modify the page so that the display:none elements are removed completely, load this page, and measure the repaint speed.
The difference between the two tests is the repaint overhead of display:none elements. Hopefully it will be minimal.
Hidden elements shouldn't repaint. Are you animating the panel? Animating (esp. translating) an element that has shadows really puts the load on repainting. Also, the bigger the shadow, the longer it takes to repaint. I haven't done exact measurements, just drawing from personal experience; the 'jank' gets pretty obvious pretty fast, at least in older machines. Maybe try a background, data-uri image instead.

Panning Html5 canvas without rerendering

I would like to pan on my Html5 canvas without having to rerender, in a smooth transition (not jumpy). Is this possible? Are there code examples?
If possible, can this also be applied for zooming?
I have a performance issue when running on a lower end system (windows tablet), where panning just uses up too much cpu and ends up unusable. The scope is ~2000 graphic objects.
Unfortunately, you can't transform a canvas without redrawing it; however, if it is really just a matter of having too many draw calls, you can render the canvas once, cache the result, then on subsequent draws redraw the cached image. Note, this method won't really take well to scaling beyond maybe 150%, depending on the actual stuff you are drawing.
I made a fiddle that shows what this might look like:
http://jsfiddle.net/mobidevelop/sBvab/
There can be a little bit of jumpiness, but it's generally better than it is without caching the image.
Your mileage may vary.
In short, no. You must redraw the scene if you want panning on the canvas, unless you're doing something bad, like using CSS to limit visible canvas size and your canvas is actually larger. (Don't do this, it isn't a performance gain).
But redrawing your canvas as you pan ought to be fast if you've written it well. If it is "jumpy", then odds are something else is wrong here.
The above is also true for zooming, especially if you want your vector paths/text/etc to scale.

Do browsers render canvas elements that are not inside the viewport?

I have a page that has pretty heavy (mid-weight rather) canvas operations going on. To cater for users on mobile devices and older computers I was thinking I could implement a mechanism that will check if the canvas element is actually visible and decide if the constant calculations and canvas updates (animation running at 30fps) do have to be done or not.
This is working fine, yet when doing a performance test with the Chrome Dev Tools I noticed that even when I disable my visibility check and just let things render all the time the CPU usage of the function in question drops quite a bit when no part of the canvas element(s) is visible (although in theory it should still be performing the same tasks). So: at least on my computer running Chrome 17 it does not make a real difference if I check for the element's actual visibility.
To cut a long story short: Do I need to do this or are browsers smart enough to handle such a case without even telling them (and I can save the visibility checking)?
EDIT:
So I made some "research" on this topic and built this fiddle.
What happens is that it just generates noise at 30 frames per second. Not too pleasing to the eye but, well... The upper part is just a plain div to block the viewport. When I scroll down and have the canvas element in the viewport CPU Usage tells me it's taking up about 40%, so apparently the browser does have quite a lot to do here. When I scroll back up so that I just have the maroon colored div in my viewport and profile the CPU usage it drops to sth around 10%. When I scroll back down: usage goes up again.
So when I implement a visibility check like in this modified fiddle, I do see an increase (a tiny one to be honest) in CPU usage instead of a drop (as it has the additional task of checking if the canvas is inside the viewport).
So I am still wondering if this is some side effect of something that I am not aware of (or I am making some major mistake when profiling) or if I can expect browsers to be smart enough to handle such situations?
If anyone could shed a light on that I'd be very thankful!
I think you're confused between whether the logic is running and whether the rendering is happening. Many browsers now hardware-accelerate their canvases so all rendering happens on the GPU, so actual pixel pushing takes no CPU time anyway. However your tick function has non-trivial code to generate random noise on the CPU. So you're only really concerned over whether the tick function is running. If the canvas is offscreen, it certainly won't be rendered to the display (it's not visible). As for the canvas draw calls, it probably depends on the browser. It could render all draw calls to an off-screen canvas in case you suddenly scroll it back in to view, or it could just queue up all the draw calls and not actually do anything with them until you scroll the canvas in to view. I'm not sure what each browser does there.
However, you shouldn't use setInterval or setTimeout for animating Canvas. Use the new requestAnimationFrame API. Browsers don't know what you do in a timer call so will always call the timer. requestAnimationFrame on the other hand is designed specifically for visual things, so the browser has the opportunity to not call the tick function, or to reduce the rate it's called at, if the canvas or page is not visible.
As for how browsers actually handle it, I'm not sure. However, you should definitely prefer it since future browsers may be able to better optimise requestAnimationFrame in ways they cannot optimise setInterval or setTimeout. I think modern browsers also reduce the ordinary timers to 1 Hz if the page is not visible, but it's definitely much easier for the browser to optimise requestAnimationFrame, plus some browsers get you V-syncing and other niceness with it.
So I'm not certain requestAnimationFrame will mean your tick function is not called if the canvas is scrolled out of view. So I'd recommend using both requestAnimationFrame and the existing visibility check. That should guarantee you the most efficient rendering.
From my own experience it renders whatever you tell it to render regardless of position on screen.
An example is if you draw tiles, that exceeds the canvas size, you will still see the performance drop unless you optimize the script.
Try your function with a performance demanding animation, and see if you still get the same results.