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();
Related
I am trying to make an 'Eraser' for my fabricjs-based 0.5 Opacity free drawing app(with non-trivial background image), i. e. everything drawing is half-transparent and we still can see the background through the free drawing.
However I understand by default all free drawing are 'path-based' i. e. everything we draw (between mouse-down mouse up) is captured as an individual path in the canvas, so it is not possible to erase arbitrary part of the path. So I am thinking maybe we can capture the mouse-down/up event manually and draw an image pixie by pixie and place it on the canvas with opacity=0.5? so that we can use white to overwrite all those 'old' drawing?
Is this a workable/efficient enough solution?
However I am not sure how this can be implemented in fabricjs? could you please give me some advise on the steps or some pseudocode? thanks
I didn't complete my attempt when i had a similar problem , but the basic concept was simple 'Read the pixel under the cursor(and under the canvas, where another canvas with a background image was) and paint the path with the same color' , creating an eraser effect. The starting stone was this jsfiddle.net/DV9Bw/1/ maybe it can help you out, i didn't try it to its completion since the idea was quickly abandoned
Ok I am developing a game using Libgdx and everything was fine until I noticed that when my character moves, its texture becomes slightly blurred at the edges, as if it is blending in with the background in the android version. There seems to be a slight graininess to the image as well which becomes more noticeable when it moves. I THINK these problems might be related to texture filtering, but wanted to come on and ask here to see if anyone had experienced this before. Any insight appreciated.
EDIT: Here is an the image, you can see it's quite grainy on the whole. When it moves the graininess seems move, it is hard to describe, but it looks as if the pixels on the eater are moving relative to each other slightly.
The way I draw it is pretty straight forward the following is called in my render method:
idleTexture = new Texture(Gdx.files.internal("images/GreenGuy.png"));
spriteBatch.draw(idleTexture, x, y*ppuY,width*ppuX,height*ppuY);
All other work I look at does what I am doing, but I am not totally happy with the results. I have tried changing between linear and nearest filtering but this did not change anything. I have also tried just using a smaller image instead of shrinking a large one, but I still get the same problem of the pixels not remaining relatively static while the character is moving.
this.context.drawImage(myimage, 0, 0);
Putting the image on the canvas is pretty well covered all over the web.
But how do I remove it after it's there?
Canvas is an immediate drawing surface. This means that you execute a command on it (drawImage or fillRect) and it does that command, and it doesn't give a damn what has just done. There is no undoing of something.
You had a hard time searching for it because there's no such thing as "removing" for a Canvas. All it knows is that it has some pixels of some color from somewhere. It has no idea where.
To simplify a bit, there are generally two ways:
Clear the entire canvas, and draw everything all over again EXCEPT the one image you do not want drawn
Use two canvases, one that only has the image and one with all the other stuff. Clear this canvas with clearRect(0,0,width,height) and you're done.
You'll notice in 1. that you will probably have to start keeping track of the things that you draw on canvas if you want some of them selectively removed or repositioned. Instilling object persistence, or rather turning canvas from an immediate drawing surface to a retained drawing surface, is something that a lot of canvas libraries do. If you want to do it yourself, I've written a few tutorails to help people get started.
If you want to look into libraries, take a peek at easel.js. It's pretty learnable.
Option 1:
Draw a rectangle over it of the same color as the background.
Option 2 (works for non-trivial background, but slower):
Get the pixel data from the canvas before drawing the image, then redraw that pixel data to remove the image.
So I came up with a quick and easy way to clear my canvas. I just put my <canvas> tags in between <p> tags with an Id, then each time i needed my canvas cleared I just rerendered my <p> tags by changing the innerHTML, works like a charm.
I am implementing free drawing with HTML5 canvas. Currently every thing is working fine. I am using moveTo() and lineTo() for every mousemove. I have to fine tune the drawing;
when I draw some curve like lines with rapid movements, the drawing will be drawn like joints of straight lines. Is there any alternative way for drawing, to make the drawing smoother?
I dont think there is a better way for the drawing itself, however, if you put the draw functions directly onto the mouse move event handlers, then that would slow it down,
To speed that up you could just save the coordinates in an array in the event handlers and wait for the mouse to stop moving before walking trough the array and drawing.
The advantage would be that the events are called more reapidly, making smoother curves, the disadvantge would be that there is a 'lag' if you move the mouse alot.
An alternative would be to try and detect when the user curves and use the appropiate curve drawing method.
I actually did the same thing:
ctx.beginPath();
ctx.moveTo(lp.x-.5, lp.y-.5); // Last recorded position.
ctx.lineTo(cp.x-.5, cp.y-.5); // Current position at time of call.
ctx.stroke();
Bezier Curves are great for pen-like (paths) functionality, but I've ended up with unintended results with that as well, namely the curve between P0 and P2 being too distant from P1... This can be handled by adding extra points against which to evaluate the function (taking it to higher degrees, which seems to be how adobe does it).
I've spent two days answering this question, doing a lot of research of the best examples, tearing through code where available. There are essentially two responses:
1.) Apply a filter – a box- or gaussian- blur will smooth the rough edges a little, making it look less angular.
2.) Apply a Bezier Curve – Between the mousedown and mouseup events, log an array of the points and apply the curve. The longer the line, the slower the re-rendering.(Muro - deviantArt's canvas app appears to do this). [NB: If the idea is to create an artistic web app for people to draw on, show them the original line until the smooth rendering is complete.]
I like somewhere in between, personally. A slight blur tends to soften things, especially near corners, and makes slowly placed (thus frequent, shorter lines) much softer).
Something I'll add, which may be completely obvious so I apologize: Make sure you've set your cap style to 'round' –– ctx.lineCap = 'round'
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.