Nick
Nick

Reputation: 5198

Manipulating dynamically created SVG elements

I'm trying to be able to "drag" SVG elements (using Raphael) loaded from a database around a canvas using AJAX. I can load them and display them from the DB fine, but when I want to add event handlers to each individual one, I can't seem to get it right.

I tried using .on() after loading all elements from the DB, when the DOM is ready:

$('circle').on("mousedown", function(event) {
        ox = event.screenX;
        oy = event.screenY;
        event.target.attr({opacity: .5});
        dragging = true;
    });

But this never seems to get called.

I can add events during the creation of the circles, but then only the last element added actually moves--but only if the mouse is within the X,Y of the other loaded circles:

var data = $.ajax({
    type: "POST",
    url: "map.php",
    data: "loadMap=1",
    success: function(text) {
        var item = text.split(";");
        for (x in item)
        {
            if (item[x].length > 0)
            {
                var str = item[x].split(",");
                if (str[0] == "node")
                {
                    var c = svg.circle(str[1], str[2], 10);
                    c.attr("id", str[3]);
                    c.attr("fill", "black");
                    c.attr("stroke", "none");

                    c.mousedown(function(event) {
                        ox = event.screenX;
                        oy = event.screenY;
                        c.attr({opacity: .5});
                        dragging = true;
                    });

                    c.mousemove(function(event) {
                    if (dragging) {
                        c.translate(event.screenX - ox, event.screenY - oy);
                        ox = event.screenX;
                        oy = event.screenY;
                        }
                    });

                    c.mouseup(function(Event) {
                        dragging = false;
                        c.attr({opacity: 1});
                    });

                }
                else if (str[0] == "room")
                {
                }
            }
        }
    }
});

What am I doing wrong, or better yet, what is the best way to approach this problem?

Upvotes: 0

Views: 821

Answers (2)

methodofaction
methodofaction

Reputation: 72445

Depending on the amount of circles it might be a bad idea adding an event listener to each of them. A more robust solution would be adding the event to the svg element

$("#svgelement").on("mousedown", "circle", function(event){
        target = this;
        ox = event.screenX;
        oy = event.screenY;
        target.setAttribute('opacity', 0.5)
        dragging = true;
});

$("#svgelement").on("mousemove", function(event){
  if (dragging) {
      if(target) target.setAttribute('transform', 'translate('+ event.screenX - ox +','+  event.screenY - oy +')');
      ox = event.screenX;
      oy = event.screenY;
  }
});

//attached to the window, otherwise you might drag
//all the way out of the svg and release there.
$(window).on("mouseup", function(Event) {
   dragging = false;
   target.setAttribute('opacity', 1)
   target = false;
});

Another benefit is that you don't require to load this as callback on ajax success, so you can discard sync problems.

Upvotes: 2

CapelliC
CapelliC

Reputation: 60034

I think the error could be that you refer to c from inside the mouse event handlers you are attaching to circles.

Then each event handler refers to the object that c refers to, i.e. the last object. event carries a target member, and you should use that instead.

I'm using jQuerySVG, and the event' member I'm using is currentTarget, see if is available for you (I think so)

Upvotes: 1

Related Questions