Tile Map Coordinates - javascript

I am have now this code: http://jsfiddle.net/DK67k/2/
In here is 2D tile map and when you click on tile you get coordinates on alert.
But for get precises coordinate you need click on top left tile(tiles is 16x16) and if I click on bottom right tile I am get second tile coordinates.
Maybe anyone have idea how to fix this?

The canvas point (0,0) is at mouse coords (10,10), i think is due to parent of canvas has a padding area.
function mouseCheck(e) {
x = e.pageX-10;
y = e.pageY-10;
mouseX = Math.floor(x / 16);
mouseY = Math.floor(y / 16);
}

Blaus' answer is correct.
Though you might want to subtract the canvas offset left- and top position to make your canvas element available for dynamic positioning, and not relative to the 10px padding.
function mouseCheck(e) {
var x = e.pageX - canvas.offsetLeft;
var y = e.pageY - canvas.offsetTop;
mouseX = Math.floor(x / 16);
mouseY = Math.floor(y / 16);
}

Related

Javascript | SVG object jumps after rotation

I'm trying to rotate an SVG object (a rectangle, which is also draggable using x and y attributes) via rotate(angle x y), x and y is the midpoint of the object which I calculate with this function:
getMidPoint(x, y, width, height, angle, oldMidPointX, oldMidPointY, drawPoint) {
let angleRad = angle * Math.PI / 180;
let cosa = Math.cos(angleRad);
let sina = Math.sin(angleRad);
// Find new x/y values after rotation
let tempX = x - oldMidPointX;
let tempY = y - oldMidPointY;
let xAfterRotation = (tempX * cosa) - (tempY * sina);
let yAfterRotation = (tempX * sina) + (tempY * cosa);
drawPoint(x, y, "aqua");
// translate back
x = xAfterRotation + oldMidPointX;
y = yAfterRotation + oldMidPointY;
drawPoint(x, y, "green");
let wp = width / 2;
let hp = height / 2;
let px = x + (wp * cosa) - (hp * sina);
let py = y + (wp * sina) + (hp * cosa);
drawPoint(x, y, "red");
return {
px: px,
py: py };
}
Consecutive rotations are no problem. The jumping occurs if the object gets rotated, resized (for example increasing the width of the object) and then rotated again. While the function above gives the correct midpoint, the object first jumps and rotates around the the calculated point.
I don't know what I'm missing here, maybe someone can spot the mistake or give me some ideas to try out.
EDIT
Here is an image to showcase my problem.
1: Starting position; red dot marks the midpoint of the object and green dot is the position used for calculating the midpoint.
2: Rotating the object with no problem.
3: Resizing the object.
4: Calculating new midpoint on start; blue dot marks x and y coordinates of the object.
5: Rotating the second time, "jumping" occurs.
6-8: The object rotates (the same rotation started at previous step) around the midpoint but with an offset.
9: 360° rotation puts the top left corner of the object to it's x/y position
Maybe someone can spot the mistake now.

Innacurate Y Coordinates in Canvas

I'm testing getting the mouse position in a canvas in Javascript.
I decided to try something: I wanted to draw a rectangle at the position the mouse clicked on, but when I click anywhere on my canvas, the rectangle does draw at the X position of the cursor, but not on the Y.
I then went to see what the problem was, so I made it so that the coordinates of the mouse on the canvas were visible, and I got interesting results.
In short: it's telling my cursor's Y position was 0, even though it wasn't at the top of the canvas:
ctx.canvas.addEventListener('mousemove', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
var status = document.getElementById('status');
status.innerHTML = mouseX + ' | ' + mouseY;
});
ctx.canvas.addEventListener('click', function(event) {
var mouseX = event.clientX - ctx.canvas.offsetLeft;
var mouseY = event.clientY - ctx.canvas.offsetTop;
item.drawItem(mouseX, mouseY);
});
Can anyone tell me why is this happening?
Use canvas.getBoundingClientRect().left instead of ctx.canvas.offsetLeft and canvas.getBoundingClientRect().top instead of ctx.canvas.offsetTop. See if this works?

How do I check if a mouse click is inside a rotated text on the HTML5 Canvas in JavaScript?

I have drawn a text on the canvas in coordinates X, Y and saved them. I have a simple method that checks if a mouse click has happened inside the text boundaries. The problem is when I rotate the text 45 Degree I cannot check whether a mouse click has happened within the rotated text or not.
In short, how can I check whether a mouse click is inside a rotated text or shape?
Create a rect object which is rotated at the same angle as the text, but not drawn.
Then use:
// set transforms here.
// add rect representing text region:
ctx.beginPath();
ctx.rect(x, y, w, h); // region for text
if (ctx.isPointInPath(mx, my)) {
// we clicked inside the region
}
ctx.setTransform(1,0,0,1,0,0); // reset transforms after test
Demo:
var canvas = document.querySelector("canvas"),
ctx = canvas.getContext("2d"),
txt = "ROTATED TEXT", tw, region;
// transform and draw some rotated text:
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.font = "32px sans-serif";
ctx.translate(150, 75);
ctx.rotate(0.33);
ctx.translate(-150, -75);
ctx.fillText(txt, 150, 75);
tw = ctx.measureText(txt).width;
// define a region for text:
region = {x: 150 - tw*0.5, y: 75 - 16, w: tw, h:32}; // approx. text region
// function to check if mouse x/y is inside (transformed) region
function isInText(region, x, y) {
ctx.beginPath();
ctx.rect(region.x, region.y, region.w, region.h);
return ctx.isPointInPath(x, y);
}
// test for demo
canvas.onmousemove = function(e) {
var rect = canvas.getBoundingClientRect(),
x = e.clientX - rect.left,
y = e.clientY - rect.top;
// just to visualize:
ctx.clearRect(0,0,300,150);
ctx.fillStyle = isInText(region, x, y) ? "red" : "black";
ctx.fillText(txt, 150, 75);
};
<canvas></canvas>
DO NOT USE BELOW CODE DIRECTLY. HERE I'M TRYING TO EXPLAIN ONLY THE LOGIC THAT HOW YOU CAN PROCEED WITH THIS KIND OF PROBLEMS. YOU MAY HAVE TO WRITE CODE ACCORDING TO YOUR PROBLEM, OR EXTEND THIS SOLUTION TO FIT INTO YOUR PROBLEM
This is more of the mathematical problem where you have to find whether a point is inside rotated Rectangle or not(same as what #user1693593 said)
You can find a rectangle that is covering text(rect(x1: text.x1, y1: text.y1, x2: text.x2, y2: text.y2) assuming (text.x1, text.y1) denotes top-left corner of text.
Now rotate the rect about it's centre by theta angle and find out x1,y1,x2,y2:
Assume all angle calculation will happen in +ve angles.
if theta < 0 then theta = (360 - abs(theta))
Now calculate angle between centre point and point(x2, y2)(Angle from centre to any corner of rect will be same, we are calculating for (x2, y2) because it will give us positive angle)
var width = (x2-x1);
var height = (y2-y1)
var hypotenuse = Math.pow(width*width + height*height, 0.5);
var innerAngle = Math.acos(x2 - x2 / hypotenuse);
Now calculate final angle of corners from centre
(x1, y1), angle((Math.PI + baseAngle) + angle) %(Math.PI*2)
(x2, y1), angle((Math.PI*2) - baseAngle + angle) % (Math.PI*2)}
(x1, y2), angle((Math.PI - baseAngle) + angle) % (Math.PI*2)}
(x2, y2), angle(baseAngle + angle) % (Math.PI*2)}
Now find out rotated Points of rectangle:
point.x = centre.x + (hypotenuse * Math.cos(point.angle));
point.y = centre.y + (hypotenuse * Math.sin(point.angle));
After rotating points It may happen that their order get changed, to make sure the correct order sort them based on x-axis, if two points have same x-axis then sort them based on y-axis (use any sorting)
Now we got sorted points. Name them based on their position p0, p1, p2, p3
Find new boundary of rotated rect from these points, find boundary in x direction and y direction:
var boundary_x1 = ( (p1.x - p0.x) / (p1.y - p0.y) ) * (mousePos.y - p0.y) + p0.x;
var boundary_x2 = ( (p3.x - p2.x) / (p3.y - p2.y) ) * (mousePos.y - p2.y) + p2.x;
var boundary_y1 = ( (p2.y - p0.y) / (p2.x - p0.x)) * (mousePos.x - p0.x) + p0.y;
var boundary_y2 = ( (p3.y - p1.y) / (p3.x - p1.x)) * (mousePos.x - p1.x) + p1.y;
after getting boundary points in x and y direction we can easily put mid point condition and can find whether a point(mousepoint) is clicked in rect or not:
var clickedInside = (mousePos.x > boundary_x1 && mousePos.x < boundary_x2) && (mousePos.y > boundary_y1 && mousePos.y < boundary_y2);
if clickedInside is true then mouseclick happened inside rect

how to calculate the area of painted region?

I paint freehand strokes on my canvas with a code like below. I need to check how much of the canvas is covered with strokes. What is a good way to check that? The only thing I can think of is to count the number of pixels that have the specific color on mouse up event. But it is lame because it is slow...
Any help?
$(document).ready(function(){
var draw = false;
var x_prev = null, y_prev = null;
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
canvas.mousedown(function(e){
draw = true;
x_prev = e.pageX - this.offsetLeft;
y_prev = e.pageY - this.offsetTop;
});
window.mouseup(function(){draw=false});
canvas.mousemove(function(e){
if(draw){
context.beginPath();
context.moveTo(e.pageX - this.offsetLeft, e.pageY - this.offsetTop);
context.lineTo(x_prev, y_prev);
context.stroke();
context.closePath();
x_prev = e.pageX - this.offsetLeft;
y_prev = e.pageY - this.offsetTop;
}
});
Computers are fast. It seems plenty fast to me to re-count the number of pixels over a particular alpha each frame when drawing. Test it yourself here: http://jsfiddle.net/ZC8cB/3/
Relevant code:
var w = canvas.attr('width'),
h = canvas.attr('height'),
area = w * h;
function updateArea() {
var data = context.getImageData(0, 0, w, h).data;
for (var ct=0, i=3, len=data.length; i<len; i+=4) if (data[i]>50) ct++;
$fill.html(ct);
$pct.html((100 * ct / area).toFixed(2));
}
If this is really too slow, you could choose to update the area every other mousemove, every third mousemove, etc. or on an interval timer. For example, here's a very-slightly-modified version that only updates every tenth mousemove: http://jsfiddle.net/ZC8cB/4/
And if a single frame of counting is too slow—because you have a slow computer or huge canvas or both—then you can fetch the ImageData in one frame and each update frame count a particular portion of the pixels.
Quantify the area to line width sized squares and count the number of unique squares encountered during draw.
var thickness = 4
var height = ..
var width = ..
var drawn = []
var covered = 0;
canvas.mousemove(function(e) {
var x = e.pageX - this.ofsetLeft;
var y = e.pageY - this.offsetTop;
x = parseInt( x / width ) * ( width / thickness )
y = parseInt( y / height ) * ( height / thickness )
id = x + y * parseInt(thickness / width)
if ( !drawn[ id ] ) {
drawn[ id ] = 1;
covered++;
}
}
You can get drawn area in percents by dividing the covered squares by number of total squares
var a = covered / ((width / thickness) * (height / thickness))

Mouse position within rotated rectangle in HTML5 Canvas

Rotation of rectangles within an html5 canvas is being stored in radians. In order to find whether subsequent mouse clicks are within any given rectangle, I am translating the mouse x and y to the origin of rotation for the rectangle, applying the reverse of the rotation to the mouse coordinates, and then translating the mouse coordinates back.
This simply isn't working - mouse coordinates are not being transformed as expected (that is, not within the bounds of the original rectangle when clicking within the visible bounds of the rotated rectangle), and testing against the rectangle's bounds is failing. Detection of mouse clicks works only within the centre-most area of the rectangle. Please see the code snippet below and tell me if you can see what's wrong here.
// Our origin of rotation is the center of the rectangle
// Our rectangle has its upper-left corner defined by x,y, its width
// defined in w, height in h, and rotation(in radians) in r.
var originX = this.x + this.w/2, originY = this.y + this.h/2, r = -this.r;
// Perform origin translation
mouseX -= originX, mouseY -= originY;
// Rotate mouse coordinates by opposite of rectangle rotation
mouseX = mouseX * Math.cos(r) - mouseY * Math.sin(r);
mouseY = mouseY * Math.cos(r) + mouseX * Math.sin(r);
// Reverse translation
mouseX += originX, mouseY += originY;
// Bounds Check
if ((this.x <= mouseX) && (this.x + this.w >= mouseX) && (this.y <= mouseY) && (this.y + this.h >= mouseY)){
return true;
}
After some further work, came to the following solution, which I thought I'd transcribe here for anyone who might need it in the future:
// translate mouse point values to origin
var dx = mouseX - originX, dy = mouseY - originY;
// distance between the point and the center of the rectangle
var h1 = Math.sqrt(dx*dx + dy*dy);
var currA = Math.atan2(dy,dx);
// Angle of point rotated around origin of rectangle in opposition
var newA = currA - this.r;
// New position of mouse point when rotated
var x2 = Math.cos(newA) * h1;
var y2 = Math.sin(newA) * h1;
// Check relative to center of rectangle
if (x2 > -0.5 * this.w && x2 < 0.5 * this.w && y2 > -0.5 * this.h && y2 < 0.5 * this.h){
return true;
}

Categories