问题
I draw an element onto a canvas as a string. I then want to be able to click the element (or tap on a mobile device) and drag it around. What I have now is:
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="bootstrap.min.css" />
<link type="text/css" rel="stylesheet" href="stylesheet.css"/>
<script src="jquery-1.11.0.js"></script>
</head>
<body>
<canvas id="canvas1" width="662" height="983">
<script src="jquery-1.11.0.js"></script>
</canvas>
<script>
var chosenChord=""; //this gets updated at various times by excluded code, but that code works, because the chord does always print correctly below
` $("button").click(function() {
canvas = document.getElementById('canvas1');
canvas1.addEventListener('click', on_canvas_click, false);
function on_canvas_click(ev) {
x = ev.clientX - canvas1.offsetLeft-40;
y = ev.clientY - canvas1.offsetTop;
//add to canvas
var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
context.fillStyle = "blue";
context.font = "bold 16px Arial";
context.fillText([theString], [x], [y]);
});
});
</script>
</body>
</html>
What do I need to add in order to enable this drag functionality?
回答1:
Here's an outline of how to drag an element on canvas
A Demo: http://jsfiddle.net/m1erickson/AGd6u/
Listen for mouse events: mousedown, mousemove, mouseup, mouseout
// 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);});
Define your pieces of text as objects in an array
// 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:
- Test if the mouse is over the text
If yes, select that text for dragging
// 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; } } }
In mousemove:
- change the position of the selected text by the distance the user has dragged
redraw the canvas
// 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 so deselect the text
// done dragging function handleMouseUp(e){ e.preventDefault(); selectedText=-1; }
Example 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 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;
// some text objects
var texts=[];
// some test texts
texts.push({text:"Hello",x:20,y:20});
texts.push({text:"World",x:20,y:70});
// calculate width of each text for hit-testing purposes
ctx.font="16px verdana";
for(var i=0;i<texts.length;i++){
var text=texts[i];
text.width=ctx.measureText(text.text).width;
text.height=16;
}
// this var will hold the index of the selected text
var selectedText=-1;
// START: draw all texts to the canvas
draw();
// clear the canvas draw 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);});
}); // end $(function(){});
</script>
</head>
<body>
<canvas id="canvas" width=300 height=300></canvas>
</body>
</html>
回答2:
I think the answer by @markE is really good. I would just like to add my 2c though.
Working with canvas directly can become daunting very quickly, as you have to do all sorts of state management on your own.
I think it's wise when you want to do something like this to rather utilize one of the many amazing frameworks out there that aims to make vector drawing on canvas easier.
To name but a few:
- paper.js (I've created a screencast on paperjs -> http://tagtree.tv/canvas-with-paper-js)
- easeljs
- kineticjs
来源:https://stackoverflow.com/questions/21605942/drag-element-on-canvas