How can I optimize updating lots of things on an HTML5 canvas? - javascript

I have a HTML5 canvas that fills the screen and looks like this:
In this state it is fully zoomed out, but I allow the user zoom in and pan around like in google maps. Every time the viewport changes, I redraw everything that is visible inside the viewport to the canvas. (So as you zoom in less things need to be drawn).
Right now zooming and panning comes with a lot of lag, because each redraw takes 30 milliseconds. When profiling in google chrome, the majority of the time comes from the context.fill() (for drawing a coloured circle) and context.drawImage() (for drawing a glossy transparent overlay on the circles).
So my rendering is very inefficient, but since the draws only happen when the viewport bounds change, its not like I have the option to only redraw a small portion of the screen at a time.
Does anyone know another way I can optimize this?
One idea I was wondering about was to draw the entire thing onto an invisible canvas, and only copy over the viewport bounds to the main canvas. But the invisible canvas would be 2000x2000 pixels. So I am unsure if this would be a good idea.

Drawing multiple light images is faster than drawing multiple fill+images and drawing a single image containing a grid of multiple lights is faster still. So...
Draw a single image of the 17x17 grid of lights all red (or all brown if brown is more common).
Then over-draw only those lights that need to be brown.
Use images of the brown lights rather than brown fill + a glossy overlaid image.

Related

HTML5 Canvas: How to draw a constant-sized image that translates properly when zooming?

I want to create a canvas that draws a background image but allows zooming and dragging as well. I came across this stackoverflow answer Zoom Canvas to Mouse Cursor. It's perfect except for one thing, it scales every image it draws because of the canvas scale factor.
I need to draw some markers on the image that don't scale when zooming in, kinda like those red arrows on google maps.
So I tried scaling the size of the image by the inverse of the zoom factor so it would be constant-sized and it worked but of course it doesn't stay at a specific spot on the image. Why does this happen and how should I fix it?
Draw 2 canvases on each other.The upper one(with a higher zindex) will be utilized for drawing the markers.The lower canvas(with a lower zindex) will be used to draw image on.You should perform all your manipulations(zoom and pan) on the lower canvas context keeping the upper one unchanged.

Creating an X-ray vision effect on an image HTML5 [duplicate]

If I change the cursor of a page into a 'flashlight' (say, a circle), and I want to reveal an image only when passing the light (the circle) over it, what would be the best way to go about this? Using css clip? But then it can only do rectangles, so I'd have to use canvas? Perhaps there's an easy way to intersect the two images?
You can do this with a canvas easily.
Here's an example:
http://jsfiddle.net/gfZ5C/
On every mouse move, we clear the canvas, redraw the image, make a clipping region that is a circle cut out of a rectangle, and draw black on the entire canvas (which will draw only on the clipping region)
Make sense?
There are a lot of ways to achieve this effect and similar effects. You can also make much fancier light sources with a bit of canvas sorcery. See for instance my answer here: Canvas - Fill a rectangle in all areas that are fully transparent

Wraparound for HTML5 Canvas: How to Get (Static) Shapes to Continue around Edges of Canvas

I'm trying to draw a tiled background using Javascript on an HTML5 canvas, but it's not working because shapes that intersect the edges of the canvas don't wrap around to the other side. (Just to be clear: these are static shapes--no motion in time is involved.) How can I get objects interrupted by one side of the canvas to wrap around to the other side?
Basically I'm looking for the "wraparound" effect that many video games use--most famously Asteroids; I just want that effect for a static purpose here. This page seems to be an example that shows it is possible. Note how an asteroid, say, on the right edge of the screen (whether moving or not) continues over to the left edge. Or for that matter, an object in the corner is split between all four corners. Again, no motion is necessarily involved.
Anyone have any clues how I might be able to draw, say, a square or a line that wraps around the edges? Is there perhaps some sort of option for canvas or Javascript? My google searches using obvious keywords have come up empty.
Edit
To give a little more context, I'm basing my work off the example here: Canvas as Background Image. (Also linked from here: Use <canvas> as a CSS background.) Repeating the image is no problem. The problem is getting the truncated parts of shapes to wrap around to the other side.
I'm not sure how you have the tiles set-up, however, if they are all part of a single 'wrapper' slide which has it's own x,x at say 0,0, then you could actually just draw it twice, or generate a new slide as needed. Hopefully this code will better illustrate the concept.
// Here, the 'tilegroup' is the same size of the canvas
function renderbg() {
tiles.draw(tiles.posx, tiles.posy);
if(tiles.posx < 0)
tiles.draw(canvas.width + tiles.posx, tiles.posy);
if(tiles.posx > 0)
tiles.draw(-canvas.width + tiles.posx, tiles.posy);
}
So basically, the idea here is to draw the groupings of tiles twice. Once in it's actual position, and again to fill in the gap. You still need to calculate when the entire group leaves the canvas completely, and then reset it, but hopefully this leads you in the correct direction!
You could always create your tillable image in canvas, generate a toDataUrl(), and then assign that data url as a background to something and let CSS do the tiling.. just a thought.
Edit: If you're having trouble drawing a tillable image, you could create a 3*widthx3*width canvas, draw on it as regular (assuming you grab data from the center square of data as the final result), and then see if you can't draw from subsets of the canvas to itself. Looks like you'd have to use:
var myImageData = context.getImageData(left, top, width, height);
context.putImageData(myImageData, dx, dy);
(with appropriate measurements)
https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas/
Edit II: The idea was that you'd have a canvas big enough that has a center area of interest, and buffer areas around it big enough to account for any of the shapes you may draw, like so:
XXX
XCX
XXX
You could draw the shapes once to this big canvas and then just blindly draw each of the areas X around that center area to the center area (and then clear those areas out for the next drawing). So, if K is the number of shapes instead of 4*K draws, you have K + 8 draws (and then 8 clears). Obviously the practical applicability of this depends on the number of shapes and overlapping concerns, although I bet it could be tweaked. Depending upon the complexity of your shapes it may make sense to draw a shape 4 times as you originally thought, or to draw to some buffer or buffer area and then draw it's pixel data 4 times or something. I'll admit, this is some idea that just popped into my head so I might be missing something.
Edit III: And really, you could be smart about it. If you know how a set of objects are going to overlap, you should only have to draw from the buffer once. Say you got a bunch of shapes in a row that only draw to the north overlapping region. All you should need to do is draw those shapes, and then draw the north overlapping region to the south side. The hairy regions would be the corners, but I don't think they really get hairy unless the shapes are large.... sigh.. at this point I probably need to quiet down and see if there's any existing implementations of what I speak out there because I'm not sure my writing off-the-cuff is helping anybody.

Canvas overlapping elements

I have a canvas animation that sometimes redraws the exact same element over another (it is a long story why this is necessary) but it happens, and it happens often enough.
Now I assumed that drawing an element (using a context path and the stroke method) over an existing exact replica of the image should do nothing at all to my animation. Instead it draws over the past image and blurs all the sides (as if it didn't exactly draw at the same location.
Please let me know if there is a way to fix this
Thanks
This is happening because canvas strokes are anti-aliased. In a practical sense you're drawing some semi-opaque pixels over some other semi-opaque pixels, and where the pixels are overlaid their opacities are added together. I don't think you can (currently) force the canvas object to turn off anti-aliasing on strokes, so you may just have to live with it. Is it that big of a problem?
http://img813.imageshack.us/img813/303/canvasl.png
EDIT: I guess you could try using PNGs with transparent backgrounds for your markers, instead of drawing them with strokes. https://developer.mozilla.org/en/Canvas_tutorial/Using_images

Html Canvas Intelligent Drawing

I'm currently implementing a HTML canvas based webapp that features panning. Is there a way to use an auxiliary buffer to hold the presently visible area so when I pan I don't have to redraw the whole canvas and only have to draw the newly visible areas?
See my previous response to a related question: What is the fastest way to move a rectangular (pixel) region inside a HTML5 canvas element
Just draw the entire canvas in a div that has overflow:hidden and implement panning as re-positioning the top and left of the canvas within that div. It is much faster. And don't worry about drawing canvases tens of thousands of pixels wide/tall, I've successfully used this on very-very large and complex HTML and SVG elements.
Take a look at the pixel manipulation API.
http://dev.w3.org/html5/2dcontext/#pixel-manipulation

Categories