I have this script to create grid of rectangles, how would I go about logging map co ordinates of the mouse position so if the mouse was on 1,1 it would log 1,1?:
+---+---+---+---+
|0,0|0,1|0,2|0,3|
+---+---+---+---+
|1,0|1,1|1,2|1,3|
+---+---+---+---+
|2,0|2,1|2,2|2,3|
+---+---+---+---+
|3,0|3,1|3,2|3,3|
+---+---+---+---+
here is the script I have to create the grid;
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = (32 * 12);
canvas.height = (32 * 12);
document.body.appendChild(canvas);
var posX = 0;
var posY = 0;
var tileSize = 32;
$(document).ready(function(){
drawGrid();
});
function drawGrid(){
for(var x = 0; x < 12; x++){
for(var y = 0; y < 12; y++){
ctx.rect(posX, posY, tileSize, tileSize);
ctx.stroke();
posX += tileSize;
}
posY += tileSize;
posX = 0;
}
}
Just quantize the mouse position based on the tile size, for example (assuming you have already obtained the mouse position):
var gridX = (mouseX / tileSize)|0;
var gridY = (mouseY / tileSize)|0;
Now you can log gridX and gridY as the original grid definition.
On mouse move get the x and y position of the mouse and divide them by the tileSize.
Demo on Fiddle
canvas.onmousemove = function(e) {
var mouseX = e.pageX;
var mouseY = e.pageY;
document.getElementsByTagName('div')[0].innerHTML = '(' + Math.floor(mouseX / tileSize) + ', ' + Math.floor(mouseY / tileSize) + ')';
}
Related
i have a canvas, inside of which i have a board/grid. When a user highlights their mouse over an intersection of the grid, i want it to show where their game peice will go. This worked perfectly fine when the board was the exact size of the canvas. I made it abit smaller by x all the way round.
So as you can see in the picture below, the green shows the canvas and the grid is the board. I put my cursor at the very bottom right corner of the green to show when it triggers. The only one that works fine is the middle one because regardless how big i make the board, the middle will always be the middle.
Any easy fix would just be to make the area with the mouseover event, the dimensions of the board instead of the canvas but the event listener is on the canvas. My code is below the image
Variables:
var canvas = document.getElementById("game-canvas");
var context = canvas.getContext("2d");
var boardSize = 13;
var border = canvas.width / 20;
var boardWidth = canvas.width - (border * 2);
var boardHeight = canvas.height - (border * 2);
var cellWidth = boardWidth / (boardSize - 1);
var cellHeight = boardHeight / (boardSize - 1);
var lastX;
var lastY;
Mouse over event:
canvas.addEventListener('mousemove', function(evt)
{
var position = getGridPoint(evt);
if ((position.x != lastX) || (position.y != lastY))
{
placeStone((position.x * cellWidth) + border, (position.y * cellWidth) + border, 'rgba(0, 0, 0, 0.2)');
}
lastX = position.x;
lastY = position.y;
});
Gets the point on the grid and converts that into a number 0 - 13 (in this case)
function getGridPoint(evt)
{
var rect = canvas.getBoundingClientRect();
var x = Math.round((evt.clientX-rect.left)/(rect.right-rect.left)*boardWidth);
var y = Math.round((evt.clientY-rect.top)/(rect.bottom-rect.top)*boardHeight);
var roundX = Math.round(x / cellWidth);
var roundY = Math.round(y / cellHeight);
return {
x: roundX,
y: roundY
};
}
And finally draws the piece on the board:
function placeStone(x, y, color)
{
var radius = cellWidth / 2;
context.beginPath();
context.arc(x, y, radius, 0, 2 * Math.PI, false);
context.fillStyle = color;
context.fill();
context.lineWidth = 5;
}
I left a couple bits out like how the grid refreshs so its not a string of circles following your mouse and stuff, to keep it as short as i can, im hoping its just a simple asnwer and nobody needs to recreate it but if you do i can include the function that refreshes the grid and draws everything. Thankyou for any advice
To get the position relative to a box
// just as an example w,h are width and height
const box = { x : 10, y : 10, w : 100, h : 100 };
// mouse is the mouse coords and relative to the topleft of canvas (0,0);
var mouse.box = {}
mouse.box.x = mouse.x - box.x;
mouse.box.y = mouse.y - box.y;
Negative values for mouse.box x,y and values greater than box width and height have mouse outside.
For more convenience you can get the mouse normalize pos in the box
mouse.box.nx = mouse.box.x / box.w;
mouse.box.ny = mouse.box.y / box.h;
The coords for nx,ny are in the range 0-1 when inside or on the edge of the box;
If you want to have grid positions then define the grid
box.gridW = 10; // grid divisions width
box.gridH = 10; // grid divisions height
Then getting the grid pos of mouse
mouse.box.gx = Math.floor(mouse.box.nx * box.gridW);
mouse.box.gy = Math.floor(mouse.box.ny * box.gridH);
const ctx = canvas.getContext("2d");
const box = { x : 50,y : 10, w : 200, h : 200, gridW : 10, gridH : 10}
function drawGrid(){
var sx = box.w / box.gridW;
var sy = box.h / box.gridH;
var bx = box.x;
var by = box.y;
for(var y = 0; y < box.gridH; y ++){
for(var x = 0; x < box.gridW; x ++){
ctx.strokeRect(x * sx + bx, y * sx + by,sx,sy);
}
}
if(mouse.box){
if(mouse.box.nx >= 0 && mouse.box.nx <= 1 &&
mouse.box.ny >= 0 && mouse.box.ny <= 1){
ctx.fillRect(mouse.box.gx * sx + bx, mouse.box.gy * sx + by,sx,sy);
}
}
}
const mouse = {};
canvas.addEventListener("mousemove",(e)=>{
mouse.x = e.pageX;
mouse.y = e.pageY;
});
function updateMouse(){
if(!mouse.box){
mouse.box = {};
}
mouse.box.x = mouse.x - box.x;
mouse.box.y = mouse.y - box.y;
mouse.box.nx = mouse.box.x / box.w;
mouse.box.ny = mouse.box.y / box.h;
mouse.box.gx = Math.floor(mouse.box.nx * box.gridW);
mouse.box.gy = Math.floor(mouse.box.ny * box.gridH);
var p = 20;
ctx.fillText("x : " + mouse.x,box.x+box.w+10,p); p+= 14;
ctx.fillText("y : " + mouse.y,box.x+box.w+10,p); p+= 20;
ctx.fillText("Box relative",box.x+box.w+10,p); p+= 14;
ctx.fillText("x : " + mouse.box.x,box.x+box.w+10,p); p+= 14;
ctx.fillText("y : " + mouse.box.y,box.x+box.w+10,p); p+= 14;
ctx.fillText("nx : " + mouse.box.nx,box.x+box.w+10,p); p+= 14;
ctx.fillText("ny : " + mouse.box.ny,box.x+box.w+10,p); p+= 14;
ctx.fillText("gx : " + mouse.box.gx,box.x+box.w+10,p); p+= 14;
ctx.fillText("gy : " + mouse.box.gy,box.x+box.w+10,p); p+= 14;
}
function mainLoop(time){
if(canvas.width !== innerWidth || canvas.height !== innerHeight){ // resize canvas if window size has changed
canvas.width = innerWidth;
canvas.height = innerHeight;
}
ctx.setTransform(1,0,0,1,0,0); // set default transform
ctx.clearRect(0,0,canvas.width,canvas.height); // clear the canvas
updateMouse();
drawGrid();
requestAnimationFrame(mainLoop);
}
requestAnimationFrame(mainLoop);
canvas {
position : absolute;
top : 0px;
left : 0px;
}
<canvas id=canvas><canvas>
I made this program that will hopefully draw a cool shape based on the sliders. The problem is, nothing is showing up other than the sliders! Why is this?
var aslider, lslider, sslider, newx, newy;
function setup() {
createCanvas(300,300);
aslider = createSlider(1,359,17);
lslider = createSlider(1,50,10);
sslider = createSlider(1,50,20);
}
function draw() {
var angle = aslider.value();
var length = lslider.value();
var size = sslider.value();
var startx = width / 2;
var starty = height / 2;
var radians = angle * (Math.PI/180);
for (var i = 0; i++; i < size) {
newx = startx * Math.sin(radians) + starty * Math.cos(radians);
newy = startx * Math.sin(radians) + starty * -Math.cos(radians);
line(startx, starty, newx, newy);
startx = newx;
starty = newy;
}
}
Your for loop is wrong. It should be
for (var i = 0; i < size; i++)
I tested it here: http://codepen.io/eerk/pen/wgOZVW?editors=1010
I have an issue with dragging image that is scaled.
I've created main_canvas that contains background and image represented via bg_canvas resp. img_canvas. Then I've made coordinates of background (panoramaX, panoramaY) and image(imageX, imageY) to check if I clicked some of them and to be able to drag them.
Image is placed on top of background:
var drawToMain = function()
{
// first clear the canvas
main_ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.scale(scaleFactor, scaleFactor);
// draw the background image
main_ctx.drawImage(bg_canvas, panoramaX,panoramaY, 600, 300);
// do the transforms
main_ctx.translate( imageX+img_canvas.width/2,
imageY+img_canvas.height/2);
main_ctx.rotate(angle);
main_ctx.translate( -(imageX+img_canvas.width/2),
-(imageY+img_canvas.height/2));
// draw the img with the transforms applied
main_ctx.drawImage(img_canvas, imageX, imageY);
// reset the transforms
main_ctx.setTransform(1,0,0,1,0,0);
};
To drag items I'm testing if I clicked one of them:
function hitImage(x, y) {
if (x > imageX_hit && x < imageX_hit + img_canvas.width * scaleFactor &&
y > imageY_hit && y < imageY_hit + img_canvas.height * scaleFactor)
return 1;
if (x > panoramaX && x < panoramaX + bg_canvas.width * scaleFactor &&
y > panoramaY && y < panoramaY + bg_canvas.height * scaleFactor)
return 2;
return 0;
}
Then I've made wheel event to scale content of main_canvas (background and image, both) where is my issue, I'm updating image coordinates there but it doesn't work for me, when I zoom-out image for example and try to drag it, it doesn't move and when I'm zoomig image is "travelling" in background:
canvas.addEventListener("wheel", myFunction);
canvas.addEventListener('DOMMouseScroll', myFunction);
function myFunction(evt) {
var delta = evt.wheelDelta ? evt.wheelDelta / 40 : evt.detail ? -evt.detail : 0;
if (delta > 0) scaleFactor = scaleFactor + 0.05;
else scaleFactor = scaleFactor - 0.05;
imageX = imageX * scaleFactor;
imageY = imageY * scaleFactor;
imageX_hit = imageX_hit * scaleFactor;
imageY_hit = imageY_hit * scaleFactor;
drawToMain();
}
THERE is a exapmle of my problem.
Is there any solution, please?
Here is the code (fixed Slavik's code, update 1):
$(document).ready(function() {
// x, y to place image
var imageX = 80,
imageY = 80;
var imageX_hit = 80,
imageY_hit = 80;
// x, y to place background image
var panoramaX = 0,
panoramaY = 0;
var startX,
startY,
dragImage;
// mouse coordinates in canvas
var mouseX,
mouseY;
// number represents scale of image and background
var scaleFactor = 1,
angle = 0;
// main canvas
var canvas = document.createElement('canvas');
canvas.width = 600;
canvas.height = 300;
document.body.appendChild(canvas);
var ctx = canvas.getContext('2d');
var canvasOffset = $(canvas).offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var main_ctx = canvas.getContext('2d');
var bg_canvas = canvas.cloneNode(); // canvas for image
var img_canvas = canvas.cloneNode();// canvas for background
var angle = 0;
// draw on the main canvas, and only on the main canvas
var drawToMain = function()
{
// first clear the canvas
main_ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.scale(scaleFactor, scaleFactor);
// draw the background image
main_ctx.drawImage(bg_canvas, panoramaX,panoramaY, 600, 300);
// do the transforms
main_ctx.translate( imageX+img_canvas.width/2,
imageY+img_canvas.height/2);
main_ctx.rotate(angle);
main_ctx.translate( -(imageX+img_canvas.width/2),
-(imageY+img_canvas.height/2));
// draw the img with the transforms applied
main_ctx.drawImage(img_canvas, imageX, imageY);
// reset the transforms
main_ctx.setTransform(1,0,0,1,0,0);
};
// I changed the event to a simple onclick
$(canvas).mousedown(function(e) {
switch (e.which) {
case 1:
// mouse position and test if image is hit
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
dragImage = hitImage(startX, startY);
break;
default:
break;
}
});
$(canvas).mousemove(function(e) {
// Im moving with image
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
// move image by the amount of the latest drag
var dx = (mouseX - startX)/scaleFactor;
var dy = (mouseY - startY)/scaleFactor;
if (dragImage == 1) {
imageX += dx;
imageY += dy;
imageX_hit += dx;
imageY_hit += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
drawToMain();
}
else if (dragImage == 2) {
panoramaX += dx;
panoramaY += dy;
imageX += dx;
imageY += dy;
imageX_hit += dx;
imageY_hit += dy;
// reset the startXY for next time
startX = mouseX;
startY = mouseY;
drawToMain();
}
});
$(canvas).mouseup(function(e) {
switch (e.which) {
case 1:
dragImage = 0;
break;
default:
break;
}
});
// ZOOM-IN or ZOOM-OUT
canvas.addEventListener("wheel", myFunction);
canvas.addEventListener('DOMMouseScroll', myFunction);
// COMPUTING scaleFactor - zoom
function myFunction(evt) {
var delta = evt.wheelDelta ? evt.wheelDelta / 40 : evt.detail ? -evt.detail : 0;
if (delta > 0) scaleFactor = scaleFactor + 0.05;
else scaleFactor = scaleFactor - 0.05;
//imageX = imageX * scaleFactor;
//imageY = imageY * scaleFactor;
//console.log(imageX, imageY);
//imageX_hit = imageX_hit * scaleFactor;
//imageY_hit = imageY_hit * scaleFactor;
drawToMain();
}
// test if I user clicked image or panorama
function hitImage(x, y) {
x=x/scaleFactor;
y=y/scaleFactor;
if (x > imageX_hit && x < imageX_hit + img_canvas.width &&
y > imageY_hit && y < imageY_hit + img_canvas.height)
return 1;
if (x > panoramaX && x < panoramaX + bg_canvas.width &&
y > panoramaY && y < panoramaY + bg_canvas.height)
return 2;
return 0;
}
// loading images into canvas
var img = new Image();
img.onload = function() {
var this_canvas = img_canvas;
this_canvas.width = 150;
this_canvas.height = 150;
this_canvas.getContext('2d').drawImage(this, 0,
0, this_canvas.width,
this_canvas.height);
drawToMain();
};
img.src = 'http://pgmagick.readthedocs.org/en/latest/_images/lena_scale.jpg';
var bg = new Image();
bg.onload = function() {
var this_canvas = bg_canvas;
this_canvas.getContext('2d').drawImage(this, panoramaX,
panoramaY, 600, 300);
drawToMain();
};
bg.src = 'http://www.ansteorra.org/graphics/background/bg_image.jpg';
});
You don't need to change imageX, imageY and imageX_hit, imageY_hit variables by multiplying on scaleFactor. You scale image by context.scale so you don't need change something in your coordinates. Just remember scale factor and use it in hitImage for checking coordinates.
I'll try to edit post and explain more clearly, if this would be solution for your problem:
https://jsfiddle.net/j1f306w5/1/
My changes:
function hitImage(x, y) {
if (x > imageX_hit * scaleFactor && x < imageX_hit * scaleFactor + img_canvas.width * scaleFactor &&
y > imageY_hit * scaleFactor && y < imageY_hit * scaleFactor + img_canvas.height * scaleFactor)
return 1;
if (x > panoramaX * scaleFactor && x < panoramaX * scaleFactor + bg_canvas.width * scaleFactor &&
y > panoramaY * scaleFactor && y < panoramaY * scaleFactor + bg_canvas.height * scaleFactor)
return 2;
return 0;
}
and
function myFunction(evt) {
var delta = evt.wheelDelta ? evt.wheelDelta / 40 : evt.detail ? -evt.detail : 0;
if (delta > 0) scaleFactor = scaleFactor + 0.05;
else scaleFactor = scaleFactor - 0.05;
//imageX = imageX * scaleFactor;
//imageY = imageY * scaleFactor;
//imageX_hit = imageX_hit * scaleFactor;
//imageY_hit = imageY_hit * scaleFactor;
drawToMain();
}
I've a screen being redraw every 25ms, and images are flickering, here is my code
var FRAME_RATE = 40;
var intervalTime = 1000/FRAME_RATE;
gameLoop();
function gameLoop(){
context.clearRect(0, 0, 640, 640);
renderMap();
window.setTimeout(gameLoop, intervalTime);
}
and here is renderMap() function
function renderMap(){
var startX = playerX - (screenW / 2);
var startY = playerY - (screenH / 2);
maxX = playerX + (screenW / 2);
maxY = playerY + (screenH / 2);
$.getJSON('mapa3.json', function(json){
for (x = startX; x < maxX; x=x+32){
for (y = startY; y < maxY; y=y+32){
intTile = json.layers[0].data[((y/32)* 100) + (x/32)];
context.putImageData(getTile(intTile - 1), x - startX, y - startY);
}
}
});
var imgCharacter = new Image();
imgCharacter.src = 'char.png';
var posX = (screenW - imgCharacter.width) / 2;
var posY = (screenH - imgCharacter.height) / 2;
imgCharacter.onload = function(){context.drawImage(imgCharacter, posX, posY)}
}
What changes do I need to make to the code to stop flickering?
I believe it is because you are loading the image each iteration. Try putting the var imgCharacter..., the following line, and the image's onload function outside of renderMap so it is only ran once
var imgCharacter = new Image();
imgCharacter.onload = function () {
renderMap();
}
imgCharacter.src = 'char.png';
function renderMap() {
var startX = playerX - (screenW / 2);
var startY = playerY - (screenH / 2);
maxX = playerX + (screenW / 2);
maxY = playerY + (screenH / 2);
$.getJSON('mapa3.json', function (json) {
for (x = startX; x < maxX; x = x + 32) {
for (y = startY; y < maxY; y = y + 32) {
intTile = json.layers[0].data[((y / 32) * 100) + (x / 32)];
context.putImageData(getTile(intTile - 1), x - startX, y - startY);
}
}
});
var posX = (screenW - imgCharacter.width) / 2;
var posY = (screenH - imgCharacter.height) / 2;
context.drawImage(imgCharacter, posX, posY)
}
Thank you to markE for letting me know the onload function also needs to go outside renderMap, I overlooked it the first time
Load all images and other data before draw and storage them inside array.
Better use requestAnimationFrame.
Remember, getting JSON (or other data) can take some time.
I've already created a bouncing ball which bounces off the walls of the HTML5 Canvas that I have specified.
My goal is to make a "Game Over" screen appear when the pointer (mouse) hovers over the ball.
I have already searched and found some tutorials on mouse events in Javascript, but I'm not really sure how to implement them into my code =/.
Any help would be amazing.
<script>
var x = Math.floor((Math.random() * 600) + 1);
var y = Math.floor((Math.random() * 300) + 1);
var dx = 2;
var dy = 4;
function begin()
{
gameCanvas = document.getElementById('gameCanvas');
context = gameCanvas.getContext('2d');
return setInterval (draw, 20);
}
begin();
function draw()
{
context.clearRect(0,0,600,300);
context.fillStyle = "#0000FF";
context.beginPath();
context.arc(x,y,80,0,Math.PI*2,true);
context.closePath();
context.fill();
if (x < 0 || x > 600) dx=-dx
if (y < 0 || y > 300) dy=-dy;
x += dx;
y += dy;
}
gameCanvas.onmousemove = function (e)
{
var gameCanvas = e.target;
var context = gameCanvas.getContext('2d');
var coords = RGraph.getMouseXY(e);
}
You need to check if the mouse is hovering over the ball (hit test) by checking the distance of the ball to the cursor. If the distance is smaller than radius of the ball, it means that the mouse is over the ball.
Note, that you need to adjust the code below to your needs
Example:
var mouse_x = 10, mouse_y = 10, ball_x = 10, ball_y = 10, ball_radius = 70, is_game_over = false
if( Math.sqrt( Math.pow( mouse_x - ball_x, 2 ) + Math.pow( mouse_x - ball_x, 2 )) < ball_radius && !is_game_over ) {
console.log('Cursor is over the mouse, game over')
is_game_over = true
}
Do it for every frame update.
you can add onmousemove=SetValues() to your body element like so:
<body onmousemove=SetValues()>
and change your code to this:
<script>
var x = Math.floor((Math.random() * 600) + 1);
var y = Math.floor((Math.random() * 300) + 1);
var dx = 2;
var dy = 4;
var mouseX;
var mouseY;
function setValues(e)
{
mouseX = e.pageX; //get mouse x
mouseY = e.pageY; //get mouse y
}
function begin()
{
gameCanvas = document.getElementById('gameCanvas');
context = gameCanvas.getContext('2d');
return setInterval (draw, 20);
}
begin();
function draw()
{
context.clearRect(0,0,600,300);
context.fillStyle = "#0000FF";
context.beginPath();
context.arc(x,y,80,0,Math.PI*2,true);
context.closePath();
context.fill();
if (x < 0 || x > 600) dx=-dx
if (y < 0 || y > 300) dy=-dy;
x += dx;
y += dy;
//check if the mouse is on the ball
var centerX = x + 80; //center of ball
var centerY = y; //center of ball
if(Math.pow((mouseX - centerX), 2) + Math.pow((mouseY - centerY), 2) <= 6400){
//do whatever to end game
}
}