Is there any trick to determine if user clicks on given element rendered in canvas? For example I'm displaying rhombus from .png file with transparent background and i want to know if user click inside or outside that figure (like mouse-element collision).
There is no concept of individual elements in a canvas - it is simply just an area that you're drawing pixels onto. SVG on the other hand is made up of elements which you can then bind events to. However there are a few approaches you can take to add click events to canvas:
Position an html element that overlays the area on the canvas you want to be clickable. A for a rectangular area or an image map for something more irregular.
Use separate canvases for each element that you want to be clickable.
CAKE - I haven't used this myself, but it's description is "SVG sans the XML". This may cover your needs. Demos here http://glimr.rubyforge.org/cake/canvas.html#EditableCurve
One idea is to draw the image to a temporary canvas, then use getImageDate() to receive data for the pixel you are interested in, and check if its alpha value is 0 ( = transparent).
The following is a sketch of a solution. It is assumed that...
x and y are the coordinates of the mouse click event
you are looping over gameObjects, the current object being stored in the variable gameObject
the game object has been initialized with an image, x and y coordinates
The following code would then check whether the click was on a transparent area:
var tempCanvas = document.createElement('canvas');
if (tempCanvas.getContext) {
tempContext = tempCanvas.getContext('2d');
}
tempContext.drawImage(gameObject.img, 0, 0);
var imgd = tempContext.getImageData(x - gameObject.x, y - gameObject.y, 1, 1);
var pix = imgd.data;
if (pix[3] == 0) {
// user clicked on transparent part of the image!
}
Note: This is probably quite inefficient. I'm sure someone can come up with a better solution.
I have solve this problem using kintech.js, tutorials and examples can be found: http://www.html5canvastutorials.com/kineticjs/html5-canvas-drag-and-drop-tutorial/
Related
I'm two days into js,html and css programming. So very newbie!
Following and building upon this TUTORIAL
Q1: How can I add this male into the background (see figuere 1.) and prohibit any strokes outside of the borders?
Adding image to background was no biggy!
function make_base()
{
base_image = new Image();
base_image.src = 'img/bmapFront.gif';
base_image.onload = function(){
context.drawImage(base_image, 0,0);
}
}
There is a context.clip function, not sure if I can use pixel form as clipping path. Making tons of "image substractions" isn't the best way.
Any suggestions
Edit:
Did the Job for me: VeryHelpful
var frontPath = new Path2D ("M 133.41,17.00 C 141.37,2.41 160.66, !VERY LONG! ")
context.clip(frontPath);
Messy strokes!
He should look like this. Then I want to save him.
Although there is such a thing as ctx.clip(), this is sometimes not what's wanted as it's impractical to use a path.
The solution that I like involves creating a virtual empty canvas onto which you draw your pixel image. Through various manipulations, like using ctx.getImageData and similar to make sure you only get one kind of color or apply other filters only once, you can obtain an image that seems to be empty (alpha of 0, mostly) in the places where you want to clip other images or paths out.
At that point, you'd use ctx.globalCompositeOperation = 'source-atop', or pick another one you might want to use from mdn's list of globalCompositeOperations.
At this point, you can just draw this virtual canvas image onto the main canvas
If you click Run code snippet in this link, it shows a cool usage of <canvas> where you can "cut-out" part of the image (just drag your mouse on the image to "cut"). I'm just curious if there is any way to save the resulting "cut-out" part of the image, as a transparent PNG (i.e. everything that is white in the canvas would be transparent).
If anyone can point me in the right direction (or tell me it's not doable), I'd appreciate it.
Yes, there is a way. Use canvas context.getImageData to get image raw data-array. Do with it(raw data) what you need(make transparent any pixel you need), and then use context.putImageData to render data on canvas. Then use var data = canvas.toDataURL("image/png") to get image data. And then you can do so: image.src = data;
Use this link https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/getImageData for more info
Here's a quick tour showing how to crop & save a user-dragged cutout of an image:
Draw the image on the canvas.
Listen to mouse events and let the user define the region they want to cut out by continuously connecting new lines to the current mouse position.
Save every mouse point from #2 in an array.
When the user has finished defining their cutout region:
Clear the canvas.
Draw and fill the cutout area using the saved points in the arry.
Set context.globalCompositeOperation='source-in'. This mode will cause any new drawings to appear only where the newly drawn pixels and the existing pixels overlap and every thing else is made transparent. In common terms: New pixels will be "clipped" into the user defined cutout and new pixels will not appear outside the cutout.
Redraw the image.
The result is the second drawing of the image will appear only inside the user defined cutout. Everything else will be transparent.
Finally, you can use var url=canvasElement.toDataURL to save the cropped canvas image into a .png dataURL. If you then want an actual image from this dataURL you can var img=new Image() and set the img.src=url.
I've been struggling to get this code working. Basically, I want the user to be able to click anywhere inside of the canvas, and the coordinates at the clicked point will be where the rectangle gets drawn. However, the code I have places the rectangles at totally unexpected points along the canvas. I checked the values in Firebug and they seemed to be accurate based on where I clicked inside the canvas, so I'm not sure why the rectangles are not getting drawn at the correct points. Maybe there is some other mistake going on that I am not seeing though, so any help or input would be appreciated. I've posted the relevant code below.
I should also note that the canvas element is inside the div with id='container'.
$('#container').click(function (e) {
var offset=$(this).offset();
var x=(e.pageX - offset.left);
var y=(e.pageY - offset.top);
ctx.fillStyle='#FF0000'; //color red
ctx.fillRect(x,y,10,10); //draw 10 x 10 rectangle starting at x,y
});
pageX/Y gets the x/y coordinate of the page (think 100, 200). Let's say your canvas is positioned at (100,100) on the page. When you're graphing the point, you're saying "Graph a point at 100,200 IN RELATION TO THE CANVAS. That would mean you are trying to graph a point at (200,300) instead of (100,200) linke you want. You need to get your x/y in relation to the canvas, like so:
var x = event.offsetX !== undefined ? event.offsetX : event.layerX;
var y = event.offsetY !== undefined ? event.offsetY : event.layerY;
If you only want to add a click event on the canvas then it's better to use
$("#myCanvas").click(function(e){
});
If you use myCanvas instead of container then $(this) would refer to the canvas and you get the position of the mouse relative to the canvas.
It is because you use the container div that the variable offset is wrong.
I have used the Canvas code provided elsewhere on this site to create a screen where I have several overlapping transparent pngs with the non-transparent parts being irregular shapes. I can get the color under the cursor and that is great. But my shapes are all the same color and I need a way to get the ID of the particular shape as well so I know which one was clicked on. Imagine a map made of overlapping pngs fo reach country and you want to detect which country was clicked on. From what I can tell, id detection only applies to rectangular regions. Any suggestions?
$('#myCanvas').click(function(e){
var position = findPos(this);
var x = e.pageX - position.x;
var y = e.pageY - position.y;
var coordinate = "x=" + x + ", y=" + y;
var canvas = this.getContext('2d');
var p = canvas.getImageData(x, y, 1, 1).data;
var hex = "#" + ("000000" + rgbToHex(p[0], p[1], p[2])).slice(-6);
alert(hex);
});
This code gets and displays the color (findPos and rgbToHex are separate functions left off for clarity). I need an id! Help!
Even with transparency, the images are all rectangles. You then know which images are at a clicked point by rectangle intersection - check your array of images and their x,y points with width,height for point intersection. You then come up with an array of possibly clicked images. If there's only one in the list, you are done.
The images have an implied Z-order of the reverse order in which you wrote them, meaning, an image is overwritten by the next image written which overlaps it. You can use that to know which order to try them in for hit-testing if more than one is at the point clicked. The only trick is to detect if an image pixel is transparent or not.
To detect transparency for a pixel point clicked in a single image, you could keep a second hidden canvas element. Clear it, then write the target image to it at the same position, and use the same code to see if the clicked pixel within the second canvas is the transparent color. If it is, repeat this process with the next image in the Z-order until you get the image where a non-transparent pixel was clicked.
A small but important optimization is to check the color clicked first, and if it's the transparent color you already know none of the images were clicked on a non-transparent point.
I'm working on a script to do several things. In a nutshell, here's what it needs to do:
Read the coordinates from a page and be able to pop up a box within a specific region.
The pop up box needs to be able to follow the mouse around.
I need to be able to modify the box to look however I want (I was thinking a div container that is set to display:hidden, and then the JS sets the display to block when your mouse is in the specified region).
I need to be able to modify it easily (aka, add and subtract objects and coordinate sets)
I was originally using HTML maps (), and that worked great, until I resized my browser, and the div that I had following the mouse no longer lined up correctly. Something about the offset not working correctly, and I couldn't get it to work correctly, so I switched to an HTML canvas.
And now I've got the coordinates in the canvas correctly, I just can't figure out how to get something to pop up when the mouse is inside of a certain section. Here's my current code:
function drawLines(numbers, color){
//poly [x,y, x,y, x,y.....];
var poly=numbers;
context.fillStyle = color;
context.beginPath();
context.moveTo(poly[0], poly[1]);
for( item=2 ; item < poly.length-1 ; item+=2 )
{context.lineTo( poly[item] , poly[item+1] )};
context.closePath();
context.fill();
}
I've got each region inside of an array, which I then pass to the function one by one. The color was a test, and I can easily get each region to show up as a specified color, but that doesn't solve my problem. Any ideas? Thanks!
Seems strange to jump to canvas over a style issue, but ignoring that...
You could bind mousemove events on the canvas element and then do hit tests on your region to see if the mouse is inside the region.
Doing the hit test efficiently might be tricky depending on the number of regions your testing, but it's definitely doable.
The canvas is just like any other block level element, so the same events apply and are bound in the same way.
Here's one example of mouse events interacting with canvas. In this example, the events are bound to the document, but similar ideas apply.
http://dev.opera.com/articles/view/blob-sallad-canvas-tag-and-javascrip/