An example here.
var context=document.getElementById("canvas").getContext("2d");
//Red Box
context.beginPath();
context.fillStyle="Red";
context.rect(10,10,50,50);
context.fill();
//Pink circle
context.beginPath();
context.lineWidth="3";
context.fillStyle="Pink";
context.arc(250,250,50,0,Math.PI*2,false);
context.fill();
context.stroke();
context.font="1.2em Verdana";
context.fillStyle="Black";
context.fillText(context.isPointInPath(35,35),35,35);
context.fillText(context.isPointInPath(250,250),250,250);
If you write without beginPath all objects detected.
How to identify objects on the canvas or to omit beginPath?
If you want to use that function you need to rebuild the path every time you want to do the test (just don't call fill or stroke).
What I do normally instead is using my own point-in-polygon test function or my own spatial data structure if there are a lot of objects and speed is important.
Note that a canvas is just a bitmap and it doesn't store the commands you use to draw on it. That is why it cannot do the check after drawing a shape and you can test only the current path.
Once you call beginPath the previous path geometry is discarded and what you have are only the affected pixels if you called fill or stroke.
May be for your case it may make sense to check the color of the canvas pixel...
I've just read that a new addition to the canvas specification is Path() objects. Presumably these could be stored and subsequently tested and/or replayed. Could be useful. If I've understood the spec correctly.
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#path-objects
Related
In JS, I have some performance-critical code that essentially looks like this:
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
context.drawImage(otherImage);
I profile my code with Chrome and I find that the bottleneck is... clearRect.
Wait, what?
This is really stupid. I shouldn't even need to clearRect! I'm currently touching every pixel of context twice (once for clearRect, once for drawImage), which is a total waste. In theory, I should only need to do it once, to directly copy each pixel from otherImage to context.
How can I say something like "please, screw alpha blending and whatever, just replace the contents of context with whatever is in otherImage!"
You can ensure that no blending is done by calling context.globalCompositeOperation = 'source-over'; (default), which performs only alpha blending or context.globalCompositeOperation = 'copy'; which literally just copies the image on top of the existing content (see the examples here)
I am still not certain or even sure of what the setTransform does. I found this code example on the internet and have been messing around with it to see what different changes will do to the setTransform. What are the really uses and benefits from using the setTransform variable as opposed to just drawing a new rectangle.
Question: What are the benefits and uses of using setTransform?
Code:
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.fillStyle="yellow";
ctx.fillRect(0,0,125,50)
ctx.setTransform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="red";
ctx.fillRect(0,0,250,100);
ctx.setTransform(1,0.5,-0.5,1,30,10);
ctx.fillStyle="blue";
ctx.fillRect(0,0,250,100);
</script>
Each object on the canvas has a current transformation matrix.
The setTransform() method resets the current transform to the identity matrix, and then runs transform() with the same arguments.
In other words, the setTransform() method lets you scale, rotate, move, and skew the current context.
Note: The transformation will only affect drawings made after the setTransform method is called.
Source.
Some interesting examples of its usage.
Another good explanation
I am using the easelJS library with multiple bitmapSequence objects on my canvas. I may be asking the wrong question, because I don't understand how this works. I will try to explain my situation as clearly as I can.
I am placing multiple bitmapSequence objects (sprite animation sequences) on the canvas and moving them within the global tick() function, by setting the x and y properties. Once I set their x and y properties, I call stage.update(), which re-renders the canvas and all of the bitmapSequence objects with their new locations.
After the stage.update() call, but still within the tick() function, I assign the variable ctx to canvas.getContext('2d'). Then I call ctx.fillRect(0, 0, 8, 8). In this case the 0,0 (x,y) arguments for fillRect ALWAYS represents the origin point for the very last bitmapSequence object of which I modified the x and y attributes of prior to the stage.update() call.
This means if I draw a rectangle at 0,0 it will be show at the origin of the very last bitmapSequence object I used, and follow the bitmapSequence when I move it).
If I try to get a 2d context, and draw a rectangle prior to the stage.update() it does not show up on the canvas.
Ideally I would like to be able to draw rectangles relative to the origin of any bitmapSequence object I wish. Please help me understand what I am misunderstanding.
Maybe you are looking for translate() function? The behaviour of your program corresponds to behaviour of that function. So, if you want to reset the relative drawing, use ctx.translate(-x_of_last_bitmapSequence, -y_of_last_bitmapSequence).
Alternatively you can change the "starting point" of relative drawing:
ctx.save();
ctx.translate(x, y);
ctx.strokeRect(0, 0, 30, 30) // strokes a square at coords [x, y]
ctx.restore(); // restores the original state (relative coords are at [0, 0])
I was able to use the easelJS's Container object to achieve this instead. It allowed me to add objects to the container, and objects within the container moved with the container. Objects within the container had their x/y coordinates relative to the container, and the container had x/y coordinates relative to the canvas. It worked just as I expected it to.
I still don't know what is up with the 2D context in conjunction with easelJS.
I'm currently implementing a 2d deformable terrain effect in a game I'm working on and its going alright but I can envision it becoming a performance hog very fast as I start to add more layers to the effect.
Now what I'm looking for is a way to possibly save a path, or clipping mask or similar instead of having to store each point of the path in the terrain that i need to draw through each frame. And as I add more layers I will have to iterate over the path more and more which could contain thousands of points.
Some very simple code to demonstrate what I'm currently doing
for (var i = 0; i < aMousePoints.length; i++)
{
cRenderContext.save();
cRenderContext.beginPath();
var cMousePoint = aMousePoints[i];
cRenderContext.arc(cMousePoint.x, cMousePoint.y, 30, 0, 2 * Math.PI, false);
cRenderContext.clip();
cRenderContext.drawImage(cImg, 0, 0);
cRenderContext.closePath();
cRenderContext.restore();
}
Basically I'm after an effecient way to draw my clipping mask for my image over and over each frame
Notice how your clipping region stays exactly the same except for its x/y location. This is a big plus.
The clipping region is one of the things that is saved and restored with context.save() and context.restore() so it is possible to save it that way (in other words defining it only once). When you want to place it, you will use ctx.translate() instead of arc's x,y.
But it is probably more efficient to do it a second way:
Have an in-memory canvas (never added to the DOM or shown on the page) that is solely for containing the clipping region and is the size of the clipping region
Apply the clipping region to this in-memory canvas, and then draw the image onto this canvas.
Then use drawImage with the in-memory canvas onto your game context. In other words: cRenderContext.drawImage(in-memory-canvas, x, y); where x and y are the appropriate location.
So this way the clipping region always stays in the same place and is only ever drawn once. The image is moved on the clipping-canvas and then drawn to look correct, and then the in-memory canvas is drawn to your main canvas. It should be much faster that way, as calls to drawImage are far faster than creating and drawing paths.
As a separate performance consideration, don't call save and restore unless you have to. They do take time and they are unnecessary in your loop above.
If your code is open-source, let me know and I'll take a look at it performance-wise in general if you want.
Why not have one canvas for the foreground and one canvas for the background? Like the following demo
Foreground/Background Demo (I may of went a little overboard making the demo :? I love messing with JS/canvas.
But basically the foreground canvas is transparent besides the content, so it acts like a mask over the background canvas.
It looks like it is now possible with a new path2D object.
The new Path2D API (available from Firefox 31+) lets you store paths, which simplifies your canvas drawing code and makes it run faster. The constructor provides three ways to create a Path2D object:
new Path2D(); // empty path object
new Path2D(path); // copy from another path
new Path2D(d); // path from from SVG path data
The third version, which takes SVG path data to construct, is especially handy. You can now re-use your SVG paths to draw the same shapes directly on a canvas as well:
var p = new Path2D("M10 10 h 80 v 80 h -80 Z");
Information is taken from Mozilla official site.
Can I stroke a path so that it is not drawn on screen but converted to a new path? If so, how?
In canvas, (almost) all shapes, stroked or filled, are paths. There is no concept of a "stroke" in canvas, but there is the concept of calling stroke() on a path.
What you can do is create a path, fill it, and then stroke the very same path.
ctx.beginPath();
ctx.moveTo(50,50);
ctx.lineTo(100,100);
ctx.lineTo(25,100);
ctx.closePath();
ctx.fillStyle = 'gold'
ctx.fill();
// The path is still there, lets stroke it
ctx.lineWidth = 4;
ctx.stroke();
Live example:
http://jsfiddle.net/9SK2C/
However note that once you start a new path, that old path is lost forever. There is no built in way to save or restore paths. If you want to keep track of a path to save/restore it, you have to account for it all yourself.
You also cannot edit a path. You can add it the end of it, but there's no going back and modifying the points in a path like there is in (say) SVG. You gotta remake it from the start with the new points instead.