2

Based on Creating an HTML 5 canvas painting application I created a HTML5 canvas painting application. It works fine, but after creating each object I just need to drag the objects. Working demo

How to implement drag and drop of the figures?

Jonas
  • 121,568
  • 97
  • 310
  • 388
ramesh
  • 4,008
  • 13
  • 72
  • 117

5 Answers5

3

When the user clicks on the canvas, you have to check the coordinates (compare it to the coordinates for the objects), and see if it's on an object. E.g. You can test if a point (e.g. the coordinates for the mousedown even) is within a circle with this method:

function (pt) {
    return Math.pow(pt.x - point.x,2) + Math.pow(pt.y - point.y,2) < 
                                                             Math.pow(radius,2); 
};

If the mousedown is on the object, you have to change the objects coordinates according to how the mouse is moved.

Here is an example, where you can drag a circle:

<!DOCTYPE html>
<html>
<head>
<script>
window.onload = function() {
    drawCircle(circle);
    element = document.getElementById('canvas');
    element.addEventListener('mousedown', startDragging, false);
    element.addEventListener('mousemove', drag, false);
    element.addEventListener('mouseup', stopDragging, false);
    element.addEventListener('mouseout', stopDragging, false);
}

function mouseX(e) {
return e.clientX - element.offsetLeft;
}

function mouseY(e) {
return e.clientY - element.offsetTop;
}

var Point = function (x, y) {
    this.x = x;
    this.y = y;
    return this;
}

var Circle = function (point, radius) {
    this.point = point;
    this.radius = radius;
    this.isInside = function (pt) {
        return Math.pow(pt.x - point.x, 2) + Math.pow(pt.y - point.y, 2) <
                                                          Math.pow(radius, 2); 
    };
    return this;
}

function startDragging(e) {
    var p = new Point(e.offsetX, e.offsetY);
    if(circle.isInside(p)) {
        deltaCenter = new Point(p.x - circle.point.x, p.y - circle.point.y);
    }
}

function drag(e) {
    if(deltaCenter != null) {
        circle.point.x = (mouseX(e) - deltaCenter.x);
        circle.point.y = (mouseY(e) - deltaCenter.y);   
        drawCircle(circle);
    }
}

function stopDragging(e) {
    deltaCenter = null;
}

function drawCircle(circle) {
    var canvas = document.getElementById('canvas');
    var ctx = canvas.getContext('2d');
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    ctx.beginPath();
    ctx.arc(circle.point.x, circle.point.y, circle.radius, 0, Math.PI*2, true);
    ctx.fill();
}

var circle = new Circle(new Point(30, 40), 25);
var deltaCenter = null;
var element;

</script>
</head>
<body>
<canvas id="canvas" width="400" height="300"></canvas>
</body>
</html>

Try it on jsFiddle

Jonas
  • 121,568
  • 97
  • 310
  • 388
  • Hi jonas .. thanks for the reply and how to get the coordinates of the shapes ? – ramesh Dec 07 '11 at 07:53
  • @rajeeesh: you need to save them yourself. – Jonas Dec 07 '11 at 08:14
  • Hi this is the function I m using for add an image ... How to save the coordingtes ? this.mouseup = function (ev) { if (tool.started) { tool.mousemove(ev); var x=ev._x-28; var y=ev._y-28; var imageObj = new Image(); imageObj.onload = function(){ var p=context.drawImage(imageObj, x, y); }; imageObj.src = "test.png"; tool.started = false; img_update(); } }; – ramesh Dec 07 '11 at 09:05
3

The same effect can be accomplished using Raphael.js (http://raphaeljs.com/) with Joint.jS (http://www.jointjs.com/).

Shapes created with Raphael can be accessed like any DOM element and can be manipulated via attributes. It is an awesome framework.

Joint.js helps in connecting the shapes. They also have a diagramming library and can help create ERD, Statemachine and several common diagrams. The best part is that you can extend their diagram element and create your own custom elements. Its jaw-dropingly cool.

Checkout their demos with source code at http://www.jointjs.com/demos

Marcel Liker
  • 93
  • 1
  • 9
Srikanth
  • 586
  • 4
  • 11
2

If you are using the raphael as "raw" lib you must handle the undo/redo by yourself. The graphiti lib did have Undo/Redo Stack inside and supports the export for SVG, PNG, JSON,...

Additional you have some kind of Viso like connectors and ports.

http://www.draw2d.org/graphiti/jsdoc/#!/example

Greetings

1

I don't think there's an easy way to do this.

If you're just dealing with lines, my approach would be to keep track of all lines created, with starting coordinates, ending coordinates and some kind of z-index. When the user starts a dragging action (onmousedown), you have to check if the point is near the line, and then update the object and redraw the canvas when the mouse is moved.

How can I tell if a point belongs to a certain line?

This gets a lot more complicated if you're dealing with complex objects though. You'll probably have to find a solution to check if a point is inside a path.

Community
  • 1
  • 1
amiuhle
  • 2,673
  • 1
  • 19
  • 28
1

Objects drawn into HTML5 Canvas are turned into pixels and then forgotten. You can't adjust properties on them and have the canvas update to see the effects. You can remember them yourself, but the canvas will still have those pixels set, so you'd have to basically redraw the whole canvas (or at least some of it) when you adjust a property.

You might want to consider SVG for this application instead, SVG elements are remembered in the DOM and when their properties are updated the browser will update the graphic to reflect the changes.

If you must use canvas, then you're going to need to write quite a bit of code to handle mouse-hits, object properties, and repaints.

James Clark
  • 1,765
  • 13
  • 17
  • Hi james thanks for your reply and you got any sample or tutorial for that ? Am I need to re-code my application or I can upgrade this for my requirement ? Thanks – ramesh Dec 07 '11 at 03:39
  • 1
    Off the top of my head I don't know of any link with examples or tutorials for that kind of stuff. There are libraries like Paper.js or KineticJS which are vector-graphics wrappers around canvas, that might be a good place to start reading. I think you'll have to do _some_ recoding either way, but if you use a library, maybe not as much. SVG would be a big change, and writing your own vector graphics code would be a big change too. – James Clark Dec 07 '11 at 04:51
  • 1
    As Srikanth pointed toward, Raphael.js is a vector-graphics library too, though it uses SVG and not canvas as the back-end. – James Clark Dec 07 '11 at 04:51