So I was coding some game (or what I call game) in JavaScript. And basically, you're supposed to click a place on the canvas and the player will be drawn there. But when I clicked the sprite was offset by some amount (I don't exactly know how much) to the point on the mouse. How can I get it so that the sprite will be draw exactly on the point of the mouse?
Link to image: http://i.imgur.com/Wnqb3L6.jpg?1
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
canvas.addEventListener('mousemove', mouseMoved, false);
canvas.addEventListener('click', drawPlayerPos, false);
var spriteSheet = new Image();
spriteSheet.src = 'spritesheet.png';
spriteSheet.addEventListener('load', init, false);
var gameWidth = canvas.width;
var gameHeight = canvas.height;
function init()
{
drawPlayerPos();
}
var mouseX;
var mouseY;
function mouseMoved(e)
{
mouseX = e.pageX - canvas.offsetLeft;
mouseY = e.pageY - canvas.offsetTop;
document.getElementById('mouseCoors').innerHTML = 'X: ' + mouseX + ' Y: ' + mouseY;
}
function drawPlayerPos()
{
var srcX = 1;
var srcY = 1;
var drawX = mouseX;
var drawY = mouseY;
var width = 15;
var height = 15;
ctx.drawImage(spriteSheet,srcX,srcY,width,height,drawX,drawY,width,height);
}
If the sprite is 15x15, you want srcX and srcY to be 0, not 1. And note that your code draws the top left corner of the sprite at the mouse point; if you want it to be centered you need to do:
drawX = mouseX - width / 2;
drawY = mouseY - height / 2;
Related
I should draw a rectangle inside a pdf document in canvas, but it cleans the background of document.
I want a way to draw a rectangle in it without cleaning the background. Please can anyone help me with this.
Below is the code i am using:
$("#div").mouseover(function () {
$("canvas").on('click', function (e) {
console.log(nr)
id = ($(this).attr("id"));
console.log(id)
const baseImage = loadImage("");
var canvas = document.getElementById(id);
var ctx = canvas.getContext('2d');
Canvas = ctx;
var canvasx = $(canvas).offset().left;
var canvasy = $(canvas).offset().top;
var last_mousex = last_mousey = 0;
var prev_x = prev_y = prev_w = prev_h = 0;
var mousex = mousey = 0;
var mousedown = false;
$(canvas).on('mousedown', function (e) {
if (rectanglearray.length < 2) {
last_mousex = parseInt(e.clientX - canvasx);
last_mousey = parseInt(e.clientY - canvasy);
mousedown = true;
}
});
$(canvas).on('mouseup', function (e) {
mousedown = false;
});
$(canvas).on('mousemove', function (e) {
mousex = parseInt(e.clientX - canvasx);
mousey = parseInt(e.clientY - canvasy);
if (mousedown) {
//if (rectanglearray.length < 2) {
ctx.clearRect(0, 0, canvas.width, canvas.height); //clear canvas
ctx.beginPath();
var width = mousex - last_mousex;
var height = mousey - last_mousey;
ctx.rect(last_mousex, last_mousey, width, height);
a = last_mousex;
b = last_mousey;
c = last_mousex + width;
d = last_mousey + height;
gjer = width;
lart = height;
t = a;
h = b;
gjere = gjer;
larte = lart;
nfq = id.substring(3, 4);
ctx.strokeStyle = 'black';
ctx.lineWidth = 1;
ctx.stroke();
rectanglearray.push(ctx);
//}
}
});
execute++;
});
});
so when i click in one of the pages of pdf it takes pages id and allows to only draw a rectangle in that page, but when i draw it cleans the background.
I have an image gallery. When a image from gallery is clicked, it is rendered on a canvas. The objective is to allow users to draw rectangles on regions of interest and capture the rectangle coordinates. The drawn rectangles vanishes when I move to the next image.
The following is the code and I have tried to comment as much as I can:
//get clicked image name and store in a variable
function clickedImage(clicked_id) {
var clickedImg = document.getElementById(clicked_id).src;
var clickedImg = clickedImg.replace(/^.*[\\\/]/, '');
localStorage.setItem("clickedImg", clickedImg);
//initiate canvas to load image
var canvas = document.getElementById("iriscanvas");
var ctx = canvas.getContext("2d");
var thumbNails = document.getElementById("loaded_img_panel");
var pic = new Image();
pic.onload = function() {
ctx.drawImage(pic, 0,0)
}
//load the image from the thumbnail on to the canvas
thumbNails.addEventListener('click', function(event) {
pic.src = event.target.src;
});
//thickness of rectangle and count of rectangles
var strokeWidth = 3;
drawCount = 1;
//initiate mouse events
canvas.addEventListener("mousemove", function(e) {
drawRectangleOnCanvas.handleMouseMove(e);
}, false);
canvas.addEventListener("mousedown", function(e) {
drawRectangleOnCanvas.handleMouseDown(e);
}, false);
canvas.addEventListener("mouseup", function(e) {
drawRectangleOnCanvas.handleMouseUp(e);
}, false);
canvas.addEventListener("mouseout", function(e) {
drawRectangleOnCanvas.handleMouseOut(e);
}, false);
function reOffset() {
var BB = canvas.getBoundingClientRect();
recOffsetX = BB.left;
recOffsetY = BB.top;
}
var recOffsetX, recOffsetY;
reOffset();
window.onscroll = function(e) {
reOffset();
}
window.onresize = function(e) {
reOffset();
}
var isRecDown = false;
var startX, startY;
var rects = [];
var newRect;
var drawRectangleOnCanvas = {
handleMouseDown: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
startX = parseInt(e.clientX - recOffsetX);
startY = parseInt(e.clientY - recOffsetY);
// Put your mousedown stuff here
isRecDown = true;
},
handleMouseUp: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseup stuff here
isRecDown = false;
//if(!willOverlap(newRect)){
rects.push(newRect);
//}
drawRectangleOnCanvas.drawAll();
var brand = localStorage.getItem("brandNode");
var clickImg = localStorage.getItem("clickedImg");
//get x,y,w,h coordinates depending on how the rectangle is drawn.
if((mouseX-startX) < 0) {
stX = startX + (mouseX-startX)
} else {
stX = startX
}
if((mouseY-startY) < 0) {
stY = startY + (mouseY-startY)
} else {
stY = startY
}
if((mouseX-startX) < 0) {
stW = startX - stX
} else {
stW = mouseX - startX
}
if((mouseY-startY) < 0) {
stH = startY - stY
} else {
stH = mouseY - startY
}
//log the coordinates of the rectangles
var dat = {image : clickImg, brand: brand, x : stX, y : stY, w: stW, h: stH};
var dat = JSON.stringify(dat);
console.log(dat);
},
drawAll: function() {
ctx.drawImage(pic, 0, 0);
ctx.lineWidth = strokeWidth;
var brand = localStorage.getItem("brandNode");
for (var i = 0; i < rects.length; i++) {
var r = rects[i];
ctx.strokeStyle = r.color;
ctx.globalAlpha = 1;
ctx.strokeRect(r.left, r.top, r.right - r.left, r.bottom - r.top);
ctx.beginPath();
//ctx.arc(r.left, r.top, 15, 0, Math.PI * 2, true);
ctx.closePath();
ctx.fillStyle = r.color;
ctx.fill();
var text = brand;
ctx.fillStyle = "#fff";
var font = "bold " + 12 + "px serif";
ctx.font = font;
var width = ctx.measureText(text).width;
var height = ctx.measureText("h").height; // this is a GUESS of height
ctx.fillText(text, r.left-1, r.top - 10)
}
},
handleMouseOut: function(e) {
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
// Put your mouseOut stuff here
isRecDown = false;
},
handleMouseMove: function(e) {
if (!isRecDown) {
return;
}
// tell the browser we're handling this event
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - recOffsetX);
mouseY = parseInt(e.clientY - recOffsetY);
newRect = {
left: Math.min(startX, mouseX),
right: Math.max(startX, mouseX),
top: Math.min(startY, mouseY),
bottom: Math.max(startY, mouseY),
color: "#9afe2e"
}
drawRectangleOnCanvas.drawAll();
ctx.strokeStyle = "#9afe2e";
ctx.lineWidth = strokeWidth;
ctx.globalAlpha = 1;
ctx.strokeRect(startX, startY, mouseX - startX, mouseY - startY);
}
}
}
When I move to the next image the rectangles created on the previous image is removed. I don't know if I have to use canvas.toDataURL to retain the rectangles, because I have thousands of images in the gallery and not sure if I will have space in the browser, though not all the images are going to the used for drawing rectangles.
Moreover, after drawing the rectangles when I click on the same image, it clears all the rectangles.
How can I retain the drawn rectangles within a session at least?
Layer 2 canvases over each other. Render the image into the bottom canvas, and draw on the top one. That way, changing the image won't affect the drawn lines.
A <canvas> works just like a real-life painter's canvas. There is no concept of layers or "objects" on a canvas. It's all just paint on a single surface.
When you draw a different image on a canvas, you're overriding everything that was on the canvas already.
Code description: A Car object updates its location and orientation regularly based on mouse location. I'm the requestAnimationFrame function for smoother rendering of frames.
Issues:
The car object's x and y coordinates are NAN when I'm inside the drawing function.
Car doesn't show on canvas.
Code:
<!DOCTYPE html>
<html>
<head>
<style type="text/css">
body {
overflow:hidden;
}
</style>
</head>
<body>
<canvas id="myCanvas">
</canvas>
<script>
// requestAnimationFrame initialization with cross-browser compatibility
(function(){
var requestAnimationFrame = window.requestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.msRequestAnimationFrame;
window.requestAnimationFrame = requestAnimationFrame;
})();
// canvas and context objects
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = window.innerWidth;
myCanvas.height = window.innerHeight;
var ctx = myCanvas.getContext("2d");
myCanvas.addEventListener('mousemove', updateMousePos, false);
//mouse position coordinates
var mousex;
var mousey;
//constructor for a Car object with methods to update position, orientation, and draw the car
function Car(x, y, orientation, id, type) {
//x and y are the cooredinates of the center of a car object
this.x = x;
this.y = y;
this.type = type;
this.speed = 5; //default speed = 5
this.isAlive = 1;
this.stillExists = 1;
this.id = id;
this.orientation = orientation;
this.img = new Image();
this.img.source = 'car1.png';
this.img.width = 200;
this.img.height = 100;
//this method computes a new positin and orientation of our car.
this.updatePosAndOrien = function(){
//caclcuate car orientation using mousex and mousey and x y position of our car using atan2
var targetX = mousex - this.x;
var targetY = mousey - this.y;
var trgtOrien = Math.atan2(targetY, targetX);
this.orientation = trgtOrien;
//calculate new positon of car using speed and current location of car
var dx = mousex -this.x;
var dy = mousey - this.y;
//distance between mouse and car
var distance = Math.sqrt(dx*dx + dy*dy);
//Now we compute xspeed and yspeed of car - which are displacements along x and y axis
var factor = distance / this.speed;
var xspeed = dx / factor;
var yspeed = dy / factor;
//set new positon of car
this.x = this.x + xspeed;
this.y = this.y+ yspeed;
};
//draw method that draws the car on canvas
this.draw = function() {
this.img.x = this.x;
this.img.y = this.y;
this.img.orientation = this.orientation;
this.img.onload = function() {
ctx.save();//save context
//translate context origin to center of image
ctx.translate(Math.round(this.x), Math.round(this.y));
ctx.rotate(this.orientation); //rotate context
ctx.drawImage(img, -(this.width/2), -(this.height/2),
this.width, this.height);//draw img
ctx.restore(); //restore context
}
};
}
/*this function update mouse position upon mouse movement*/
function updateMousePos(evt) {
var rect = myCanvas.getBoundingClientRect();
mousex = evt.clientX - rect.left;
mousey = evt.clientY - rect.top;
//log mouse position
console.log("mouse postion: "+mousex+", "+mousey);
}
//defining car and starting the rendering
var ourCar = new Car(300, 400, 2, 111, 1);
console.log("car: "+ourCar.x+", "+ourCar.y);
/*This function draws everything using requestFrameAnimation(). */
function drawIt() {
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);
//update orientation of player
ourCar.updatePosAndOrien();
console.log("car in drawIt: "+ourCar.x+", "+ourCar.y); //prints NAN for both
//Draw car
console.log("drawing the car");
ourCar.draw();
requestAnimationFrame(drawIt);
}
//start rendering
requestAnimationFrame(drawIt);
</script>
</body>
</html>
There's a couple of things going on here...
First, requestAnimationFrame(drawIt) runs on page load. If the mouse has not moved yet, then mousex and mousey are NaN. Furthermore, drawIt continues to call itself, so if you look at the console it just keeps repeating the NaN. I'm not sure what your objective is, but you might want to check for valid values for ourCar.x and ourCar.y and return if there aren't any set.
As for the image, first, like xufox said, you are using img instead of this.img. However, since you are inside a function at this point, you don't want to use this as it is referring to the actual img tag itself. You should set a variable outside that function and set it equal to this.
Second, in order to get the img.onload to fire, you need to set the src attribute of the image.
JS Fiddle and code below with comments and console messages to illustrate, and updates made to get it to work, you might want to refactor for your needs.
https://jsfiddle.net/2dd4rv9u/
// canvas and context objects
var myCanvas = document.getElementById("myCanvas");
myCanvas.width = window.innerWidth;
myCanvas.height = window.innerHeight;
var ctx = myCanvas.getContext("2d");
myCanvas.addEventListener('mousemove', updateMousePos, false);
//mouse position coordinates
var mousex;
var mousey;
//constructor for a Car object with methods to update position, orientation, and draw the car
function Car(x, y, orientation, id, type) {
//x and y are the cooredinates of the center of a car object
this.x = x;
this.y = y;
this.type = type;
this.speed = 5; //default speed = 5
this.isAlive = 1;
this.stillExists = 1;
this.id = id;
this.orientation = orientation;
this.img = new Image();
this.img.source = 'http://www.iconsdb.com/icons/preview/black/car-xxl.png';
this.img.width = 200;
this.img.height = 100;
//this method computes a new positin and orientation of our car.
this.updatePosAndOrien = function(){
//caclcuate car orientation using mousex and mousey and x y position of our car using atan2
var targetX = mousex - this.x;
var targetY = mousey - this.y;
var trgtOrien = Math.atan2(targetY, targetX);
this.orientation = trgtOrien;
//calculate new positon of car using speed and current location of car
var dx = mousex -this.x;
var dy = mousey - this.y;
//distance between mouse and car
var distance = Math.sqrt(dx*dx + dy*dy);
//Now we compute xspeed and yspeed of car - which are displacements along x and y axis
var factor = distance / this.speed;
var xspeed = dx / factor;
var yspeed = dy / factor;
//set new positon of car
this.x = this.x + xspeed;
this.y = this.y+ yspeed;
};
//draw method that draws the car on canvas
this.draw = function() {
this.img.x = this.x;
this.img.y = this.y;
this.img.orientation = this.orientation;
var self = this;
this.img.onload = function() {
console.log('DRAWING');
console.log(this);
console.log(this.img);
console.log(self.img.x);
ctx.save();//save context
//translate context origin to center of image
ctx.translate(Math.round(self.x), Math.round(self.y));
ctx.rotate(self.orientation); //rotate context
// I set these to 0 because I didn't check the math and wanted to show
// that the car would draw
ctx.drawImage(self.img, 0, 0);//draw img
ctx.restore(); //restore context
}
this.img.src = this.img.source;
};
}
/*this function update mouse position upon mouse movement*/
function updateMousePos(evt) {
var rect = myCanvas.getBoundingClientRect();
mousex = evt.clientX - rect.left;
mousey = evt.clientY - rect.top;
//log mouse position
console.log("mouse postion: "+mousex+", "+mousey);
}
//defining car and starting the rendering
var ourCar = new Car(300, 400, 2, 111, 1);
console.log("car: "+ourCar.x+", "+ourCar.y);
/*This function draws everything using requestFrameAnimation(). */
function drawIt() {
if (isNaN(ourCar.x)) return;
// Use the identity matrix while clearing the canvas
ctx.setTransform(1, 0, 0, 1, 0, 0);
ctx.clearRect(0, 0, myCanvas.width, myCanvas.height);
//update orientation of player
ourCar.updatePosAndOrien();
console.log("car in drawIt: "+ourCar.x+", "+ourCar.y); //prints NAN for both
//Draw car
console.log("drawing the car");
ourCar.draw();
requestAnimationFrame(drawIt);
}
//start rendering
requestAnimationFrame(drawIt);
I am currently working on an application where I draw a rectangle on a canvas. I can draw the rectangle perfectly but then when I try to change the movement of the mouse to make the rectangle smaller there are trails that are left behind. How do I clear these trails when I make the rectangle's size smaller? below is my JavaScript code that I used. Thanks in advance.
function drawSquare() {
// creating a square
var w = lastX - startX;
var h = lastY - startY;
var offsetX = (w < 0) ? w : 0;
var offsetY = (h < 0) ? h : 0;
var width = Math.abs(w);
var height = Math.abs(h);
context.beginPath();
context.rect(startX + offsetX, startY + offsetY, width, height);
context.fillStyle = "gold";
context.fill();
context.lineWidth = 1;
context.strokeStyle = 'red';
context.stroke();
canvas.style.cursor = "default";
}
function getMousePos(canvas, e) {
var rect = canvas.getBoundingClientRect();
return {
x: e.pageX - canvas.offsetLeft,
y: e.pageY - canvas.offsetTop,
};
}
function handleMouseDown(e) {
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
isDown = true;
if (isChecBoxClicked == true) {
mouseIsDown = 1;
startX = lastX;
startY = lastY;
var pos = getMousePos(canvas, e);
startX = lastX = pos.x;
startY = lastY = pos.y;
drawSquare();
}
else {
canvas.style.cursor = "default";
}
}
function handleMouseUp(e) {
// clear the dragging flag
isDown = false;
canvas.style.cursor = "default";
// get mouse coordinates
mouseX = parseInt(e.pageX - offsetX);
mouseY = parseInt(e.pageY - offsetY);
// set the starting drag position
lastX = mouseX;
lastY = mouseY;
if (isChecBoxClicked == true)
{
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
mouseIsDown = 0;
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
function handleMouseMove(e) {
// if we're not dragging, exit
if (!isDown) {
return;
}
//if (defaultval == 1) {
// return;
//}
if (isChecBoxClicked == true) {
canvas.style.cursor = "crosshair";
if (mouseIsDown !== 0) {
var pos = getMousePos(canvas, e);
lastX = pos.x;
lastY = pos.y;
drawSquare();
}
}
}
A canvas doesn't clear itself. At least not a 2D context, like you are using. If you keep drawing on it, the new graphics is placed on top of the old. You need to explicitly clear it:
context.clearRect(0, 0, canvas.width, canvas.height);
You will probably have to clear your canvas. If you are only drawing a square you will have to do that in the drawSquare function. If you are drawing multiple things you will have to do it in a higher function that redraws multiple things.
For clearing the whole canvas, you can use the following code:
context.clearRect ( 0 , 0 , canvas.width, canvas.height );
There are also a lot of canvas libraries that will manage this for you and optimize the areas redrawn (they might only clear a part of the canvas, so there are less pixels redrawn)
I'm trying to draw a rectangle on canvas with a click, a mouse movement, and another click. How should I go about following the user's cursor after the first click and displaying a preview of a filled rectangle on canvas of what the shape would look like at any given coordinate.
So far, I can successfully create the rectangle without showing what the rectangle will look like at any coordinate.
Here is the code so far:
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var drawingShape = false;
//function getMousePos(canvas, ev) {
//var rect = canvas.getBoundingClientRect();
//}
//canvas.addEventListener('mousemove', function (ev) {
//var mousePos = getMousePos(canvas, ev);
//}
function setMousePosition(e) {
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
if (drawingShape) {
drawingShape = false;
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
} else {
drawingShape = true;
startX = mouseX;
startY = mouseY;
}
}
$("#canvas").mousedown(function (e) {
setMousePosition(e);
});
I attempted to use an event listener to mouse movement, as I saw in this HTML5 tutorial (http://www.html5canvastutorials.com/advanced/html5-canvas-mouse-coordinates/), but I'm unsure how to connect it with the existing code.
You can store the image whenever you start drawing and reload it everytime you want to edit it.
Here's my quick implementation based on your code, it needs some optimization (perhaps only capture the area you're planning to draw):
var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var canvasOffset = $("#canvas").offset();
var offsetX = canvasOffset.left;
var offsetY = canvasOffset.top;
var startX;
var startY;
var drawingShape = false;
var oldImage;
canvas.addEventListener('mousemove', function(e){
if(drawingShape){
ctx.putImageData(oldImage,0,0);
mouseX = parseInt(e.clientX - offsetX, 10);
mouseY = parseInt(e.clientY - offsetY, 10);
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
}
});
function setMousePosition(e) {
mouseX = parseInt(e.clientX - offsetX, 10);
mouseY = parseInt(e.clientY - offsetY, 10);
$("#downlog").html("Down: " + mouseX + " / " + mouseY);
if (drawingShape) {
drawingShape = false;
ctx.beginPath();
ctx.fillStyle = "#FF0000";
ctx.rect(startX, startY, mouseX - startX, mouseY - startY);
ctx.fill();
} else {
drawingShape = true;
startX = mouseX;
startY = mouseY;
oldImage = ctx.getImageData(0,0,canvas.width,canvas.height);
}
}
$("#canvas").mousedown(function (e) {
setMousePosition(e);
});
Notice how we store the image data in the mouse down event and retrieve it on each mouse move