I am working with clip() in canvas.
I have made a region to clip(), as specified below
this.svgRenderer.ctx.rect(positionX, positionY, Width, Height);
this.svgRenderer.ctx.clip();
After few drawing on the same canvas, I am trying to remove the clip for that region by using save() and restore().
But I am making mistakes and can't get that.
So suggest any other way to remove the clip for the specified region without using save() and restore()
.clip is a permanent context state change.
It can only be removed by wrapping it in .save and .restore.
ctx.save();
ctx.clip(); // assuming the clipping path was already declared
// draw whatever needs to be clipped
ctx.restore(); // reset the clipping region
// (and any other attributes that have been modified since .save())
Changing the canvas element width will clear the context state (and remove clipping) but will also erase the existing drawings.
Related
So I'm trying to optimize my code by only accessing the DOM's canvas properties when the window is resized but I'm getting this weird problem. Why does the resizing prevent this? P.S. not sure what to include I have 2k lines of code right now.
I'm using
document.getElementById('mycanvas').getContext("2d").clearRect(-2000, -2000, 2000, 2000)
With this in my render loop:
document.getElementById('mycanvas').getContext("2d").height = window.innerHeight
Without it:
Setting either width or height properties of your HTMLCanvasElement will reset all the properties of your context to their default. It will also remove all clipping areas, and more interestingly in your case, it will reset the transformation matrix, and set a new pixel data (all transparent-black). And this is slow, so you are right removing it from your code.
Your call to ctx.clearRect sets the x and y coords to -2000, this means that with a default matrix transform, you are clearing non-existing pixels.
Setting your HTMLCanvasElement.height was what cleared your canvas previously.
We can also see on your second screenshot that you are drawing the grid slightly more on the bottom-right every time, this indicates that you are probably modifying the context matrix (e.g ctx.translate(x, y)).
Now that you don't reset it with the height setting, you need to do it explicitly. This can be done with ctx.setTransform(1,0,0,1,0,1).
So a basic start for a drawing function would look like
function draw() {
// clear
ctx.setTransform(1, 0, 0, 1, 0, 0); // reset the transform matrix (fast)
ctx.clearRect(0, 0, canvas.width, canvas.height); // clear all pixels (fast)
//... start drawing ...
Now, there might be other properties that you assumed where reset to their defaults while they're not, e.g fillStyle etc. Most of them can be simply set to what you want when needed.
If you are using ctx.clip() however (but looking at the screenshot, it seems you're not), you'd need to save() and restore() the context's state to be able to remove the clipping area (bad API design...).
I have a polygon object (say a car) drawn inside a HTML5 canvas with help of methods moveTo and lineTo. I want to repeatedly draw that object at different positions in the canvas (simulating a moving object). My problem is that the previous drawn object is not getting cleared. Instead, multiple images are drawn on the canvas. How can I fix this issue?
You have to clear the canvas at the start of every draw frame
context.clearRect(0, 0, canvas.width, canvas.height);
Canvases are just arrays of pixels, they know nothing of the shapes you have drawn.
There are animation tricks that used to be used on bitmapped displays (e.g. "xor drawing") that can be used to remove the old shape before you draw the new one, but on modern machines it's generally far simpler (and perfectly fast) to just erase the canvas and start again for each frame.
Given your comments to other answers, I'd suggest just using two Canvases - one for the static background and one for the car. If the background image is static it could even be an <img> element instead of a Canvas.
If the car image is static you could also just draw that once, and then use CSS positioning to set its position relative to the background for each frame.
suppose your shape is car then you first have to assign a new graphic like:
car.graphics = new createjs.Graphics();
car.graphics
.setStrokeStyle(1)
.beginStroke("#000000")
.moveTo()
.lineTo()
.lineTo()
I am trying to achieve grass like bend on a straight line created by using Cubic bezier curve.I have created a straight line using Bezier curve and now i want to bend it from top.But the problem I am facing is I am not able to do it dynamically.The moment I use mousemove for creating the bend,series of curves appear giving the canvas a paint like look which is somthing I dont want.I just want a single curved line.My question is how do I clear the previous lines that have been drawn and restore the latest bended curve??
My CODE:here is my code if you want to have a look at it
Create two canvases stacked on top of each other:
The first one containing the static content, the other only the dynamic content.
This way you will only need to be concerned about clearing the area the grass was drawn in (and this is much faster too as there is no need to redraw static all the time).
Place the two canvases inside a div which have position set to relative, then place the canvases using position set to absolute.
Now you can make a function to draw the static content (you will need to redraw it if the browser window gets resized etc.).
Record the area the grass is drawn within and clear only this (for each grass) in the next frame.
If this last is too complicated, just use a simple clear on the "dynamic" canvas:
ctxDyn.clear(0, 0, canvasDyn.width, canvasDyn.height);
This will also preserve transparency of this canvas, or "layer" if you like.
Use requestAnimationFrame to do the actual animation.
var isPlaying = true;
function animate() {
ctxDyn.clear(0, 0, canvasDyn.width, canvasDyn.height);
drawGrass(); //function to draw the actual grass
if (isPlaying) requestAnimationFrame(animate);
}
animate(); // start
The isPlaying is a flag you can toggle with a button on screen or something similar, to be able to stop the animation. See the link for requestAnimationFrame on how to make this cross-browser as this is still a "young" implementation.
dynCtx and dynCanvas can of course be called what you want.
You need to erase the current contents of the canvas before redrawing your updated "grass". This would involve redrawing everything else that is "static" on the canvas. For example:
function redraw() {
// Erase the current contents
ctx.fillStyle = 'white';
ctx.fill(0, 0, canvas.width, canvas.height);
// Draw the stuff that does not change from frame to frame
drawStaticContent();
// Draw the dynamic content
drawGrass();
}
In your mousemove event, update your grass curve information, then 'redraw'.
Is there a way to use an image as a clipping mask instead of creating a shape like this:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
// Clip a rectangular area
ctx.rect(50,20,200,120);
ctx.stroke();
ctx.clip();
I have tried to context.drawImage('myimg.png') on top of the context and clip but that did not work.
You can only directly clip using a path.
If you have an image that you wish to clip by, you can probably achieve this by drawing your content in another canvas, and then using globalCompositeOperation combined with drawImage (with the mask) to remove the bits you don't want.
You would then then use .drawImage again (possibly with a different globalCompositeOperation) to merge that clipped image with your original content.
See for example http://www.html5canvastutorials.com/advanced/html5-canvas-global-composite-operations-tutorial/
I have a number of objects that represent an image that I want to draw onto a canvas. Each object has a X, Y, Scale property as well as a render method that gets passed a canvas object. then the canvas tag is passed to each object's render method and they all need to render themselves to the canvas.
The problem I have is that scaling is being done from the origin of the canvas and not the origin of the image. To fix this I've tried the following:
canvas.translate(-this.X, -this.Y);
canvas.scale(this.Scale, this.Scale);
canvas.translate(this.X, this.Y);
The problem with the above code is that it looks like you can only have 1 translation and the 3rd line which is supposed to move the object back to its original position becomes the translation when calling drawImage. If I remove the 3rd line I get the correct scaling origin but the image is moved to 0,0 and not rendered in the correct location.
What is the proper way to do this type of scaling?
Try:
canvas.translate(this.X, this.Y);
canvas.scale(this.Scale, this.Scale);
canvas.translate(-this.X, -this.Y);
But keep in mind, doing this you will need to do alot of ctxt.save();s and ctxt.restore();s if you got the width and height of the imagens you could simple do ctxt.drawImage(this.image, this.X, this.Y, this.Width*this.Scale, this.Height*this.Scale); since you don't need to mess with the context state stack it may be faster.
Edit:
The transformations don't affect the origin. What happen is that they must be applied in reverse order. Remember this methods are just shortcuts for stacking matrices in the transformation stack.