How to accurately draw rectangles on HTML5 canvas? - javascript

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.

Related

Why my image is teleporting when I'm hovering the image by my mouse cursor inside the div

So basically I've seen a lot of advance animation websites. And I tried to create a image wherein it follows the images as I move my mouse cursor along with div coordinates.
Basically the code is like this in my codepen.
https://codepen.io/myth-vince/pen/PoQJOXj
When you try to move the cursor into the image..it will just like teleport on the top left because I think that is the constant rect height ord width of the image.
If anyone can help me with this..It will be a big thanks. I've created some advance animation like this but never met this before that just teleport suddenly.
I believe it has something with this
var rect = e.target.getBoundingClientRect();
console.log(rect)
var x = e.clientX - rect.left; //x position within the element.
var y = e.clientY - rect.top; //y position within the element.
Or maybe the SCSS but I don't know where because everything seems fine..but I think the only really problem here is because when I try to make it also center the image in the mousecursor it will just adjust itself and will not align in center of mousecursor cause it is avoiding it to teleport.
EDIT
For more information..
the part of mouseover and mousemove the mousemove will only starts when the mouse is hovering the div so it the image will start to move out.
Now for the second I need to get the e.clientX and e.clientY so that it could get the where the part of div is. And as rectX and rectY is the getting the height and width part of it
Show DIV at mouse cursor on hover of span
you can see it here the link.
and where did I get the delaying the motion of images is here
https://stackoverflow.com/questions/9136261/how-to-make-a-setinterval-stop-after-some-time-or-after-a-number-of-actions#:~:text=To%20stop%20it%20after%20running,reached%20that%20number%20clear%20it.
var rect = e.target.getBoundingClientRect();
There's your problem.
Like most other event types, the mousemove event bubbles up through the DOM.
When you put the cursor over one of those images - then e.target is not the box any more, but that particular image. So you are not working with the getBoundingClientRect data relating to your box now, but to the particular image.
As soon as you make this
var rect = box.getBoundingClientRect();
instead, the problem is gone.

Canvas drawing using mouse coords issue?

I'm drawing to the canvas using the x/y coords of the mouse, but the line that I'm drawing always draws off a little bit, try drawing on here: http://zachrip.net/widgets/onlineedit/index.html (top left) for an example of what I mean. There is no offset so I do not account for it, so I don't know what the issue is?
The problem here is that you are setting the Canvas Element Size through your CSS, but you do not set the Drawing Surface Size.
The default size of the Drawing Surface is 300px by 150px. Since you do not set it, but set the Element Size, the browser scales the drawing surface size to fit the element. The x and y co-ordinates you get through the mouse event correspond to the Element Size, and not the actual Drawing Surface Size. Which is why you get the offset.
Now, the fiddle that I posted earlier merely had you set the size of Drawing Surface, instead of the Element. And that works, but if you'd rather have different Element and Drawing Surface sizes, then you can also do
function scaleCoords(x, y) {
x = x * DrawingSurfaceSize.width/ElementSize.width;
y = y * DrawingSurfaceSize.height/ElementSize.height;
return {x: x, y: y};
}
Example for second method.

What do the Raphael object attributes "x" and "y" mean?

I expected this to be 100% a no-brainer, but as it turns out, I cannot figure out what the x and y attributes of an svg created and manipulated with Raphael.js mean. I assumed they were the coordinates of the top-left corner of the object in relation to the canvas, but now I'm not so sure.
After creating a canvas (var paper = new Raphael(container,width,height)) and adding an image or rectangle to it, for example, if I retrieve the "x" and "y" attributes using the attr method (e.g. object.attr("x")), they're both at 0. However, if I rotate that object and then retrieve the values of x and y again, the values don't reflect the position of the top-left corner of my object in relation to the canvas anymore.
Can someone please explain this to me?
I fear #afaf12's answer complacently goes only half the distance. He's absolutely correct that transformation logic occurs after the fundamental attributes of a given element and doesn't effect them, but it is certainly possible to retrieve the x and y of that element after transformations are applied. You'll want to use the getBBox method, like this:
var bbox = elem.getBBox();
console.log("Transformed coordinates of element are %s,%s", bbox.x, bbox.y );
Please note that there is some trickiness involved -- this returns the bounding box of the element, which is often a superset of the space occupied by the element -- so there's no guarantee that the returned point will be IN the element.
Another alternative occurs if you're using paths -- path.getPointAtLength also works with transformed coordinates, so you can get the x,y offset of the beginning of a path by calling
var coord = elem.getPointAtLength(0);
console.log("Transformed coordinates of path are %s,%s", coord.x, coord.y );
Rotation is a transformation and it does not change x and y of the object.
http://raphaeljs.com/reference.html#Element.transform

Is HTML5 hit detection possible?

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.

Click on given element in canvas

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/

Categories

Resources