nickjb
nickjb

Reputation: 1216

raphaeljs clone and drag

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!

Upvotes: 2

Views: 2978

Answers (3)

nickjb
nickjb

Reputation: 1216

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);

Upvotes: 3

amadan
amadan

Reputation: 1514

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

Upvotes: 3

rsalmeidafl
rsalmeidafl

Reputation: 411

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

Upvotes: 0

Related Questions