So I have a canvas with an isometric tile map drawn on it, which looks perfect.
In the event listener at the bottom of the script, I grab the cursor's coordinates inside the canvas. How could I find out which tile the cursor is hovering over?
var cs = document.getElementById('board');
var c = cs.getContext("2d")
var gridWidth=100
var gridHeight=50
var tilesX = 12, tilesY = 12;
var spriteWidth=gridWidth
var spriteHeight=img.height/img.width*gridWidth
cs.width = window.innerWidth //spriteWidth*10
cs.height = window.innerHeight //spriteHeight*10
var ox = cs.width/2-spriteWidth/2
var oy = (tilesY * gridHeight) / 2
window.onresize=function(){
cs.width = window.innerWidth //spriteWidth*10
cs.height = window.innerHeight //spriteHeight*10
ox = cs.width/2-spriteWidth/2
oy = (tilesY * gridHeight) / 2
draw()
}
draw();
function renderImage(x, y) {
c.drawImage(img, ox + (x - y) * spriteWidth/2, oy + (y + x) * gridHeight/2-(spriteHeight-gridHeight),spriteWidth,spriteHeight)
}
function draw(){
for(var x = 0; x < tilesX; x++) {
for(var y = 0; y < tilesY; y++) {
renderImage(x,y)
}
}
}
cs.addEventListener('mousemove', function(evt) {
var x = evt.clientX,
y = evt.clientY;
console.log('Mouse position: ' + x + ',' + y);
}, false);
Sorry for pasting such lengthy code, but all of it is there just to lay the isometric grid.
EDIT: Also, how could I get the top left coordinates of the tile image to relay it?
Assuming you've arranged your tiles where the leftmost column and topmost row are zero:
var column = parseInt(mouseX / tileWidth);
var row = parseInt(mouseY / tileHeight);
BTW, if you eventually move your canvas off the top-left of the page then you must adjust your mouse coordinates by the canvas offset.
Here's an example of how to calculate mouse position:
// references to the canvas element and its context
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// get the offset position of the canvas on the web page
var BB=canvas.getBoundingClientRect();
var offsetX=BB.left;
var offsetY=BB.top;
// listen for mousedown events
canvas.onmousedown=handleMousedown;
function handleMousedown(e){
// tell the browser we will handle this event
e.preventDefault();
e.stopPropagation();
// calculate the mouse position
var mouseX=e.clientX-offsetX;
var mouseY=e.clientY-offsetY;
}
Related
I have created the following code to make the player move towards the mouse, JSFiddle
Code
var mouseX = 0, mouseY = 0;
$(document).mousemove(function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
});
$(function(){
var $map = $(".map");
var $player = $('.player');
var centerPlayerX = $player.offset().left + $player.width() / 2;
var centerPlayerY = $player.offset().top + $player.height() / 2;
var movingInterval;
$('.map').on('mousedown', function(event){
movingInterval = setInterval(function(){
var clickedPosX = mouseX,
clickedPosY = mouseY;
var currentMapPositionX = parseFloat($map.css("background-position-x"));
var currentMapPositionY = parseFloat($map.css("background-position-y"));
var moveMapX = currentMapPositionX - clickedPosX/100 + centerPlayerX/100;
var moveMapY = currentMapPositionY - clickedPosY/100 + centerPlayerY/100;
$map.css({ "background-position-x": `${moveMapX}px`, "background-position-y": `${moveMapY}px` });
var angle = getDirection(centerPlayerX, clickedPosY, clickedPosX, centerPlayerY);
$player.find('.ship').css('transform', 'rotate('+angle+'deg)');
}, 10);
}).on('mouseup', function() {
clearInterval(movingInterval);
});;
});
function getDirection(x1, y1, x2, y2){
var dx = x2 - x1;
var dy = y2 - y1;
return Math.atan2(dx, dy) / Math.PI * 180;
}
Problem
var moveMapX = currentMapPositionX - clickedPosX/100 + centerPlayerX/100;
var moveMapY = currentMapPositionY - clickedPosY/100 + centerPlayerY/100;
Problem is that I want to move the player at a set speed (px*ps). Currently the player will increase in speed when the player moves his mouse further away from the image. I currently have no idea on how I would move the player at a set speed. Therefore I would need to remove clickedPosY/X somehow and change it to a static speed but the image should still move towards were the mouse is, which is the problem.
So, let's assume you have a speed constant; what you want to do is to project the speed constant along the movement vector. The easiest way to do that is to scale the components of the offset to the click position by the ratio of the speed to the distance between the click point and the movement base:
var distanceX = clickedPosX - centerPlayerX;
var distanceY = clickedPosY - centerPlayerY;
var magnitude = Math.sqrt(distanceX * distanceX + distanceY * distanceY);
var deltaX = distanceX * speed / magnitude;
var deltaY = distanceY * speed / magnitude;
var moveMapX = currentMapPositionX - deltaX;
var moveMapY = currentMapPositionY - deltaY;
Updated fiddle
So the following code will make an array of circles. I want to be able to click on a circle and have a popup tell me how many rows and columns along that circle is starting from (1,1).
Does anyone know how to do this?
var c = document.getElementById("myCanvas");
var ctx = c.getContext("2d");
var gCanvasElement = ctx;
ctx.strokeStyle="#FF0000";
ctx.strokeRect(20,20,800,600);
// Positions are hardcoded to make sure that circle starts from the right place
var startX = 55;
var startY = 55;
console.clear();
for(var i=1;i<=8;i++){
console.group(i);
for(var j=1;j<=i;j++){
ctx.beginPath();
ctx.strokeStyle='green';
//radius is hardcoded to 30 for testing purpose
ctx.arc(startX*j + (j-1)*10,startY*i + (i-1)*10,30,0,2*Math.PI);
ctx.stroke();
//console log
console.group(j);
console.log(startX*j + (j-1)*10);
console.log(startY*i + (i-1)*10);
console.groupEnd(j);
}
console.groupEnd(i);
}
As I've written in my comment canvas is just a raster image. It does not store shapes unlike vector graphics (SVG). So you need to use math to find if the user clicked the circle or not.
http://jsfiddle.net/tarabyte/Jct6j/
function distance(x1, y1, x2, y2) { //helper to get distance between 2 points
return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
}
function center(i) { //helper to get coordinates of i-th circle
return (i*2-1)*radius + (i-1)*step/2;
}
c.addEventListener('click', function(ev){ //click lister
var x = ev.pageX - c.offsetLeft - (startX - radius), //normalized coords
y = ev.pageY - c.offsetTop - (startY - radius), //normalized coords
grid = 2*radius + step/2,
i, j, d;
if(x < 0 || y < 0) { return;} //out of circles
//cell inside your grid
i = Math.ceil(x/grid);
j = Math.ceil(y/grid);
if(i > j) { return;} //out of circles
d = distance(x, y, center(i), center(j));
if(d > radius) {return;} //to far from center
console.log(i, j);
}, false);
I need to do an action onclick of a particular (point) or a rectangle in a canvas.
Example:
$(document).ready(function(){
var canvas = $('#myCanvas').get(0);
if (!canvas.getContext) { return; }
var ctx = canvas.getContext('2d');
ctx.fillRect(150,140,8,8);
ctx.fillRect(200,120,8,8);
ctx.fillRect(200,160,8,8);
});
I need to connect two points with a line and another two points with a curve using javascript .How can i do this?
You need to maintain the regions yourselves. There are no objects on a canvas, only pixels and the browser does not know anything about it.
Demo here
You can do something like this (simplified):
// define the regions - common for draw/redraw and check
var rect1 = [150,140,8,8];
var rect2 = [200,120,8,8];
var rect3 = [200,160,8,8];
var regions = [rect1, rect2, rect3];
Now on your init you can use the same array to render all the rectangles:
$(document).ready(function(){
var canvas = $('#myCanvas').get(0);
if (!canvas.getContext) { return; }
var ctx = canvas.getContext('2d');
//use the array also to render the boxes
for (var i = 0, r; r = regions[i]; i++) {
ctx.fillRect(r[0],r[1],r[2],r[3]);
}
});
On the click event you check the array to see if the mouse coordinate (corrected for canvas) is inside any of the rectangles:
$('#myCanvas').on('click', function(e){
var pos = getMousePos(this, e);
// check if we got a hit
for (var i = 0, r; r = regions[i]; i++) {
if (pos.x >= r[0] && pos.x <= (r[0] + r[2]) &&
pos.y >= r[1] && pos.y <= (r[1] + r[3])) {
alert('Region ' + i + ' was hit');
}
}
});
//get mouse position relative to canvas
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
Also remember to redraw the canvas if the window is re-sized or for other reason clears the canvas (browser dialogs etc.).
To connect the boxes you need to store the first hit position and when you get a second hit draw a line between them.
Demo with lines here
Add to the global vars and also make canvas and context available from global (see fiddle for related modifications in onready):
var x1 = -1, y1;
var canvas = myCanvas;
var ctx = canvas.getContext('2d');
And in the click event:
$('#myCanvas').on('click', function(e){
var pos = getMousePos(this, e);
for (var i = 0, r; r = regions[i]; i++) {
if (pos.x >= r[0] && pos.x <= (r[0] + r[2]) &&
pos.y >= r[1] && pos.y <= (r[1] + r[3])) {
//first hit? then store the coords
if (x1 === -1) {
x1 = pos.x;
y1 = pos.y;
} else {
//draw line from first point to this
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(pos.x, pos.y);
ctx.stroke();
x1 = -1; //reset (or keep if you want continuous lines).
};
}
}
});
I wrote a JavaScript that allows a user to draw with their mouse on an HTML5 canvas (similar to MS Paint).
Right now, I have 2 problems:
The drawing feature only works if the HTML5 canvas element is positioned at the top left corner (0, 0) of the web page, otherwise it doesn't work at all OR the drawing is off center.
I'm unable to erase the drawing. When I erase the drawing it erases BUT as soon as I start drawing again, it comes back.
My code is below:
HTML Canvas
<canvas id="can1" width="500" height="500"></canvas>1
JavaScript for Canvas Drawing
// Variables
var x1;
var y1;
var isPressed = false;
var myCanvas;
var myContext;
function startCanvas() {
// Canvas stuff
myCanvas = document.getElementById("can1");
myContext = myCanvas.getContext("2d");
// Specify a black background, and white lines that are 3 pixels thick.
myContext.fillStyle = '#fff';
myContext.strokeStyle = '#fff';
myContext.fillRect(0, 0, 500, 500);
myContext.lineWidth = 3;
myContext.fill();
}
function functionMouseDown(e) {
// Get coordinates
x1 = e.clientX
y1 = e.clientY;
isPressed = true;
}
function functionMouseMove(e) {
// If mouse is down and moved start drawing line
if (isPressed == true) {
drawLine(e);
}
}
function functionMouseUp() {
// Stop drawing line
isPressed = false;
//myContext.closePath();
//myContext.stroke();
}
function drawLine(e) {
// Draw line
var x = e.clientX;
var y = e.clientY;
myContext.strokeStyle = '#cc0000';
myContext.lineWidth = 1;
myContext.moveTo(x1, y1);
myContext.lineTo(x, y);
myContext.stroke();
// Set start coordinates to current coordinates
x1 = x;
y1 = y;
}
JavaScript that I use to erase canvas:
myContext.clearRect(0, 0, 500, 500);
I use the following function to accomplish this
function relMouseCoords(event){/*needs fixing for general case*/
var totalOffsetX = 0
var totalOffsetY = 0
var canvasX = 0
var canvasY = 0
var currentElement = this
do{
totalOffsetX += currentElement.offsetLeft
totalOffsetY += currentElement.offsetTop
}
while(currentElement = currentElement.offsetParent)
canvasX = event.pageX - totalOffsetX
canvasY = event.pageY - totalOffsetY
return {x:canvasX, y:canvasY}
}
HTMLCanvasElement.prototype.relMouseCoords = relMouseCoords;
then
var cord = e.target.relMouseCoords(e);
x1 = cord.x;
y1 = cord.y;
...
var cord = e.target.relMouseCoords(e);
var x = cord.x;
var y =cord.y;
http://jsfiddle.net/mowglisanu/u3rvT/1/
The simplest solution is to set the off set of the canvas using myCanvas.offsetLeft and myCanvas.offsetTop.
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))