Make image drawn on canvas draggable with JavaScript - javascript

I was able to successfully draw an image on an HTML canvas. But I need to be able to drag the image about on the canvas.
I know this function can be implemented easily by some JavaScript libraries like KinectJS. But I want to just do it with simple JavaScript.
window.onload = function(){
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
var destX = 0;
var destY = 0;
var imageObj = new Image();
imageObj.onload = function(){
context.drawImage(imageObj, destX, destY);
};
imageObj.src = "westeros.png";
<canvas id="myCanvas" height=1024 width=360></canvas>

To do dragging you handle 3 mouse events:
mousedown -- set a flag indicating that the drag has begun.
mouseup -- clear that drag flag because the drag is over
mousemove -- if the drag flag is set, clear the canvas and draw the image at the mouse position
Here is some code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var img = new Image();
img.onload = function(){
ctx.drawImage(img, 0,0);
};
img.src = "http://images.christmastimeclipart.com/images/2/1271716593176_1788/img_1271716593176_17881.jpg";
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var canvasWidth=canvas.width;
var canvasHeight=canvas.height;
var isDragging=false;
function handleMouseDown(e){
canMouseX=parseInt(e.clientX-offsetX);
canMouseY=parseInt(e.clientY-offsetY);
// set the drag flag
isDragging=true;
}
function handleMouseUp(e){
canMouseX=parseInt(e.clientX-offsetX);
canMouseY=parseInt(e.clientY-offsetY);
// clear the drag flag
isDragging=false;
}
function handleMouseOut(e){
canMouseX=parseInt(e.clientX-offsetX);
canMouseY=parseInt(e.clientY-offsetY);
// user has left the canvas, so clear the drag flag
//isDragging=false;
}
function handleMouseMove(e){
canMouseX=parseInt(e.clientX-offsetX);
canMouseY=parseInt(e.clientY-offsetY);
// if the drag flag is set, clear the canvas and draw the image
if(isDragging){
ctx.clearRect(0,0,canvasWidth,canvasHeight);
ctx.drawImage(img,canMouseX-128/2,canMouseY-120/2,128,120);
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=400 height=300></canvas>
</body>
</html>

markE's answer got me most of the way there, but I had some problems with it recognizing the location my mouse was in. I'm attaching my code although since I work with OO JS it'll be differently structured:
hitImage: function() {
return (this.startX > this.imageX &&
this.startX < this.imageX + this.imageWidth &&
this.startY > this.imageY &&
this.startY < this.imageY + this.imageHeight);
},
handleMouseDown: function(e){
this.startX = parseInt(e.clientX - this.offsetX);
this.startY = parseInt(e.clientY - this.offsetY);
// set the drag flag
this.isDragging= this.hitImage;
},
handleMouseUp: function(e,img){
this.startX=parseInt(e.clientX-this.offsetX);
this.startY=parseInt(e.clientY-this.offsetY);
// clear the drag flag
this.isDragging=false;
this.drawImage(e,img);
},
handleMouseOut: function(e,img){
this.handleMouseUp(e,img);
},
handleMouseMove: function(e,img){
// only compute new positions if in drag
if(this.isDragging){
this.canMouseX=parseInt(e.clientX - this.offsetX);
this.canMouseY=parseInt(e.clientY - this.offsetY);
// move the image by the amount of the latest drag
var dx = this.canMouseX - this.startX;
var dy = this.canMouseY - this.startY;
this.imageX += dx;
this.imageY += dy;
// Negative image locations break the pattern in this.fillPattern
this.imageY = Math.max(0, this.imageY);
this.imageX = Math.max(0, this.imageX);
// reset the startXY for next time
this.startX = this.canMouseX;
this.startY = this.canMouseY;
this.drawImage(e,img);
}

Related

Draw a line on mouse drag on a canvas loaded with an image

I have a canvas loaded with an image.
Now, I want to mark lines on some part of the image.
So, I wrote some code which draws a line on mouse drag.
function drawLine(x, y) {
ctx.beginPath();
ctx.moveTo(startX, startY);
ctx.lineTo(x, y);
ctx.closePath();
ctx.stroke();
ctx.restore();
}
canvas.onmousedown = function (e) {
ctx.save();
e.preventDefault();
e.stopPropagation();
startX = parseInt(e.clientX - offsetX);
startY = parseInt(e.clientY - offsetY);
isDown = true;
}
canvas.onmousemove = function (e) {
if (!isDown) {
return;
}
e.preventDefault();
e.stopPropagation();
mouseX = parseInt(e.clientX - offsetX);
mouseY = parseInt(e.clientY - offsetY);
drawLine(mouseX, mouseY);
}
canvas.onmouseup = function (e) {
if (!isDown) {
return;
}
e.preventDefault();
e.stopPropagation();
isDown = false;
}
The issue now is that, the drag creates a series of lines instead of one.
I have tried to save the context before drawing and restore it after drawing, but didn't help.
Note that, I cannot clear the canvas using clearRect(), as my image data will be lost.
Here, I have used a dummy image.
I have created a fiddle.
Any help would be appreciated.
Regards,
Rohith
One way of doing it is to save all your drag-lines in an array of drag-lines.
That way you can clear the canvas and redraw the image and redraw all the accumulated lines.
Example code and a Demo: http://jsfiddle.net/m1erickson/bH38a/
The green lines are my (totally non-medical !) additions.
BTW, this example reduces the opacity of the background image so the lines are more visible (a handy technique).
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{
border:1px solid red;
}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var startX,startY,mouseX,mouseY;
var isDown=false;
var lines=[];
var imageOpacity=0.33;
var img=new Image();
img.crossOrigin="anonymous";
img.onload=start;
img.src="https://dl.dropboxusercontent.com/u/139992952/multple/heart.jpg";
function start(){
canvas.width=canvas.width=img.width;
canvas.height=img.height;
ctx.strokeStyle="green";
ctx.lineWidth=3;
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseUp(e);});
// redraw the image
drawTheImage(img,imageOpacity);
}
function drawLines(toX,toY){
// clear the canvas
ctx.clearRect(0,0,canvas.width,canvas.height);
// redraw the image
drawTheImage(img,imageOpacity);
// redraw all previous lines
for(var i=0;i<lines.length;i++){
drawLine(lines[i]);
}
// draw the current line
drawLine({x1:startX,y1:startY,x2:mouseX,y2:mouseY});
}
function drawTheImage(img,opacity){
ctx.globalAlpha=opacity;
ctx.drawImage(img,0,0);
ctx.globalAlpha=1.00;
}
function drawLine(line){
ctx.beginPath();
ctx.moveTo(line.x1, line.y1);
ctx.lineTo(line.x2, line.y2);
ctx.stroke();
}
function handleMouseDown(e){
e.stopPropagation();
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
startX=mouseX;
startY=mouseY;
isDown=true;
}
function handleMouseUp(e){
e.stopPropagation();
e.preventDefault();
// Put your mouseup stuff here
isDown=false;
lines.push({x1:startX,y1:startY,x2:mouseX,y2:mouseY});
}
function handleMouseMove(e){
if(!isDown){return;}
e.stopPropagation();
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
drawLines(mouseX,mouseY);
}
$("#save").click(function(){
var html="<p>Right-click on image below and Save-Picture-As</p>";
html+="<img src='"+canvas.toDataURL()+"' alt='from canvas'/>";
var tab=window.open();
tab.document.write(html);
});
}); // end $(function(){});
</script>
</head>
<body>
<h4>Drag-draw lines.</h4>
<button id="save">Export Image</button><br>
<canvas id="canvas"></canvas>
</body>
</html>

How to differentiate click and mousedown event in JavaScript?

I have a canvas, I want to draw dots when user clicked and draw a line when clicked and dragged.
In order to identify whether I should generate a line when mouse is moving on the canvas, I set a variable 'isDrawing' to tell if the user has clicked on the canvas before moving on it. I bind 'mousedown' event to the canvas and set 'isDrawing' to true when the event is triggered. If it is true I will start drawing a line, otherwise I will do nothing to this behavior. But the problem is when user clicked to draw dots, the 'isDrawing' is also set to true because the 'mousedown' event is triggered by the click. My question is how to differentiate the click and mousedown event so that when user just clicked somewhere the 'mousedown' event will not be triggered? thanks.
#Aaron has the start of a good idea...Add your dot in mouseup instead of mousedown.
In mouseup if the mouse has been dragged less than 5 total pixels then treat the mouseup as a click rather than a drag. (5 pixels is an example--adjust for your desired tolerances).
In mousemove, delay drawing your line until the mouse has been dragged at least 5 pixels.
Here's example code and a Demo: http://jsfiddle.net/m1erickson/ZTuKP/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
var isDown=false;
var lastX,lastY;
var dragHash;
function handleMouseDown(e){
e.preventDefault();
e.stopPropagation();
lastX=parseInt(e.clientX-offsetX);
lastY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
dragHash=0;
isDown=true;
}
function handleMouseUp(e){
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
if(dragHash<5){
alert("It's a click...add a dot");
}else{
alert("You've been dragging");
}
// Put your mouseup stuff here
isDown=false;
}
function handleMouseMove(e){
if(!isDown){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-lastX;
var dy=mouseY-lastY;
lastX=mouseX;
lastY=mouseY;
// accumulate the drag distance
// (used in mouseup to see if this is a drag or click)
dragHash+=Math.abs(dx)+Math.abs(dy);
if(dragHash>4){
// it's a drag operation, draw the line
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Here's an example using pure javascript small and compact: http://jsfiddle.net/kychan/2t97S/
function e(id) { return document.getElementById(id); }
var box = e('box'),
ctx = box.getContext('2d'),
w = box.width,
h = box.height,
mx = 0,
my = 0
;
ctx.fillStyle = '#333';
ctx.fillRect(0,0,w,h);
ctx.fillStyle = '#FF0000';
ctx.strokeStyle= '#FF0000';
box.addEventListener('mousedown', function(e) {
mx = e.pageX - box.offsetLeft,
my = e.pageY - box.offsetTop;
}, false);
// reduces dender.
function d(i,c) {
return (c-10<i && c+10>i);
}
box.addEventListener('mouseup', function(e) {
var nx = e.pageX - box.offsetLeft,
ny = e.pageY - box.offsetTop;
ctx.beginPath();
if (d(mx,nx) && d(my,ny)) {
ctx.arc(mx,my,1, 0, Math.PI*2, false);
}else{
ctx.moveTo(mx, my);
ctx.lineTo(nx, ny);
}
ctx.closePath();
ctx.stroke();
mx=nx, my=ny;
}, false);

How can I drag a piece of user generated text around the HTML5 canvas?

Basically what I have coded is the ability to type a word into a text box. When a button is pressed to submit it that word is then posted to the HTML5 canvas so people can see it. What I want to do now is to have the ability to drag that word around the HTML5 canvas. I'm having slightly difficulty in achieving this and was wondering if someone could help me with this please? Here's my code what I've done so far:
var fname;
var canvas;
var ctx;
var canvasX;
var canvasY;
var mouseIsDown;
function addTitle2() {
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
canvas.addEventListener("mousedown", mouseDown, false);
canvas.addEventListener("mousemove", mouseXY, false);
document.body.addEventListener("mouseup", mouseUp, false);
var fname = document.forms[0].fname.value;
ctx.fillStyle = "black";
ctx.strokeStyle = "black";
ctx.font = "35px Arial";
ctx.fillText(fname, Math.random() * 500, Math.random() * 400);
ctx.stroke();
}
function mouseUp() {
mouseIsDown = 0;
mouseXY();
}
function mouseDown() {
mouseIsDown = 1;
mouseXY();
}
function mouseXY(e) {
e.preventDefault();
canvasX = e.pageX - canvas.offsetLeft;
canvasY = e.pageY - canvas.offsetTop;
ShowPos();
}
function ShowPos() {
if(mouseIsDown) {
ctx.fillText(fname, canvasX, canvasY);
}
}
Dragging text is largely responding to mouse events.
A Demo: http://jsfiddle.net/m1erickson/9xAGa/
First create text objects to refer to
// some text objects
var texts=[];
// some test texts
texts.push({text:"Hello",x:20,y:20});
texts.push({text:"World",x:20,y:70});
In mousedown
Iterate through each text object and see if the mouse is inside.
// handle mousedown events
// iterate through texts[] and see if the user
// mousedown'ed on one of them
// If yes, set the selectedText to the index of that text
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
for(var i=0;i<texts.length;i++){
if(textHittest(startX,startY,i)){
selectedText=i;
}
}
}
// test if x,y is inside the bounding box of texts[textIndex]
function textHittest(x,y,textIndex){
var text=texts[textIndex];
return(x>=text.x &&
x<=text.x+text.width &&
y>=text.y-text.height &&
y<=text.y);
}
In mousemove
Change the selected text's x,y by the distance the mouse has been dragged:
// handle mousemove events
// calc how far the mouse has been dragged since
// the last mousemove event and move the selected text
// by that distance
function handleMouseMove(e){
if(selectedText<0){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
var text=texts[selectedText];
text.x+=dx;
text.y+=dy;
draw();
}
In mouseup
The drag is over:
// done dragging
function handleMouseUp(e){
e.preventDefault();
selectedText=-1;
}
Annotated Code:
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
#theText{width:10em;}
</style>
<script>
$(function(){
// canvas related variables
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
// variables used to get mouse position on the canvas
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var scrollX=$canvas.scrollLeft();
var scrollY=$canvas.scrollTop();
// variables to save last mouse position
// used to see how far the user dragged the mouse
// and then move the text by that distance
var startX;
var startY;
// an array to hold text objects
var texts=[];
// this var will hold the index of the hit-selected text
var selectedText=-1;
// clear the canvas & redraw all texts
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<texts.length;i++){
var text=texts[i];
ctx.fillText(text.text,text.x,text.y);
}
}
// test if x,y is inside the bounding box of texts[textIndex]
function textHittest(x,y,textIndex){
var text=texts[textIndex];
return(x>=text.x &&
x<=text.x+text.width &&
y>=text.y-text.height &&
y<=text.y);
}
// handle mousedown events
// iterate through texts[] and see if the user
// mousedown'ed on one of them
// If yes, set the selectedText to the index of that text
function handleMouseDown(e){
e.preventDefault();
startX=parseInt(e.clientX-offsetX);
startY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
for(var i=0;i<texts.length;i++){
if(textHittest(startX,startY,i)){
selectedText=i;
}
}
}
// done dragging
function handleMouseUp(e){
e.preventDefault();
selectedText=-1;
}
// also done dragging
function handleMouseOut(e){
e.preventDefault();
selectedText=-1;
}
// handle mousemove events
// calc how far the mouse has been dragged since
// the last mousemove event and move the selected text
// by that distance
function handleMouseMove(e){
if(selectedText<0){return;}
e.preventDefault();
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
var dx=mouseX-startX;
var dy=mouseY-startY;
startX=mouseX;
startY=mouseY;
var text=texts[selectedText];
text.x+=dx;
text.y+=dy;
draw();
}
// listen for mouse events
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
$("#submit").click(function(){
// calc the y coordinate for this text on the canvas
var y=texts.length*20+20;
// get the text from the input element
var text={text:$("#theText").val(),x:20,y:y};
// calc the size of this text for hit-testing purposes
ctx.font="16px verdana";
text.width=ctx.measureText(text.text).width;
text.height=16;
// put this new text in the texts array
texts.push(text);
// redraw everything
draw();
});
}); // end $(function(){});
</script>
</head>
<body>
<input id="theText" type="text">
<button id="submit">Draw text on canvas</button><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
Create a transparent div over canvas and position it such a way that it cover only area you filled with text. Make this div draggable. On div position change clear canvas and redraw text on canvas based on new position of div.
You should repeat all fillText stuff when mouse is down, also clear the screen before every draw
function drawText() {
ctx.clearRect(0, 0, 500, 400);
ctx.fillStyle = "black";
ctx.strokeStyle = "black";
ctx.font = "35px Arial";
ctx.fillText(fname, canvasX, canvasY);
ctx.stroke();
}
Here's a jsfiddle
Okay so I just want to point out one problem in the following jsfiddle solution by markE
Dragging text is largely responding to mouse events
the problem is that if your page doesn't fit the window and is scrollable if you have scrolled your page and now you are dragging the text, it won't work because the mouse event will return clientY that couldn't calculate the saved coordinates.
Reproduce by giving height as
<canvas id="canvas" width=300 height=3000></canvas>
and drag text after scrolling.

Canvas size in HTML5

I have this code in my project, here is the link: http://jsfiddle.net/89wgk/
This is my code:
<canvas id="myCanvas" width="188" height="200"></canvas>
var rectWidth = 110;
var rectHeight = 110;
var rectX = 10;
var rectY = 25;
When I put the mouse in curved rectangle starts the shadow, but I want that to happen when I put the mouse over the reeds (rectangle) and not within the canvas.
I wonder how do I run the shadow so when I move the mouse over the rectangle?
Here is how I would do it:
create a function that draws the arc shape because it must be redrawn often
listen for mouseMove events on the canvas
test whether the mouse is inside the arc with context.isPointInside(mouseX,mouseY)
redraw the arc with/without the shadow based on if the mouse is inside the arc
Have Fun!
Here is code and a Fiddle: http://jsfiddle.net/m1erickson/64BHx/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
#canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var context=canvas.getContext("2d");
var $canvas=$("#canvas");
var canvasOffset=$canvas.offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var w = 110;
var h = 110;
var x = 10;
var y = 25;
var isShadowed=false;
context.strokeStyle="#FF2A2A";
context.shadowBlur = 20;
context.shadowOffsetX = 5;
context.shadowOffsetY = 5;
context.globalAlpha=.250;
context.strokeRect(x,y,w,h);
context.globalAlpha=1.00;
function draw(){
// clear the canvas
context.clearRect(0,0,canvas.width,canvas.height);
// save the context state
context.save();
// set/clear the shadow based on isShadowed
context.shadowColor= isShadowed ? '#7FD4FF' : "#FFFFFF";
// draw the arc shape
context.beginPath();
context.moveTo(x,y);
context.quadraticCurveTo(x+w-2,y+2,x+w,y+h);
context.lineTo(x+w-35,y+h);
context.quadraticCurveTo(x+w-2-35,y+2+35,x,y+35);
context.lineTo(x,y);
context.fillStyle="red";
context.fill();
context.stroke();
// restore the context state
context.restore();
}
// testing: display if mouse is in/out of arc shape
var $status=$("#status");
// listen for mousemove events
$("#canvas").mousemove(function(e){handleMouseMove(e);});
// handle mousemove events
function handleMouseMove(e){
// we alone are using mousemove events
e.preventDefault();
// get current mouse X/Y
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// hit test if mouse is inside the arc shape
var isInside=context.isPointInPath(mouseX,mouseY);
$status.text("Is mouse inside: "+isInside);
// don't redraw unless needed
if(isInside && isShadowed){return;}
if(!isInside && !isShadowed){return;}
// change the shadow and redraw
isShadowed=isInside;
draw();
}
// start by drawing the unshadowed arc
draw();
}); // end $(function(){});
</script>
</head>
<body>
<p id="status">Status</p><br>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

canvas drag and drop with multiple items

I am creating a multiple item drag and drop for a project and have a reached a wall.
At present I have 5 square items I have added to the canvas and also stored there x, y, width, height, bgcolour into an array called items. I have detected when the mouse selects one of these squares and can drag an item around. However my issue is that the item I am dragging around is always the same item, the first one added to the canvas. If anybody could help me work out how to detect which item specifically I have selected that would be great.
There is a'lot of code so I will try and post only the required bits.
//Items are added to canvas and values added to items[];
//a click event runs when the canvas is clicked, the following code is then run
var mouseCheck = function(e) {
var length = items.length;
var pos = $('#scalesPlatform').offset(),
top = pos.top,
left = pos.left,
mx = e.pageX - left,
my = e.pageY - top;
var imagedata = ctx.getImageData(mx, my, 1, 1);
if (imagedata.data[3] > 0) {
for (var i = length - 1; i >= 0; i--) {
var hit = items[i];
offsetX = mx - items[i].x;
offsetY = my - items[i].y;
hit.x = mx - offsetX;
hit.y = my - offsetY;
canvas.addEventListener('mousemove', function() {
move(hit, drag, items, event);
});
canvas.addEventListener('mouseup', function() {
drag = false;
move(hit, drag, event);
});
}
}
}
The issue is I need the variable hit to equal the item I have selected.
Any help would be greatly apprecaited.
Here’s how to drag/drop with multiple items
You have your squares defined in objects:
var items=[]
items.push({x:0,y:10,width:50,height:50,color:"red",isDragging:false});
items.push({x:70,y:10,width:50,height:50,color:"green",isDragging:false});
items.push({x:140,y:10,width:50,height:50,color:"blue",isDragging:false});
So you can hit test like this to detect which item(s) will be dragged:
function setDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
// if x/y hit this item, set it’s isDragging flag
if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
item.isDragging=true;
}
}
}
Your mousemove handler calculates the distance of the drag.
dragX=mouseX-startX;
dragY=mouseY-startY;
Then in your draw() function you can handle both dragging and non-dragging items.
Items being dragged will be drawn at their original position plus dragX/dragY.
if(item.isDragging){
ctx.rect(item.x+dragX,item.y+dragY,item.width,item.height);
}else{
ctx.rect(item.x,item.y,item.width,item.height);
}
Here is example code and a Fiddle: http://jsfiddle.net/m1erickson/62L9q/
<!doctype html>
<html>
<head>
<link rel="stylesheet" type="text/css" media="all" href="css/reset.css" /> <!-- reset css -->
<script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script>
<style>
body{ background-color: ivory; }
canvas{border:1px solid red;}
</style>
<script>
$(function(){
var canvas=document.getElementById("canvas");
var ctx=canvas.getContext("2d");
var canvasOffset=$("#canvas").offset();
var offsetX=canvasOffset.left;
var offsetY=canvasOffset.top;
var isMouseDown=false;
var startX;
var startY;
var dragX;
var dragY;
var items=[]
items.push({x:0,y:10,width:50,height:50,color:"red",isDragging:false});
items.push({x:70,y:10,width:50,height:50,color:"green",isDragging:false});
items.push({x:140,y:10,width:50,height:50,color:"blue",isDragging:false});
draw();
function draw(){
ctx.clearRect(0,0,canvas.width,canvas.height);
for(var i=0;i<items.length;i++){
var item=items[i];
if(isMouseDown){
}
ctx.beginPath();
if(item.isDragging){
ctx.rect(item.x+dragX,item.y+dragY,item.width,item.height);
}else{
ctx.rect(item.x,item.y,item.width,item.height);
}
ctx.fillStyle=item.color
ctx.fill();
}
}
function setDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
if(x>=item.x && x<=item.x+item.width && y>=item.y && y<=item.y+item.height){
item.isDragging=true;
}
}
}
function clearDragging(x,y){
for(var i=0;i<items.length;i++){
var item=items[i];
if(item.isDragging){
items[i].isDragging=false;
item.x+=dragX;
item.y+=dragY;
}
}
}
function handleMouseDown(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousedown stuff here
startX=mouseX;
startY=mouseY;
setDragging(startX,startY);
isMouseDown=true;
}
function handleMouseUp(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseup stuff here
isMouseDown=false;
clearDragging();
}
function handleMouseOut(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mouseOut stuff here
isMouseDown=false;
clearDragging();
}
function handleMouseMove(e){
mouseX=parseInt(e.clientX-offsetX);
mouseY=parseInt(e.clientY-offsetY);
// Put your mousemove stuff here
if(isMouseDown){
dragX=mouseX-startX;
dragY=mouseY-startY;
draw(mouseX,mouseY);
}
}
$("#canvas").mousedown(function(e){handleMouseDown(e);});
$("#canvas").mousemove(function(e){handleMouseMove(e);});
$("#canvas").mouseup(function(e){handleMouseUp(e);});
$("#canvas").mouseout(function(e){handleMouseOut(e);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>

Categories

Resources