将多个对象添加到svg并添加拖动行为问题

时间:2015-12-16 06:30:49

标签: javascript html html5 d3.js svg

我对SVG和d3库完全不熟悉。我需要动态添加5个圆圈到svg,其中包含可拖动的事件处理程序。我编写了一些代码,用于添加单个圆圈并添加可拖动的行为,并且工作正常。现在我在for循环中尝试相同的东西,以便添加5个圆圈。它显示所有圆圈,但是当我拖动一个特定的圆圈并将其放置在那里然后它停留在那里当我触摸另一个圆圈时,旧圆圈从我们放置的位置消失并出现在我们接下来开始的新圆圈上。请看下面提到的代码。对此有任何帮助将不胜感激。

   function addCircles()
    {    
    var box = d3.select(".box");  

         for(var i = 0;i<5;i++)
         {

            var drag = d3.behavior.drag()  
                 .on('dragstart', function() { console.log("dragstart"); circle.style('fill', 'red'); })
                 .on('drag', function() { console.log("drag X - " + d3.event.x + " Y - " + d3.event.y); circle.attr('cx', d3.event.x)
                                                .attr('cy', d3.event.y); })
                 .on('dragend', function() {    console.log("dragend - " + d3.event.x); 
                                                circle.style('fill', 'green');  }); 

var circle = box.selectAll('.draggableCircle'+i)  
                    .data([{ x: i*15, y: i*15, r: 10 }])
                    .enter()
                    .append('svg:circle')
                    .attr('class', 'draggableCircle'+i)
                    .attr('cx', function(d) { return d.x; })
                    .attr('cy', function(d) { return d.y; })
                    .attr('r', function(d) { return d.r; })
                    .call(drag)
                    .style('fill', 'green');


         } 
    } 

我在调试chrome中的代码后检查了一下,发现没有检测到dragEnd的位置。

1 个答案:

答案 0 :(得分:1)

你的小提琴没有用,所以我不得不用提供的代码制作自己的小提琴:http://jsfiddle.net/Qh9X5/6932/

首先创建数据,然后从该数据中绘制圆圈,而不是一次性完成所有操作。

var nodeData = [];

     for(var i = 1;i<15;i++) //change the value 15 to however many circles you want
     {      

        nodeData.push({
           x:i*15,
           y:i*15,
           r:10
        })    

     }

然后使用此数据创建圈子:

 var circle = box.selectAll('.draggableCircle'+i)  
                    //.data([{ x: i*15, y: i*15, r: 10 }])
                    .data(nodeData)
                    .enter()
                    .append('svg:circle')
                    .attr('class', function(d,i){
                    return 'draggableCircle'+i; //changed this to use i in the loop 
                                              //through the nodes not i in the for loop
                    })
                    .attr('cx', function(d) { return d.x; })
                    .attr('cy', function(d) { return d.y; })
                    .attr('r', function(d) { return d.r; })
                    .style('fill', 'green')
                    .call(drag)

你的拖动也没有正确完成。你有这条线:

circle.attr('cx', d3.event.x).attr('cy', d3.event.y);

你不想要这个,因为你经历了每一个圈子并且对所有圈子都进行了拖拽。你只想在你正在“拖动”的元素上调用它:

function dragmove(d, i) //-updates the co-ordinates 
{
    d.x += d3.event.dx;
    d.y += d3.event.dy; 


    d3.select(this).attr("transform", function(d,i)
    {
        return "translate(" + [ d.x,d.y ] + ")";
    });    
}

我认为这是我为使其发挥作用所做的所有改变。

另一方面,使用JSFiddle,您必须在左侧包含D3库,否则它将不起作用。此外,当在html中调用“drawCircles()”函数时,您必须更改小提琴的加载,否则它将无法找到该函数。另外,如上所述,如果您在问题中再次使用JSFiddle,请在向SO用户发送链接之前确保其有效。

EDIT

我添加了这一行,以便在加载时获得正确的圆圈位置:

circle.attr("transform", function(d){
          return "translate(" + [ d.x,d.y ] + ")";
          })

现在拖动工作完美:))希望这有帮助