2

I have a number of circles that i'm using as draggable buttons, i can assign drag events to these and it works correctly, but i want to clone AND drag them, so i end up with multiple buttons (as many as needed). How do i clone and then drag the cloned object?

This is what i have

var a = r.circle(20, 50, 15)
// drag handler
        var start = function(x,y,event) {
            this.ox = this.attr("cx");
            this.oy = this.attr("cy");
            this.animate({r: 20, opacity: .25}, 500, ">");
        },
        move = function(dx, dy) {
            this.attr({cx: this.ox + dx, cy: this.oy + dy});
        },
        up = function () {
            this.animate({r: 15, opacity: .5}, 500, ">");
        };
a.drag(move, start, up);

I have tried various things, cloning 'a', cloning 'this' in start, but my js knowledge is limited so any help would be appreciated.

Thanks!

nickjb
  • 1,176
  • 1
  • 12
  • 16

3 Answers3

3

Try using objects.

I created an object to encapsulate the Raphael object and the drag functions to be used on it.

function Button(ix,iy,ir)
{
// grab a reference to the objects "this"
var that = this;
that.a = r.circle(ix, iy, ir).attr({"fill":"red"})
// drag handler
    that.start = function(x,y,event) {
        that.a.ox = this.attr("cx");
        that.a.oy = this.attr("cy");
        that.a.animate({r: 20, opacity: .25}, 500, ">");
    }
   that.move = function(dx, dy) {
        that.a.attr({cx: that.a.ox + dx, cy: that.a.oy + dy});
    }
   that.up = function () {
        that.a.animate({r: 15, opacity: .5}, 500, ">");
    };
that.a.drag(that.move,that.start,that.up);
return that;
}

The important thing here is to capture the "this" reference in a variable and use the variable to refer to it in your drag functions.

The reason for doing this is that when drag calls "move", "start" and "up", the this object isn't going to refer to your object. "This" changes frequently. By using "that", you're locking in the object to use within these methods.

Here's a better explanation of "that = this". (Be sure to upvote lonesomeday for an excellent explanation)

Here's a fiddle that creates two buttons that you can drag independently.

Hope that helps

Community
  • 1
  • 1
amadan
  • 1,514
  • 10
  • 14
  • Thanks but dragging isn't the problem, how to i clone the button and then drag the clone? – nickjb Oct 21 '11 at 10:51
  • I must be missing your point. Do you want to drag the button, then clone it, then be able to drag both buttons around? I've updated the [fiddle](http://jsfiddle.net/whMkT/3/) to do just that. – amadan Oct 21 '11 at 14:40
  • Thanks for that, maybe my description wasn't quite up to scratch but what i wanted was to have several buttons at the start. As soon as you click on the button and drag it, it would create a new button that would be dragged leaving the original in place and intact. I've actually after much trial and error found a different solution using mousemove (whown in my answer below) which works, but i think your method using an clone button could work too. Thanks again – nickjb Oct 21 '11 at 20:43
3

My own solution uses mousemove, see my jsfiddle

It clones on the movement start, mousedown, mouseup, click dont work but this does

a.mousemove(clone_handler);
var clone_handler = function() {
var x = this.clone();
x.drag(move, start, up);
nickjb
  • 1,176
  • 1
  • 12
  • 16
0

Not sure if Raphael has clone functionality for a generic node, but cloning a circle can be done manually by doing something like

var circle = r.circle(x, y, r);
var clone = r.circle(circle.cx, circle.cy, circle.r);
clone.attr({ attr1: circle.attr1, ...);

Edit: aparent you can simply call circle.clone() instead of doing the above (Element.clone)

As for cloning when dragging, it may not be straightforward to do as once the drag starts I suppose you can't change the object being dragged. Your alternatives here could be:

  • Clone the circle when the drag starts, drag the original item and leave the copy in its original place (this is a bad idea if you have event handlers attached to the original item)
  • Do as above, but switch the original and the copy positions once the drag ends (it may produce flickering)
  • Find a way to programatically cancel the dragging of the original item and trigger the dragging of its copy, while at the same time taking care that this doesn't develop into an infinite recursion
rsalmeidafl
  • 411
  • 2
  • 4