Drag-n-Drop with HTML Canvas

This example shows how to implement drag-&-drop in a HTML Canvas using javascript. It’s done using plain old Javascript, i.e. without using any libraries like JQuery or moo-tools etc.

The main pitfall to look out for is any scaling done as a result of CSS sizing. The actual width and height of any visual element as calculated by the browser is a combination of all styles that match the element, and as such it may differ from the size specified in the html attribute, as well as to that of any single CSS definition. You should get this in JavaScript using the offsetWidth, and offsetHeight properties of the object.

Anyway, here is the code for the example …

HTML

<canvas id="canvas" width="400" height="300"></canvas>
<div id="status"></div>

CSS


#canvas
{
width:500px;
height:500px;
margin:50px;
}

#status
{
margin:10px;
padding:2px;
background-color:rgb(200,200,200);
border:1px inset rgb(150,150,150);
font:10px verdana;
}

Javascript


var canvas;
var ctx;
var status;

var isMouseDown = false;

// Canvas Dimensions
var cw = 0;
var ch = 0;

// Puck Dimensions (and Half thereof)
var pw = 30;
var ph = 30;
var pw2 = 0;
var ph2 = 0;

// Puck Position
var px = 50;
var py = 100;

// cursor offset relative to the puck
var cx = 0;
var cy = 0;

// Attr:Actual dimensions Scale
var sx = 1.0;
var sy = 1.0;

function Init()
{
canvas = document.getElementById("canvas");
ctx = canvas.getContext("2d");
status = document.getElementById("status");

cw = canvas.width;
ch = canvas.height;

// get the scale based on actual width;
sx = cw / canvas.offsetWidth;
sy = ch / canvas.offsetHeight;

// Rescale the puck
pw = pw * sx;
ph = ph * sy;
pw2 = pw/2;
ph2 = ph/2;

// Rescale the puck position
px = px * sx;
py = py * sy;

status.innerHTML = "Attr:" + canvas.width + "," + canvas.height
+ "; Actual:" + canvas.offsetWidth + "," + canvas.offsetHeight
+ "; Scale:" + sx + "," + sy
+ "; Puck:" + pw + "," + ph;

canvas.onmouseup = MouseUp;
canvas.onmousedown = MouseDown;
canvas.onmousemove = MouseMoved;

return setInterval(Repaint, 10); // repaint the canvas at intervals
}

function Repaint()
{
// Clear the canvas
ctx.clearRect(0, 0, cw, ch);

// Draw the background
DrawRect(0, 0, cw, ch, "rgb(220,220,190)");

// Draw the puck
DrawRect(px, py, pw, ph, "blue");
}

function DrawRect(x, y, w, h, colour)
{
ctx.fillStyle = colour;
ctx.beginPath();
ctx.rect(x, y, w, h);
ctx.closePath();
ctx.fill();
}

function MouseMoved(e)
{
status.innerHTML = "Cursor[" + e.pageX + ", " + e.pageY + "], Offset["
+ (e.pageX - canvas.offsetLeft) + ", " + (e.pageY - canvas.offsetTop) + "]";

if ( IsCursorOverPuck(e.pageX, e.pageY) )
{
document.body.style.cursor = 'pointer';
}
else
{
document.body.style.cursor = 'default';
}

if (isMouseDown)
{
px = (e.pageX - canvas.offsetLeft)*sx - cx*sx;
py = (e.pageY - canvas.offsetTop)*sy - cy*sy;

status.innerHTML = "mouse down. Offset[" + cx + ", " + cy + "], Puck[" + px + ", " + py + "]";
}

}

function MouseUp()
{
isMouseDown = false;
}
function MouseDown(e)
{
if ( IsCursorOverPuck(e.pageX, e.pageY) )
{
cx = (e.pageX - canvas.offsetLeft)*sx - px;
cy = (e.pageY - canvas.offsetTop)*sy - py;
isMouseDown = true;
}
}

function IsCursorOverPuck(x, y)
{
status.innerHTML = "Cursor[" + x + ", " + y + "], CanvasOffset["
+ (x - canvas.offsetLeft) + ", " + (y - canvas.offsetTop) + "], Puck["
+ px + ", " + py + "]";

return (x - canvas.offsetLeft) * sx > px && (x - canvas.offsetLeft) * sx < px + pw && (y - canvas.offsetTop) * sy > py && (y - canvas.offsetTop) * sy < py + ph; } Init();

You can check the demo here.

Author: Musaul Karim

Software Engineer, Hobbyist Photographer, and a bit of a gadget geek.

1 thought on “Drag-n-Drop with HTML Canvas”

Leave a Reply

Your email address will not be published. Required fields are marked *