Mask an image using image map or canvas? - javascript

Okay, my issue is better explained visually:
I need to make those 5 images easily replaceable without the client having to manually cut angles out of images, etc. So I'm picturing it this way:
I created PNG masks for the blue bar and blue space above them. But the images still overlap at the bottom because they are all square (see last image for an example). Is there any way, using an image map (or even javascript) to cut/mask pieces out of a square image on page load?
Thanks,
Chris

I think your best option would be to use canvas unless I'm forgetting something with css3
<canvas id="image1" width="___" height="____">
</canvas>
var people = [___];
var canvas = document.getElementById("image1");
var context = canvas.getContext("2d");
context.drawImage(people[0], x, y, width, height);
context.beginPath();
context.moveTo(x, y);
context.lineTo(x1, y1);
context.lineTo(x2, y1);
context.arcTo(x, y);
context.clip();
context.closePath();
I may have messed up but I'm going for something like this
(x, y)\__
/ \__
/ \__
(x2, y1)(_________________\(x1, y1)
Which is my best way of drawing the leftmost pizza slice with ascii
Doing this will require multiple canvas elements. where each one represents one slice. The reason is because clipping will erase everything but what's in the path.
Resources:
MDN:clipping

Related

How to remove a drawn arch from canvas

I have been trying to print arc in the html page. How can i remove the already drawn arch from the page?. i have written the below code.
<!DOCTYPE html>
<html>
<body>
<canvas id="myCanvas" width="1200" height="1000"
style="border:1px solid #d3d3d3;">
Your browser does not support the HTML5 canvas tag.</canvas>
<script>
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
/*ctx.beginPath();
ctx.arc(600,500,20, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
ctx.beginPath();
ctx.arc(600,500,40, 0.5*Math.PI,2*Math.PI);
ctx.stroke();
*/
var radius=20;
for (i=0; i<10; i++)
{
var ctx = c.getContext("2d");
ctx.beginPath();
ctx.arc(600,500,radius, 0.5*Math.PI, 2*Math.PI);
ctx.stroke();
radius= radius+30;
}
</script>
</body>
</html>
How can i achieve this?.
Call clearRect method:
ctx.clearRect(0, 0, 1200, 1000)
The four arguments are:
axis-X of left top corner of the area to wipe
axis-Y of left top corner of the area to wipe
width of the area to wipe
height of the area to wipe
So with this method, you could wipe either the whole canvas or just a certain part of it.
If you want to remove the whole previously drawn image please take a look at the other anwers. In the comments OP made it clear that this is not what he was trying to achieve. So instead I will answer the intended question:
How do I un-stroke a path?
A bitmap is not a vector graphic. You cannot simply remove or modify things you've drawn previously. By drawing on a canvas you modify the pixel color values of its image data. If you need to undo things you have to maintain a separate data structure with the relevant data yourself.
For example you could create a copy of the image data before drawing something. Then you could return to this snapshot afterwards. HTMLCanvasElement#toDataURL returns the complete image as an url which you can use as the src of an image. Later you can draw this image on the canvas to revert all subsequent changes. HTMLCanvasElement#toBlob does about the same but it returns a blob. This might consume less memory but it's a little more inconvenient to use. The most convenient method is CanvasRenderingContext2D#getImageData. You can even use it to copy only a small part of the image. This is useful if you have a big canvas but only modify pixels in a small region.
Another way to make modifications undoable is by maintaining a detailed list of your steps. For example whenever you draw an arc you store the exact parameters as one entry in the list. steps.push({type: 'stroke', style: 'rgb(0,0,0)', shapes: [{type: 'arc', x: 600, y: 500, radius: radius, from: 0.5 * Math.PI, to: 2 * Math.PI}]}) You can remove, rearrange or modify the elements in this list any way you like and have all necessary information to draw the resulting image from scratch. Basically you've implemented just another vector graphic library.

Adding image to moving and colliding circles

I currently have a bunch of balls(circles) that are bouncing and colliding with eachother inside a box.
Right now they are currently plain green balls. But I want to use a image for this circles.
How can I do this? Here is my render function.
function render() {
var ball;
context.fillStyle = "#008800";
for (var i = 0; i <balls.length; i++) {
ball = balls[i];
ball.x = ball.nextx;
ball.y = ball.nexty;
context.beginPath();
context.arc(ball.x,ball.y,ball.radius,0,Math.PI*2,true);
context.closePath();
context.fill();
}
Any ideas? Is it possible? If not, is there any other methods to achieve bouncing and colliding balls with images?
You can do this three ways:
Method 1 - use pattern to fill the ball
Define the image you want to use as a pattern:
/// create a pattern
var pattern = context.createPattern(img, 'repeat');
Now you can use the pattern as a fill style instead of the green color:
context.fillStyle = pattern;
However, as patterns are always drawn with basis at the coordinate's origo (default 0, 0) you will need to to translate for each move. Luckily not that much extra code:
/// to move pattern where the ball is
context.translate(x, y);
context.beginPath();
/// and we can utilize that for the ball as well so we draw at 0,0
context.arc(0, 0, radius, 0, Math.PI * 2);
context.closePath();
context.fillStyle = pattern;
context.fill();
Now, depending on how you want the move the balls around you may or may not need to translate back for each time.
Here's an online demo showing this approach.
Method 2 - Clip the image to fit the ball with Path clipping
Instead of pattern we can use drawImage to draw the image. However, the problem is that this will draw a square so unless you are creating a ball shaped image which fits on top of your ball with transparent pixels.
You can therefor use clipping to achieve the same as with the pattern method:
Here only a few more lines are needed:
/// define the ball (we will use its path for clipping)
context.beginPath();
context.arc(x, y, radius, 0, Math.PI * 2);
context.closePath();
/// as we need to remove clip we need to save current satte
context.save();
/// uses current Path to clip the canvas
context.clip();
/// draw the ball which now will be clipped
context.drawImage(img, x - radius, y - radius);
/// remove clipping
context.restore();
Here's an online demo of this approach.
Method 3 - Pre-clip the ball as an image
Make a ball in Photoshop or some similar programs and just draw this as an image instead of drawing an arc which you then fill.
You simply draw the ball instead of creating a Path with arc:
drawImage(ballImage, x - radius, y -radius);
If you need to draw in different sizes simply extend the call to:
drawImage(ballImage, x - radius, y - radius, radius, radius);
If performance is critical this is the way to go as this has better performance than the other two approaches but isn't as flexible as them.
If you need a balance between flexibility and performance the clipping approach appear to be the optimal one (this may vary from browser to browser so test).
Here's an online demo with drawImage
Checkout the drawImage function. This allows you to draw an image at a coordinate point on the canvas. It takes an Image instance as it's first parameter and various other position and cropping values. To quote from the MDN page linked above:
drawImage(image, dx, dy, dw, dh, sx, sy, sw, sh)
image
An element to draw into the context; the specification permits any image element (that is, <img>, <canvas>, and <video>). Some browsers, including Firefox, let you use any arbitrary element.
dx The X coordinate in the destination canvas at which to place the top-left corner of the source image.
dy The Y coordinate in the destination canvas at which to place the top-left corner of the source image.
dw The width to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not
scaled in width when drawn.
dh The height to draw the image in the destination canvas. This allows scaling of the drawn image. If not specified, the image is not
scaled in height when drawn.
sx The X coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sy The Y coordinate of the top left corner of the sub-rectangle of the source image to draw into the destination context.
sw The width of the sub-rectangle of the source image to draw into the destination context. If not specified, the entire rectangle from
the coordinates specified by sx and sy to the bottom-right corner of
the image is used. If you specify a negative value, the image is
flipped horizontally when drawn.
sh The height of the sub-rectangle of the source image to draw into the destination context. If you specify a negative value, the
image is flipped vertically when drawn.
In your case, you would replace the path drawing function with drawImage.
var img = new Image;
img.onload = function() {
//You have to make sure the image is loaded first
//Begin rendering!
render();
};
img.src = "path/to/your/ball/img.png"
function render() {
var ball;
context.fillStyle = "#008800";
for (var i = 0; i <balls.length; i++) {
ball = balls[i];
ball.x = ball.nextx;
ball.y = ball.nexty;
context.drawImage(img, ball.x - (img.width/2), ball.y - (img.height/2)); //Make x, y the centerpoint
}
}

Division / sub-canvas

I have few coordinates in an XML file. They are lines, circles and arcs. I am reading them in a data structure and then trying to plot them on a canvas. What i am trying to figure out is how to divide the canvas into sub canvases. e.g suppose my canvas is
<canvas id="myCanvas" width="800" height="600" role="img">
Your browser does not support the canvas element.
</canvas>
What I am trying to achieve is how to make an imaginary window of width and height of 200px starting from say x1=200px on canvas and y1=250. And draw the image I have only in that box.
I have managed to scale down the image based on the imaginary box but cannot get around the concept of how to draw only in that imaginary box. The points are randomly distributed.
There are other ways to achieve this but the one you'll probably find most useful in this context is to use translation and a clip mask:
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
/// for simplicity, save current settings
ctx.save();
/// move coordinate system to the upper left corner of isolated region
ctx.translate(offsetX, offsetY);
/// create a clipping mask by using a simple rectangle
ctx.beginPath();
ctx.rect(0, 0, width, height);
/// define the last path (rectangle) as clipping mask
ctx.clip();
/// ... draw other things into this region from offset 0...
ctx.restore(); /// done and back to full canvas
By moving the whole coordinate system to the upper left corner of your region you can use offsets relative to the new isolated area. By adding a clip mask anything drawn outside the region will be clipped.
You will need to do this for each region one by one.
Another way is to add an offset to all drawing points. For example:
ctx.lineTo(x + offsetX, y + offsetY);
where offsetX/Y is the upper left corner of the region.
However, it will get more complicated if you need clipping - not a huge issue with images as you can define the destination region but for lines and and other path operation you will need to clip yourself by using interpolation etc.
Here is a live demo demonstrating this:
Fiddle (updated link)
The demo sets up a canvas and context and then fills the whole with a red color.
Then if sets the clipping and mask and translate it.
We now have a "virtual canvas" and the other graphic is intact
We now fill the region with the same fill operation but with blue. Now we can see only this regions is filled even the size is outside the actual region
Then we remove the clip and draw a line as evidence that we are now back in full mode

HTML5/Javascript - How to get the coordinates of a shape/image on the canvas?

Say I drew a rectangle on the canvas. Surely there is some sort of built in method to get the XY coordinates, and dimensions of that rectangle? But after some googling I came up with nothing. And just to clarify, I am not talking about the coordinates of the canvas element itself, but rather a shape/image that is drawn unto the canvas.
Any help is appreciated.
If you're talking about a 2D canvas drawing, then the drawing maps 1:1 with screen coordinates, so it is just location of <canvas> + location of the drawing.
To clarify, drawing on a <canvas> basically just changes the pixels of the canvas - after you draw to it, you can't reference the drawn object the same way you can reference an html element.
Canvas is 2D table (Array) of numbers (= pixels = colors). When drawing into canvas, you are just editing this table. When you draw into canvas (= change numbers in table), what should be the coordinates of your adjustment?
If you are drawing rectangles only and you can define the coordinates for your rectangle, you must know your coordinates inside a program, because you have just drawn it.
If you want your image to be separated into some "objects" (shapes), you should use SVG.
Basically, you should be using canvas as a means to output graphics to the screen and the rest of your logic goes straight into the JavaScript that powers your game/application. The best way to go about making something like this is to create objects and assign properties to them; in its simplest form that can look like this:
function Player(x, y)
{
this.x = x;
this.y = y;
}
var examplePlayerObject = new Player(20, 20);
By extending this object via prototyping you can create multiple copies of an object that has the exact same functions; such as draw. Drawing the player in this instance could just be a red square that is 20px*20px.
Player.prototype.draw = function()
{
context.clearRect(0, 0, canvas.width, canvas.height);
context.fillStyle = 'red';
context.fillRect(this.x, this.y, 20, 20);
}
Then, you should have an update step with some means of clearing what is on the screen and redrawing the parts which have changed.
function animationStep()
{
examplePlayerObject.x++;
examplePlayerObject.y++;
examplePlayerObject.draw();
}
This animation step should run each frame; look into requestAnimationFrame for smooth animation. Paul Irish has a good shim for older browsers. Add in requestAnimationFrame(animationStep) at the end of that function and you will have a red square moving slowly across the screen. Good luck!

When I draw my SVG contents to a canvas, the SVG is cropped

I have a bunch of lines of SVG text that I need to draw to a canvas. I'm converting my SVG object into an SVG data URI, applying that to an image's source, and then drawing that image to the canvas, but it's clipping the text after a certain width and height for some reason.
I know the issue isn't the canvas size because I'm also drawing other images to the canvas first (that're way wider and taller than the text) with no problems. Another weird thing is, if I take the image and append it to the body, it comes out perfectly.
var imageText = new Image();
imageText.src = "data:image/svg+xml;base64," + btoa($("#text_container").html());
imageText.onload = function() { context.drawImage(imageText, 0, 0); };
#text_container is my DIV that holds all the SVG code.
EDIT: To give more detail, here's a comment I wrote below: I'm building a JS application that lets users create a custom football. You can change different colors and features of the ball and text, so it boils down to several DIVs with some SVG text (because the text goes along an arc'd path). I can take the background-images of the DIVs and draw it onto the canvas just fine, to create the football. I have problems when I try to draw the text onto the canvas because it's being cropped. Then I'm going to take that canvas element and turn it into a PNG for the user to save.
I moved the text up and to the left more so you could see the cropping better. The ball draws just fine, as you can see. http://i.imgur.com/Sngu4.png
I had this exact same problem, but I think I just found the solution.
It's not enough just to set a width and a height on your SVG element. Apparently, you also need to set the viewBox:
<svg width="720" height="400" viewBox="0 0 720 400"></svg>
This should render the image correctly on the canvas. :)
A shot in the dark.... does drawImage() have some sort of size parameters you can set? Maybe it has a default that it's drawing to in size, then clipping the rest. Just a thought...
It could also be that, since your image is dynamically created, there's some sort of image size parameters that are missing that would normally be included in say a .jpg, which the drawImage() function could be looking for.
Assuming that context is your canvas' RenderingContext ("2D"), you should include the "destiny width" and "destiny height" parameters on your context.drawImage() function:
context.drawImage(image, dx, dy, dw, dh)
If myCanvas is the id of your canvas object (and $ is jQuery's function), you can call:
var dw = $('myCanvas').width();
var dh = $('myCanvas').height();
context.drawImage(image, 0, 0, dw, dh);
This will scale the image in order to fit the whole canvas. My advice is to first "see" what the svg image is (i.e. add it to the body and measure in which coordinates the text is: sx, sy, sw and sh, in the link above), because you probably has to crop it "on purpose" in order to position it where you want:
context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)

Categories