I'm looking for the fastest and lightest way to drag and drop shapes and sprites on a JS Canvas for game-development purposes.
I've started by doing distance checks using the current mouse position and the origins of circles. It works, but when they overlap we have problems and I don't know how well this will work when testing for multiple sprites and other shapes yet on each 'frame'.
Any ments or pointers to better methods are appreciated!
I'd rather not use a library like jQuery since I'm going for pure speed and lightness and of course to learn the actual methods! Here's where I'm at:
//add the canvas listeners and functions
canvas.addEventListener("mousemove",mousemove);
canvas.addEventListener("mousedown",mousedown);
canvas.addEventListener("mouseup",mouseup);
function mousemove(e){
mouseX = e.layerX - canvas.offsetLeft;
mouseY = e.layerY - canvas.offsetTop;
//for each circle stored in my array of Circle objects, is my mouse within its'
//bounds? If so, set the circles' (X,Y) to my mouse's (X,Y)
for(i=0;i<circArray.length;i++){
dx = mouseX - circArray[i].x;
dy = mouseY - circArray[i].y;
dist = Math.sqrt((dx*dx) + (dy*dy));
if(draggable && dist < circArray[i].r){
circArray[i].x = mouseX;
circArray[i].y = mouseY;
}
}
}
function mousedown(){
draggable = true;
}
function mouseup(){
draggable = false;
}
I'm looking for the fastest and lightest way to drag and drop shapes and sprites on a JS Canvas for game-development purposes.
I've started by doing distance checks using the current mouse position and the origins of circles. It works, but when they overlap we have problems and I don't know how well this will work when testing for multiple sprites and other shapes yet on each 'frame'.
Any ments or pointers to better methods are appreciated!
I'd rather not use a library like jQuery since I'm going for pure speed and lightness and of course to learn the actual methods! Here's where I'm at:
//add the canvas listeners and functions
canvas.addEventListener("mousemove",mousemove);
canvas.addEventListener("mousedown",mousedown);
canvas.addEventListener("mouseup",mouseup);
function mousemove(e){
mouseX = e.layerX - canvas.offsetLeft;
mouseY = e.layerY - canvas.offsetTop;
//for each circle stored in my array of Circle objects, is my mouse within its'
//bounds? If so, set the circles' (X,Y) to my mouse's (X,Y)
for(i=0;i<circArray.length;i++){
dx = mouseX - circArray[i].x;
dy = mouseY - circArray[i].y;
dist = Math.sqrt((dx*dx) + (dy*dy));
if(draggable && dist < circArray[i].r){
circArray[i].x = mouseX;
circArray[i].y = mouseY;
}
}
}
function mousedown(){
draggable = true;
}
function mouseup(){
draggable = false;
}
Share
Improve this question
edited Dec 16, 2011 at 1:14
Jonas
129k102 gold badges327 silver badges405 bronze badges
asked Dec 16, 2011 at 0:26
VerneVerne
711 gold badge1 silver badge2 bronze badges
2
- 1 You're thinking of jQuery UI draggables (jqueryui./demos/draggable). Even if you don't go with jQuery I would highly advise checking out an unminified version and see what they do. The developers have definitely thought through some of these performance issues. Because of the liberal license you can likely cut out a small piece of the codebase. – buley Commented Dec 16, 2011 at 0:35
- 1 You may want to look at fabric.js. Here's a demo: kangax.github./fabric.js/stickman – Jim Schubert Commented Dec 16, 2011 at 1:18
1 Answer
Reset to default 3Here's the setup I've used for dragging a single item. I can't tell if you want to drag multiple things or not, that'd be a slight modification.
In words: in mousedown search for a hit object in the reserved order you drew the objects (so the topmost item gets hit first), store this hit item, then mousedrag is simply piping the coords/delta to that item.
//start with only the mousedown event attached
canvas.addEventListener("mousedown",mousedown);
//and some vars to track the dragged item
var dragIdx = -1;
var dragOffsetX, dragOffsetY;
function mousedown(e){
//...calc coords into mouseX, mouseY
for(i=circArray.length; i>=0; i--){ //loop in reverse draw order
dx = mouseX - circArray[i].x;
dy = mouseY - circArray[i].y;
if (Math.sqrt((dx*dx) + (dy*dy)) < circArray[i].r) {
//we've hit an item
dragIdx = i; //store the item being dragged
dragOffsetX = dx; //store offsets so item doesn't 'jump'
dragOffsetY = dy;
canvas.addEventListener("mousemove",mousemove); //start dragging
canvas.addEventListener("mouseup",mouseup);
return;
}
}
}
function mousemove(e) {
//...calc coords
circArray[dragIdx].x = mouseX + dragOffsetX; //drag your item
circArray[dragIdx].y = mouseY + dragOffsetY;
//...repaint();
}
function mouseup(e) {
dragIdx = -1; //reset for next mousedown
canvas.removeListener(.... //remove the move/up events when done
}
My js is rusty at the moment but this should give the idea. The dragOffsetX/Y is used to keep the item from jumping to the cursor when clicked. You could also just store the old mouse coordinate and add a delta to your item.
Also, instead of storing an index to your drag item you could store a reference to it, or maybe an array of references to drag multiple items. And instead of directly manipulating your items you could put a mousedown/drag/up interface on them to let them handle it. This'll make it easier to mix in other types of items.
Another thing I'm not sure about is how you're calculating your coordinates. I do something different but it's older code and I'm guessing your way measures just as well. -t