JS exercise 9 – Drag Square

In this exercise, we will explore how to create a drag and drop functionality. The aim is to enable dragging a square around the screen, with the option of leaving a trail or not.

This is the code for the exercise:

<!DOCTYPE html>
<html>
<head>
	<title>Drag Square</title>
	<script type="text/javascript">
	var canvas,ctx;
	var x, y, size;
	var mouseX, mouseY;
	var dragging;
	function setup(){
		//canvas setup
		canvas=document.getElementById("myCanvas");
		ctx=canvas.getContext("2d");
		//note 1-if you want a trail, draw background in setup()
		ctx.fillStyle="black";
		ctx.fillRect(0,0,canvas.width,canvas.height);
		//variables setup
		x=50;
		y=50;
		size=50;
		dragging = false;
		//function calls
		canvas.addEventListener("mousemove",doMouseMove);
		canvas.addEventListener("mousedown",doMouseDown);
		canvas.addEventListener("mouseup",doMouseUp);
		setInterval(draw,10);
	}
	function draw(){
		//note 2-if you don't want a trail, draw background in draw()
		//ctx.fillStyle="black";
		//ctx.fillRect(0,0,canvas.width,canvas.height);
		//following is the same as if(dragging==true){
		if(dragging){
			x=mouseX-size/2;
			y=mouseY-size/2;
		}
		ctx.fillStyle="rgba(255,126,0,0.1)";
		ctx.fillRect(x,y,size,size);
		ctx.strokeStyle="rgba(255,255,255,0.9)";
		ctx.strokeRect(x,y,size,size);
	}
	function doMouseMove(event){
		mouseX = event.pageX-canvas.offsetLeft;
		mouseY = event.pageY-canvas.offsetTop;
		console.log("x:"+mouseX+", y:"+mouseY);
	}
	function doMouseDown(){
		var right = x+size;
		var bottom = y+size;
		if(mouseX>x && mouseX<right && mouseY>y && mouseY<bottom){
			dragging=true;
			console.log("you clicked me!!");
		}else{
			console.log("missed it, better luck next time");
		}
	}
	function doMouseUp(){
		dragging=false;
	}
	</script>
</head>
<body onload="setup()">
	<canvas id="myCanvas" width="400" height="400" style="border:1px solid">
	</canvas>
</body>
</html>

In this exercise, we created a background – a black rectangle with the size of the canvas. Depending if we want a trail or not, we can define this background in the setup() function (trails will appear) or in the draw() function (trails will not appear as the background will be constantly redrawn, overlapping trail):

	ctx.fillStyle="black";
	ctx.fillRect(0,0,canvas.width,canvas.height);

We then use variables (declared previously) to define default position and size (height equals width in this case) for our square – x, y and size (all set to 50).

We also use a variable to determine the current dragging state of our square. By default, it is not being dragged:

	dragging = false;

Next, we create three event listeners to check for mouse actions: a mousemove listener to check position of mouse; a mousedown listener to check if the mouse button has been pressed; and a mouseup litener to check if the mouse button has been released. The functions triggered by the listeners are, respectively, doMouseMove, doMouseDown and doMouseUp:

canvas.addEventListener("mousemove",doMouseMove);
canvas.addEventListener("mousedown",doMouseDown);
canvas.addEventListener("mouseup",doMouseUp);

A setInterval is also created to run the draw() function every 10 milliseconds.

setInterval(draw,10);

The doMouseMove function checks the mouse position and stores it in variables mouseX and mouseY. For debugging, we print out these two variables to the browser JavaScript console:

mouseX = event.pageX-canvas.offsetLeft;
mouseY = event.pageY-canvas.offsetTop;
console.log("x:"+mouseX+", y:"+mouseY);

The doMouseDown function does the most important work – it checks if the user has pressed the mouse button while the cursor was inside the rectangle. If she/he has, it sets the dragging variable to true. An if clause checks this: if at the moment of mouse press 1) mouseX is greater than the left of the square (x) and 2) less than the right of the square (right), and 3) mouse Y greater than the top of the square (y) and 4)  less then the bottom of the square (bottom), then the mouse has been pressed (&& is logical and), and dragging is set to false. right and bottom are, respectively x and y plus size.

if(mouseX>x && mouseX<right && mouseY>y && mouseY<bottom){
	dragging=true;
}

The doMouseUp function will stop the dragging action, by resetting the dragging variable to false.

function doMouseUp(){
	dragging=false;
}

Inside the draw() function, the rectangle is drawn using a fillRect method, and the parameters x, y, size (for width) and again size (for height):

ctx.fillRect(x,y,size,size);

When the variable dragging is true (meaning that the mouse button has been pressed when cursor was over the square, and that the button has not been released yet), the x and y variables are updated to reflect the mouse position (mouseX and mouseY), with an adjustment to the center (the middle of the square, or size/2):

if(dragging){
	x=mouseX-size/2;
	y=mouseY-size/2;
}

Note that we can abbreviate if(dragging==true) to if(dragging).

Also note that we may need, in other cases, to make the canvas unselectable to avoid conflict with other elements in the page. More on this here, and also check the W3C reference for default actions and cancelable events, namely preventDefault().

More tutorials on this topic:

  • Introductory – How to Drag and Drop on an HTML5 Canvas by James Litten
  • Advanced – Making and Moving Selectable Shapes on an HTML5 Canvas: A Simple Example by Simon Sarris
  • More advanced – Selectable Shapes Part 2: Resizable, Movable Shapes on HTML5 Canvas by Simon Sarris

This is a screenshot of the resulting applet:

Link to the exercise: http://mlab.taik.fi/mediacode/coursefiles/course_2011_10/9-drag_square.html

Advertisements

2 thoughts on “JS exercise 9 – Drag Square

  1. Pingback: JS (extra) exercise – Simple hit test | Software Studies for Media Designers

  2. Pingback: HTML5 Canvas – Square Dragging « Valeria's blog

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s