Clear Canvas Rect (but keep background) - html

I'm trying to animate a circle and just moving it horizontally which works fine. However while the circle is moving, I have to do a clearRect over that circle so that it redraws it self in the horizontal direction. When I do a clearRect it also makes the background have white box around so effectively its going to be one white horizontal line in the direction the circle is moving.
Is there a way to clear the circle without clearRect?
If I have to keep redrawing the background after clearRect the canvas will flicker when theres say 10 circles moving in that area.
Any other approaches to solving this?
function drawcircle() {
clear();
context.beginPath();
context.arc(X, Y, R, 0, 2*Math.PI, false);
context.moveTo(X,Y);
context.lineWidth = 0.3;
context.strokeStyle = "#999999";
context.stroke();
if (X > 200)
{
clearTimeout(t); //stop
}
else
{
//move in x dir
X += dX;
t = setTimeout(drawcircle, 50);
}
}
function clear() {
context.clearRect(X-R, Y-R, 2*R, 2*R);
}

Basics: HTML5 Canvas as a Non-Retained Drawing Mode Graphics API
First, let us discuss the manner in which the HTML5 Canvas works. Like a real-world canvas with fast-drying oil paints, when you stroke() or fill() or drawImage() onto your canvas the paint becomes part of the canvas. Although you drew a 'circle' and see it as such, the pixels of the circle completely replaced the background (or in the case of anti-aliasing at the edges of the circle, blended with and forever changed them). What would Monet say if you asked him to 'move' one of the people in a painting a little bit to the right? You can't move the circle, you can't erase the circle, you can't detect a mouseover of the circle…because there is no circle, there is just a single 2D array of pixels.
Some Options
If your background is fully static, set it as a background image to your canvas element via CSS. This will be displayed and overlaid with content you draw, but will not be cleared when you clear your canvas.
If you cannot do the above, then you might as well just clear the entire canvas and re-paint it every frame. In my tests, the work needed to clear and redraw just a portion of the canvas is not worth the effort unless redrawing the canvas is very expensive.
For example, see this test: http://phrogz.net/tmp/image_move_sprites_canvas.html
In Safari v5.0.4 I see 59.4fps if I clear and re-draw the entire canvas once per frame, and 56.8fps if I use 20 clearRect() calls and 20 drawImage() calls to re-draw just the dirtied part of the background each frame. In this case it's slower to be clever and keep track of small dirty regions.
As another alternative, use a retained-drawing graphics system like SVG or HTML. With these, each element is maintained independently. You can change the position of the item and it will magically move; it is up to the browser to intelligently draw the update in the most efficient manner possible.
You can do this while retaining the power of custom canvas drawing by creating and layering multiple canvases in the same HTML page (using CSS absolute positioning and z-index). As seen in this performance test, moving 20 sprites via CSS is significantly faster than trying to do it all yourself on a single canvas.
Flickering?
You wrote:
If I have to keep redrawing the background after clearRect the canvas will flicker when theres say 10 circles moving in that area.
That has never been my experience. Can you provide a small example showing this 'flicker' problem you claim will occur (please specify OS, browser, and version that you experience this on)? Here are two comments by prominent browser developers noting that neither Firefox nor Safari should ever show any flickering.

This is actually very easy to accomplish by simply positioning more than one canvas on top of each other. You can draw your background on a canvas that is (wait for it...) in the background, and draw your circles on a second canvas that is in the foreground. (i.e. stacked in front of the background canvas)
Multiple canvases is actually one of the best ways to increase performance of anything animation where elements of the final image move independently and do not not necessarily move in every frame. This allows you avoid redrawing items that have not moved in every frame. However, one thing to keep in mind is that changing the relative depth (think z-index) of items drawn on different canvases now requires that the actual <canvas> elements be reordered in the dom. In practice, this is rarely an issue for 2D games and animations.

Contrary to what the accepted answer suggests; yes, you can restore previous draw states, and contrary to what the other answers imply; no, you don't need additional canvases to do so:
The CanvasRenderingContext2D API includes the functions getImageData() and putImageData(). After creating a background image, store the whole thing in a variable const background = context.getImageData(x, y, width, height) (a simple RGBA bitmap of type Uint8ClampedArray), then after wiping the canvas with clearRect() or whatever, restore the background image simply by passing that variable back in the opposite direction: context.putImageData(x, y, background).

There are two ways you can do it that may reduce the flickering, esp if you have many circles.
One is double buffering, and for a brief question on this you can look at:
Does HTML5/Canvas Support Double Buffering?
Basically, you draw on two canvases, and swap them in and out as needed.
This would be the preferable option, esp with many changes per frame, but, the other way I have done this is to just draw over the circle I want to erase, using the background color, then draw with the correct color the new circle.
The only problem is that there is a small chance that you may leave some evidence of the attempted erasing, as it seems that for some shapes it is hard to get it to draw exactly on top.
UPDATE:
Based on a comment you can look at this discussion about double buffering on the canvas:
HTML canvas double buffering frame-rate issues
The basic idea is to keep track of everything you have drawn, with the current position, then on a separate canvas, you redraw everything, then, flip them out, and then I would just redraw again, in the new positions, to ensure that the image looks exactly like it should. Swapping them in and out is a quick operation, the only problem would be if you put event handlers on the canvas, in this case, have them on the div or span surrounding the canvas, so this information doesn't get lost.

Related

what is it that you can do with canvas and not with SVG?

I am working on project I need to choose between the SVG and Canvas. I am finding SVG best at most of the things.
Are there anythings that you can not do with the SVG but you can with Canvas?
First,
If you already have invested time in the SVG learning curve, you might well complete your project without Canvas because these 2 elements do remarkably similar things. Canvas has a fairly large & steep learning curve that you might want to avoid "mid-project".
Contrary to popular opinion...Both Canvas and SVG use vector drawing commands!
They use vector commands to paint lines and curves on their drawing surfaces. Both Canvas and SVG render those drawings onto their element surfaces as pixels.
And...
Both Canvas and SVG can transform (offset, rotate and scale) their drawings. Both Canvas and SVG can apply style to their drawings (fill color, stroke color, opacity, etc).
But...
SVG goes one step further and "remembers" all the drawing commands. This means SVG can reissue those drawing commands even when scaling. So SVG is ideal for drawings that must be scaled without becoming "jaggy". You can even use CSS to re-style your drawings (change colors, opacity, position, rotation, etc). That's often very useful. For example, you can make an SVG leopard change the color of its spots with CSS!
Canvas just "draws and forgets" -- it remembers nothing about what or where it's drawn. As such, it's a lighter element. You say: "But canvas does all those games with moving players". With canvas, the programming practice is to erase the canvas and redraw any shapes in their new positions. This gives the illusion that the shapes are being commanded to move (which they are not). Canvas is built to be extremely fast at these redraws and will easily redraw modestly complex game scenes at 60 frames per second. This speed comes at the cost. You must "remember" where your scene elements are so you can later re-render them in their new positions and with their new stylings. (No simple CSS ability to make a canvas leopard change its spots).
SVG drawings come with the traditional mouse events already built in. Canvas only fires the traditional mouse events on the canvas as a whole and not on individual drawings (because canvas forgets about the shapes it's drawn). Therefore, if you want to get mouse events related to an individual canvas shape you must (1) Remember where you drew your shapes (2) listen for the mouse event on the whole canvas, (3) check if the mouse is inside any shape (this is easily done mathematically) and then handle the mouse event for your discovered shape. Canvas elements require more code to impliment.
IMHO, one particular use-case where canvas shines:
In addition to these functional differences, Canvas lets you examine and change any pixel on the canvas surface. In particular, this valuable pixel information lets you do some nice tasks with images:
Recolor any part of an image at the pixel level (if you use HSL you can even recolor an image while retaining the important Lighting & Saturation so the result doesn't look like someone slapped paint on the image),
"Knockout" the background around a person/item in an image,
Detect and Floodfill part of an image (eg, change the color of a user-clicked flower petal from green to yellow -- just that clicked petal!),
Do Perspective warping (e.g. wrap an image around the curve of a cup),
Examine an image for content (eg. facial recognition),
Answer questions about an image: Is there a car parked in this image of my parking spot?,
Apply standard image filters (grayscale, sepia, etc)
Apply any exotic image filter you can dream up (Sobel Edge Detection),
Combine images. If dear Grandma Sue couldn't make it to the family reunion, just "photoshop" her into the reunion image. Don't like Cousin Phil -- just "photoshop him out,
Play a video / Grab a frame from a video,
Export the canvas content as a .jpg | .png image (you can even optionally crop or annotate the image and export the result as a new image),
Many more image pixel manipulations that haven't come to mind!
Canvas is a pixel manipulation element.
SVG is vector element container.
I feel distinction between these two is outside the scope of StackOverflow to dicuss, as it is related to computer art basics, not programming and there is a lot of information available if not in search engines then in WikiPedia. For example one would use pixel-based media for pixel games.

HTML 5 canvas image special effects

I'm working on a 2d tile based HTML5 canvas application and I would like to know what kind of special effects I can apply to the images as their being drawn ( context.drawImage(...) ). The only trick I've come across is modifying the canvas.globalAlpha value. This leaves some color from the previous frames, creating a blurring or dazed effect if things on the canvas object are moving from frame to frame.
Is there something for rendering images that is comparable to setting the context.fillStyle to an ARGB value for primitive shapes?
Is there a multiply mode? ie: multiply the image pixel color by the destination color. This could be used for primitive lighting. (I've toyed around with context.globalCompositionOperation but didn't find anything interesting)
Are there any other cool effects you've come across?
NOTE: I don't want to use WebGL for this application, and it's a game. That means it's realtime and I can't modify each pixel with javascript code because that takes too long. (although I could probably do that when the player dies and nothing is moving on the screen anymore)
Canvas doesn't provide any predefined effects.
To manipulate the image shape you can use matrix transformations.
To manipulate the image pixels and colors you should use getImageData method - http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#pixel-manipulation.
Then use google to find algorithms to apply some effects like swirl, blur, emboss etc.

HTML5 Canvas - Animating color, scale, and rotation

I'm new to canvas, so pardon the beginner question. I'm trying to animate a square on a canvas that changes colors, rotates, and scales up and down (this is just for practice). I'm just trying to grasp all of the concepts and create an example that does all of them at once.
What I want it to do is scale up to a certain amount, then once it reaches that amount, it scales back down to the beginning amount (and then repeats). The same goes for the color (continue animating, then go backwards through the colors). How can I accomplish this?
Here's an example of my code that I wrote:
http://jsfiddle.net/ggsFJ/1/
You'll notice a couple bugs:
Once the color gets to yellow, it stops animating.
The scaling obviously doesn't work.
The rotation isn't either clearing the canvas fast enough or something, because it's showing a trail of positions.
Where can I find some resources on accomplishing this? Any help is appreciated.
There's one small problem that's causing all the other problems (well, apart from the yellow - I'm not experiencing that particular one):
ctx.restore;
That line does nothing. You need to call ctx.restore using parentheses. Once you do that, the scaling works, and clearRect() will clear a non-transformed rectangle:
ctx.restore();
And here's the updated demo.
The problem I can see is with your restore method call.
You are just saying ctx.restore (possibly by mistake). It should be ctx.restore();

html5 basic paint tool

I'm new to html5. And I'm trying to create a basic painting tool.
What I want to do in this tool is to have one or more shapes(maybe overlapping) and to paint the shapes without getting the colors overlapped. If a circle is drawn inside a rectangle and if I start coloring the circle, the rectangle should not be painted even if the mouse is dragged over it unless the dragging starts inside it.
To achieve this should I use multiple canvases or shapes?
Thanks in advance.
Well, first you need to program in the idea of keeping track of separate shapes. If you haven't already done that see here for a tutorial.
I imagine your shapes will all be kept as images or in-memory canvases themselves. I'm not sure how else you can do it.
There are a million ways you could do this, here's one:
When you start your drawing operation you need to detect which shape you're on. Then you draw that shape to an in-memory canvas and switch that temporary canvas' globalcompositeoperation to source-atop. This will make sure the paint can only paint in the already opaque regions of that shape (if that's your intent here, which it seems to be).
All while you are painting you will want to update the temporary canvas and redraw the main canvas constantly. While you are redrawing the main canvas, instead of painting that shape's image file you'll want to paint the temporary canvas (if you use canvases to keep the shapes you can just update those in real time).
If you are not using temporary canvases for each shape, when you stop the drawing operation you are gonna have to update the image associated with the shape to complete the operation.
Using an in-memory canvas (not added to the DOM) for every shape (that is the size of the shape and no larger) will make coding things slightly easier and might not be that bad on performance. I'd give it a try with 100 and 1000 (or more) in-memory canvases on your targeted platforms to see though.
The alternative is to use one in-memory canvas and have an HTMLImageElement (png) that represents every shape, but using the canvas.toImageURL function can be a bit of a performance hit in itself. I'd try both methods to see which works best in your case. If the shape count is small enough, it probably doesn't matter which.

Zooming in and out on canvas

I wrote a paint application using the HTML5 canvas element.
Now I want to give the user an option to zoom in and out while painting.
How can I do this?
There are a few ways. It really depends on what you're looking for.
You could do it by scaling the entire context, as in ctx.scale(2,2), and then redrawing everything at this larger scale. Several things drawn, like paths and text, will scale gracefully. To accomplish this you will need to keep good track of everything drawn so far.
Another way is to take the entire canvas and draw it back to itself. This requires a temporary canvas because the operation is really: Draw to temp canvas, clear main, draw back to main scaled.
Another way is to use CSS transforms to merely zoom the canvas itself, which will make the image blurry (its zoomed!) but does not require changing any of the pixels already on the canvas.