I have a canvas element with a photo loaded on it. When clicking a link, the following is performed:
var ctx = canvas.getContext("2d");
ctx.scale(-1,1);
ctx.drawImage(canvas, canvas.width * -1, 0, canvas.width, canvas.height);
This works as expected (the image is flipped horizontally) on the first click, the third click, the fifth click, etc. On the second click, the fourth click, the sixth click, etc, nothing happens.
Any ideas on how I can get this to work for every click?
Yeah, the problem is because you're not restoring the canvas scale to 1,1 after you draw the image, so basically the first time the event is called your canvas scale is gonna be turned into -1,1 the next time it's gonna be 1,1 but you need it to be always -1,1. That's because you're drawing the image directly from the canvas and not from an image element thus, you gonna need to flip it every time.
Try using ctx.save() before the scaling and ctx.restore() after drawing the image. Or calling ctx.scale(-1, 1) again after drawing the image. Or you could just do the scaling outside the event (but after you've drawn the image to the canvas the first time) if your canvas is only used for this.
This here works for every click:
http://jsfiddle.net/4kcjn/2/
Ask yourself, what is different between it and yours?
It could be image-load related. Try yours without an image. Does it still have the same problem?
Related
I've seen other posts about this but I can't find anything to help me out.
I'm drawing an image on the canvas which moves, when it moves it leaves a trail of itself behind which hasn't been cleared. If I draw this image on top of another I get no trail but the image on top flickers. I don't think clearRect will work for me.
Can I save the canvas state between the image animation? Or should I be using a second canvas?
I'm not quite sure how to proceed, any advice would be great
* added examples - jsfiddle.net/zE67k/2 with an image and flicker. jsfiddle.net/zE67k/3 without an image and trail. this is just an example, I'm trying to achieve this with a background image to the canvas also.
* I also tried placing one canvas on top of another and I still get the flicker, I think the problem is where I place the clearRect. It does work if I put the clearRect just before the eye is drawn, but the way this code draws and updates the eyes does so one at a time, therefore the previous eye is cleared leaving only one. I'm trying it from this tutorial http://astronautz.com/wordpress/html5-eyes-that-follow-the-mouse/
You should save the clean canvas before drawing the other image ontop and restore that saved clean state before drawing the moved image again. You can use an additional canvas to save a clean state:
// create clean buffer
var buffer = document.createElement('canvas'),
canvas = document.getElementById('myCanvas');
buffer.width = canvas.width;
buffer.height = canvas.height;
// draw "background"/clean state to canvas
drawBackground(canvas);
// save clean state
buffer.getContext('2d').drawImage(canvas);
Then whenver you want to draw / move your other image/item simply restore the clean state:
canvas.getContext('2d').drawImage(buffer);
drawObject(canvas, x, y, w, h);
I am playing around with HTML5 Canvas to develop an interactive personal website.
I created a canvas 400x200 and then put a background image on it. Now on top of the BG Image, I have placed 5 more images. Now, my requirement is, depending on the image clicked I want to 1, display a text outside of the canvas, and 2, grey out the other 4 images (more in an animated form).
I am able to accomplish till displaying the images, I am unable to create a click event action. Is it because the whole canvas is treated as one single image? if so would using #usemap work? I tried adding a addEventListener event but nothing is happening.
is there a easier way in SVG to accomplish the same?
Thanks for any pointers.
You can add click handler on the canvas using jquery like this
$("#canvasId").click(function(e){
alert("canvas clicked";
}
Now you will have to determine the image at which the click event was occurred. If you know the top-left and bottomRight corner of the image you can determine the image on which you had clicked. To determine the mouse location you can use something like following
var x = Math.floor((e.pageX-$("#canvasId").offset().left) / 20);
var y = Math.floor((e.pageY-$("#canvasId").offset().top) / 20);
I'm messing around with HTML5 canvas and clipping. I am wondering how I can get the user to click on the canvas, have it clip a circle, and then repeat. So essentially, the user can click multiple times and there will be multiple clips.
I tried a couple solutions that were slightly similar to what I want but it isn't working.
Here is the clipping code:
context.save();
context.beginPath();
context.arc(mouseX,mouseY,50,50,Math.PI*2,true);
context.globalCompositeOperation = 'destination-out';
context.clip();
context.closePath();
var img = new Image();
img.src = canvasSnowflake.toDataURL();
context.drawImage(canvasSnowflake, 0, 0);
context.restore();
you can view the entire thing in action here: http://jsfiddle.net/cnbishop/8FzuB/. right now you can click one time and the clip works, but you can get a new clip if you click on the canvas again. Is this even possible?
Everytime the user clips you'll need to save this action somehow in JS. Next time the user clicks, you retrieve the past clipping, apply it and then apply the new clip action.
Basically, you need to reapply all the clipping actions in the history in the same order as they were executed as Canvas is unable to "remember" its previous rendering.
Did I interpret your question correctly?
I'm trying to program a paint application using Canvas.
the way it works is by connection lines when the mouse is pressed.
when the line is opaque it works well, but when I change the alpha parameter I get a problem.
I tried two options:
a. The path begins when the mouse is down for the first time and ends when the mouse is up again:
every move of the mouse calls the stroke() function. because the line is transparent the beginning of the whole path will become opaque and the end won't, because stroke() is called many times, and it drwas the whole path again and again.
b. The path begins and ends every move of the mouse:
the line is transparent through the whole way, but the matching point between every path and path are less transparent (because they're made of two lines). so the whole path is not solid.
the only way I get a good result is when I call stroke() only when the mouse is up again. then it strokes the whole path well, but I see nothing while actually drawing it.
what can I do?
thanks
I think your best bet is to create a second overlay canvas that is positioned (using absolute positioning) over your primary canvas.
During a mouse drag, for every mousemove event use a clearRect() to clear your overlay canvas and then draw the entire stroke-in-progress.
When you get a mouseup, clear the overlay and draw the entire stroke to the primary canvas.
Here's a live example:
http://jsfiddle.net/rnNFB/1/
I don't know the correct term, but in GTK I believe it was called a pixel buffer. You could copy all or some of the drawing area to a pixbuf, and then later dump the pixbuf back to the screen, rather than going through and rendering the entire thing all over again. I am implementing a menubar, and the menubar drops down and occludes everything underneath it. However, it takes a few seconds to draw the entire canvas, so I was wondering if there is a correct way to copy everything that will be occluded by the drop down menu, then when the drop down menu is closed, redraw it to the screen. I imagine this can be done with the context.getImageData() function, but I have read that it is extremely inefficient.
It is true, getImageData() is far too inefficient. But there's a better start for specifically what you're trying to do:
With canvas context's drawImage method, you can pass in an image but you can also pass in another canvas. So construct a temp canvas that will never be added to the page:
// only exists in javascript, not on the page
tempcanvas = document.createElement('canvas');
tempcanvas.height = (normal canvas width);
tempcanvas.width = (normal canvas height);
Then you can call tempcanvasContext.drawImage(normalCanvas, 0, 0) to take a snapshot of the current canvas right before the drop down menu is created. When the drop down menu disappears, you call normalcanvasContext.drawImage(tempcanvas, 0, 0) to draw it back.
I hope this gives a good general idea, and it should be much faster than getImageData. You can make it even more efficient by only copying the exact portions of the screen you want to redraw.