3

I am a newbie to HTML5 and JavaScript, I know there's a lot of libraries can do that, but I am wondering if there's a way to do it just using plain javascript.

I have a canvas and when the canvas is clicked somewhere, there will be a little red dot appear at where the user clicked. I want to make each of the little dot draggable, any ideas on it? thanks.

Here's the code I have:

in HTML:

<div id="primal_plane" style="position:absolute; top:100px; left:10px;"> <canvas id="canvas_prime" onclick="drawDot('canvas_prime')" width="700" height="500"></canvas> </div> 

in JS file:

function drawDot(plane) { var canvas = document.getElementById(plane); var context = canvas.getContext("2d"); context.beginPath(); context.arc(mouseX * 50, mouseY * 50, 4, 0, 2 * Math.PI, false); context.fillStyle = 'green'; context.fill(); context.lineWidth = 1; context.strokeStyle = 'yellow'; context.stroke(); } 

2 Answers 2

9

To outline your solution:

  • Listen for mousedown events and either (1) create a new circle if the mouse is not over a circle or (2) start a drag operation on a circle if the mouse is over a circle.
  • Listen for mousemove events and move the dragged circle by the distance the mouse has moved since the last mousemove event
  • Listen for mouseup events and stop the drag operation

Here is annotated code and a Demo: http://jsfiddle.net/m1erickson/ytUhL/

<!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() { // canvas related variables // references to canvas and its context and its position on the page 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 cw = canvas.width; var ch = canvas.height; // flag to indicate a drag is in process // and the last XY position that has already been processed var isDown = false; var lastX; var lastY; // the radian value of a full circle is used often, cache it var PI2 = Math.PI * 2; // variables relating to existing circles var circles = []; var stdRadius = 10; var draggingCircle = -1; // clear the canvas and redraw all existing circles function drawAll() { ctx.clearRect(0, 0, cw, ch); for(var i=0; i<circles.length; i++){ var circle = circles[i]; ctx.beginPath(); ctx.arc(circle.x, circle.y, circle.radius, 0, PI2); ctx.closePath(); ctx.fillStyle = circle.color; ctx.fill(); } } function handleMouseDown(e) { // tell the browser we'll handle this event e.preventDefault(); e.stopPropagation(); // save the mouse position // in case this becomes a drag operation lastX = parseInt(e.clientX - offsetX); lastY = parseInt(e.clientY - offsetY); // hit test all existing circles var hit = -1; for (var i=0; i < circles.length; i++) { var circle = circles[i]; var dx = lastX - circle.x; var dy = lastY - circle.y; if (dx*dx + dy*dy < circle.radius * circle.radius) { hit = i; } } // if no hits then add a circle // if hit then set the isDown flag to start a drag if (hit < 0) { circles.push({x:lastX, y:lastY, radius:stdRadius, color:randomColor()}); drawAll(); } else { draggingCircle = circles[hit]; isDown = true; } } function handleMouseUp(e) { // tell the browser we'll handle this event e.preventDefault(); e.stopPropagation(); // stop the drag isDown = false; } function handleMouseMove(e) { // if we're not dragging, just exit if (!isDown) { return; } // tell the browser we'll handle this event e.preventDefault(); e.stopPropagation(); // get the current mouse position mouseX = parseInt(e.clientX - offsetX); mouseY = parseInt(e.clientY - offsetY); // calculate how far the mouse has moved // since the last mousemove event was processed var dx = mouseX - lastX; var dy = mouseY - lastY; // reset the lastX/Y to the current mouse position lastX = mouseX; lastY = mouseY; // change the target circles position by the // distance the mouse has moved since the last // mousemove event draggingCircle.x += dx; draggingCircle.y += dy; // redraw all the circles drawAll(); } // 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) { handleMouseUp(e); }); ////////////////////// // Utility functions function randomColor(){ return('#' + Math.floor(Math.random()*16777215).toString(16)); } }); // end $(function(){}); </script> </head> <body> <canvas id="canvas" width=300 height=300></canvas> </body> </html> 
Sign up to request clarification or add additional context in comments.

2 Comments

This is some fine piece of code, clear and very helpful!
Hi nice code, how would I need to change the script to draw something with my mouse on the canvas and afterwards make the drag function avaible, just do you have any idea how to resize the current clicked canvas?
0

You will have to store a list of the dots created, but you will have to check if a dot already exists. If so, set a boolean flag that identifies the dragging behavior when the mousedown event occurs and another to identify the dot being dragged. On the mouseup event clear the flag. The mousemove method should update a variable that stores the current mouse position and updates the position of the current dot being dragged. Use jQuery.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.