Javascript 如何使用JS拖动几个圆?

Javascript 如何使用JS拖动几个圆?,javascript,d3.js,Javascript,D3.js,我用d3画了一组圆。我可以轻松地拖动其中一个圆圈,并跟踪其cx和cy位置 var width= 800; var height=600; svg= d3.select("body").select(".div1").append("svg") .attr("width", width) .attr("height",height); transformed_data = [

我用d3画了一组圆。我可以轻松地拖动其中一个圆圈,并跟踪其cx和cy位置

 var width= 800;
 var height=600;
 svg= d3.select("body").select(".div1").append("svg")
                            .attr("width", width)
                            .attr("height",height);
 transformed_data =  [
                  [5, 20], [480, 90], [250, 50], [100, 33], [330, 95],
                  [410, 12], [475, 44], [25, 67], [85, 21], [220, 88] 
                ];

 X = [0,800];
 Y = [0,600];

 xScale =d3.scale.linear().domain(X).range([70, width-70]);
 yScale =d3.scale.linear().domain(Y).range([70, height-70]);

 drag = d3.behavior.drag()
          .on("drag", function(d,i) {
                d3.select(this).attr("cx", d3.event.x);
                d3.select(this).attr("cy", d3.event.y);
          })
         .on("dragend",function(d,i){

         });

svg.selectAll('circle')
        .data(transformed_data)
        .enter()
        .append("circle")
        .attr("id", function(d,i){return "id_" + i.toString();})
        .attr("cx", function(d,i){return xScale(transformed_data[i][0]);})
        .attr("cy", function(d,i){return yScale(transformed_data[i][1]);}) 
        .attr("r",10)
        .call(drag);

但是,我不知道如何使用鼠标选择几个圆并将它们拖到一起。有什么想法吗,比如说

有一个实现,允许您拖动多个元素,该链接由@Lars提供,效果很好,但交互不自然,我个人不喜欢。代码如下:

搜索了一会儿之后。我最终得到了以下代码,它工作得非常完美,我相信交互是非常自然的

<html>
 <head>
   <title>jQuery UI Selectable - Serialize</title>
   <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/theme/smoothness/jquery-ui.css">
   <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
   <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
   <link rel="stylesheet" href="/resources/demos/style.css">  

  <style>
      rect.selection {
          stroke: black;
          stroke-dasharray: 4px;
          stroke-opacity  : 0.9;
          fill: transparent;
       }
      .state circle {
          stroke  : gray;
          cursor  : pointer;
       }
      .state {
          fill    : black;
      }
      .selected{
          fill    : red;
      }

   </style>

   <body> 
      <div class="div1"></div>  
   </body>


<script type="text/javascript">

var width = 800,
    radius=10,
    height = 600;

   svg= d3.select("body").select(".div1").append("svg")
                            .attr("width", width)
                            .attr("height",height);
   var transformed_data= d3.range(10).map(function(d) {
       return {
         x: parseInt(Math.random() * width),
         y: parseInt(Math.random() * height),
       }
     });

    // Drag Evenet 
    drag = d3.behavior.drag()
            .on("drag", function( d, i) {
                    var selection = d3.selectAll('.selected');
                    console.log(selection[0] + "---"+selection[1]);
                    svg.selectAll( "rect.selection").remove();
                    if(selection[0].indexOf(this)==-1) {
                        selection = d3.select(this);
                        selection.classed("selected", true);
                    } 
                    selection.attr("cx", function(d){ d.x += d3.event.dx; return d.x;})
                    selection.attr("cy", function(d,i){d.y += d3.event.dy; return d.y;})    
            });

    gStates = svg.selectAll('circle')
                 .data(transformed_data)
                 .enter()
                 .append("circle")
                 .attr("class","state")
                 .attr("id", function(d,i){return "id_" + i.toString();})
                 .attr("cx", function(d,i){return d.x;})
                 .attr("cy", function(d,i){return d.y;}) 
                 .attr("r",10)
                 .call(drag);

    svg.on( "mousedown", function() {
            if(!d3.event.ctrlKey) {
                    d3.selectAll(".selected").classed( "selected", false);
            }
            var p = d3.mouse(this);
            svg.append( "rect")
               .attr({
                    class   : "selection",
                    x       : p[0],
                    y       : p[1],
                    width   : 0,
                    height  : 0
                })
        })
       .on( "mousemove", function() {
            var s = svg.select( "rect.selection");
            if( !s.empty()) {
                var p = d3.mouse( this),
                    d = {
                        x       : parseInt( s.attr( "x"), 10),
                        y       : parseInt( s.attr( "y"), 10),
                        width   : parseInt( s.attr( "width"), 10),
                        height  : parseInt( s.attr( "height"), 10)
                    },
                    move = {
                        x : p[0] - d.x,
                        y : p[1] - d.y
                    };

                if( move.x < 1 || (move.x*2<d.width)) {
                    d.x = p[0];
                    d.width -= move.x;
                } else {
                    d.width = move.x;       
                }

                if( move.y < 1 || (move.y*2<d.height)) {
                    d.y = p[1];
                    d.height -= move.y;
                } else {
                    d.height = move.y;       
                }

                s.attr( d);
                d3.selectAll( ".state").each( function( state_data, i) {
                    if( 
                        !d3.select(this).classed("selected") && 
                            // inner circle inside selection frame
                        state_data.x-radius>=d.x && state_data.x+radius<=d.x+d.width && 
                        state_data.y-radius>=d.y && state_data.y+radius<=d.y+d.height
                    ) {
                        d3.select(this)
                        .classed( "selection", true)
                        .classed( "selected", true);
                    }
                });
            }
        })

        .on( "mouseup", function() {
              // remove selection frame
            svg.selectAll( "rect.selection").remove();

              // remove temporary selection marker class
            d3.selectAll( '.state.selection').classed( "selection", false);
        })
        .on( "mouseout", function() {
            if( d3.event.relatedTarget.tagName=='HTML') {
                    // remove selection frame
                svg.selectAll( "rect.selection").remove();

                    // remove temporary selection marker class
                d3.selectAll( '.state.selection').classed( "selection", false);
            }
        });
</script>
  </head>

jQuery UI可选-序列化
矩形选择{
笔画:黑色;
笔划阵列:4px;
笔划不透明度:0.9;
填充:透明;
}
.州议会{
笔画:灰色;
光标:指针;
}
.州{
填充:黑色;
}
.选定{
填充物:红色;
}
可变宽度=800,
半径=10,
高度=600;
svg=d3。选择(“正文”)。选择(“div1”)。追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
变量转换_数据=d3.范围(10).映射(函数(d){
返回{
x:parseInt(Math.random()*宽度),
y:parseInt(Math.random()*高度),
}
});
//拖网
drag=d3.behavior.drag()
.开启(“拖动”,功能(d,i){
var selection=d3.selectAll('.selected');
console.log(选择[0]+“--”+选择[1]);
selectAll(“rect.selection”).remove();
if(选择[0]。indexOf(此)==-1){
选择=d3。选择(本);
selection.classed(“selected”,true);
} 
selection.attr(“cx”,函数(d){d.x+=d3.event.dx;返回d.x;})
attr(“cy”,函数(d,i){d.y+=d3.event.dy;返回d.y;})
});
gStates=svg.selectAll('circle')
.数据(转换的_数据)
.输入()
.附加(“圆圈”)
.attr(“类别”、“状态”)
.attr(“id”,函数(d,i){return“id_”+i.toString();})
.attr(“cx”,函数(d,i){返回d.x;})
.attr(“cy”,函数(d,i){返回d.y;})
.attr(“r”,10)
.呼叫(拖动);
on(“mousedown”,function()){
如果(!d3.event.ctrlKey){
d3.选择全部(“.selected”).classed(“selected”,false);
}
var p=d3.小鼠(此);
svg.append(“rect”)
艾特先生({
类:“选择”,
x:p[0],,
y:p[1],,
宽度:0,
身高:0
})
})
.on(“mousemove”,function(){
var s=svg.select(“rect.selection”);
如果(!s.empty()){
var p=d3.鼠标(此),
d={
x:parseInt(s.attr(“x”),10),
y:parseInt(s.attr(“y”),10),
宽度:parseInt(s.attr(“宽度”),10),
高度:parseInt(s.attr(“高度”),10)
},
移动={
x:p[0]-d.x,
y:p[1]-d.y
};

如果(move.x<1 | | |(move.x*2),则有一个实现允许您拖动多个元素,该链接由@Lars提供,效果非常好,但交互不自然,我个人不喜欢。下面是代码:

在搜索了一段时间后,我最终得到了以下代码,它工作得非常完美,我相信交互是非常自然的

<html>
 <head>
   <title>jQuery UI Selectable - Serialize</title>
   <link rel="stylesheet" href="//code.jquery.com/ui/1.11.4/theme/smoothness/jquery-ui.css">
   <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
   <script src="http://code.jquery.com/ui/1.11.4/jquery-ui.js"></script>
   <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js"></script>
   <link rel="stylesheet" href="/resources/demos/style.css">  

  <style>
      rect.selection {
          stroke: black;
          stroke-dasharray: 4px;
          stroke-opacity  : 0.9;
          fill: transparent;
       }
      .state circle {
          stroke  : gray;
          cursor  : pointer;
       }
      .state {
          fill    : black;
      }
      .selected{
          fill    : red;
      }

   </style>

   <body> 
      <div class="div1"></div>  
   </body>


<script type="text/javascript">

var width = 800,
    radius=10,
    height = 600;

   svg= d3.select("body").select(".div1").append("svg")
                            .attr("width", width)
                            .attr("height",height);
   var transformed_data= d3.range(10).map(function(d) {
       return {
         x: parseInt(Math.random() * width),
         y: parseInt(Math.random() * height),
       }
     });

    // Drag Evenet 
    drag = d3.behavior.drag()
            .on("drag", function( d, i) {
                    var selection = d3.selectAll('.selected');
                    console.log(selection[0] + "---"+selection[1]);
                    svg.selectAll( "rect.selection").remove();
                    if(selection[0].indexOf(this)==-1) {
                        selection = d3.select(this);
                        selection.classed("selected", true);
                    } 
                    selection.attr("cx", function(d){ d.x += d3.event.dx; return d.x;})
                    selection.attr("cy", function(d,i){d.y += d3.event.dy; return d.y;})    
            });

    gStates = svg.selectAll('circle')
                 .data(transformed_data)
                 .enter()
                 .append("circle")
                 .attr("class","state")
                 .attr("id", function(d,i){return "id_" + i.toString();})
                 .attr("cx", function(d,i){return d.x;})
                 .attr("cy", function(d,i){return d.y;}) 
                 .attr("r",10)
                 .call(drag);

    svg.on( "mousedown", function() {
            if(!d3.event.ctrlKey) {
                    d3.selectAll(".selected").classed( "selected", false);
            }
            var p = d3.mouse(this);
            svg.append( "rect")
               .attr({
                    class   : "selection",
                    x       : p[0],
                    y       : p[1],
                    width   : 0,
                    height  : 0
                })
        })
       .on( "mousemove", function() {
            var s = svg.select( "rect.selection");
            if( !s.empty()) {
                var p = d3.mouse( this),
                    d = {
                        x       : parseInt( s.attr( "x"), 10),
                        y       : parseInt( s.attr( "y"), 10),
                        width   : parseInt( s.attr( "width"), 10),
                        height  : parseInt( s.attr( "height"), 10)
                    },
                    move = {
                        x : p[0] - d.x,
                        y : p[1] - d.y
                    };

                if( move.x < 1 || (move.x*2<d.width)) {
                    d.x = p[0];
                    d.width -= move.x;
                } else {
                    d.width = move.x;       
                }

                if( move.y < 1 || (move.y*2<d.height)) {
                    d.y = p[1];
                    d.height -= move.y;
                } else {
                    d.height = move.y;       
                }

                s.attr( d);
                d3.selectAll( ".state").each( function( state_data, i) {
                    if( 
                        !d3.select(this).classed("selected") && 
                            // inner circle inside selection frame
                        state_data.x-radius>=d.x && state_data.x+radius<=d.x+d.width && 
                        state_data.y-radius>=d.y && state_data.y+radius<=d.y+d.height
                    ) {
                        d3.select(this)
                        .classed( "selection", true)
                        .classed( "selected", true);
                    }
                });
            }
        })

        .on( "mouseup", function() {
              // remove selection frame
            svg.selectAll( "rect.selection").remove();

              // remove temporary selection marker class
            d3.selectAll( '.state.selection').classed( "selection", false);
        })
        .on( "mouseout", function() {
            if( d3.event.relatedTarget.tagName=='HTML') {
                    // remove selection frame
                svg.selectAll( "rect.selection").remove();

                    // remove temporary selection marker class
                d3.selectAll( '.state.selection').classed( "selection", false);
            }
        });
</script>
  </head>

jQuery UI可选-序列化
矩形选择{
笔画:黑色;
笔划阵列:4px;
笔划不透明度:0.9;
填充:透明;
}
.州议会{
笔画:灰色;
光标:指针;
}
.州{
填充:黑色;
}
.选定{
填充物:红色;
}
可变宽度=800,
半径=10,
高度=600;
svg=d3。选择(“正文”)。选择(“div1”)。追加(“svg”)
.attr(“宽度”,宽度)
.attr(“高度”,高度);
变量转换_数据=d3.范围(10).映射(函数(d){
返回{
x:parseInt(Math.random()*宽度),
y:parseInt(Math.random()*高度),
}
});
//拖网
drag=d3.behavior.drag()
.开启(“拖动”,功能(d,i){
var selection=d3.selectAll('.selected');
console.log(选择[0]+“--”+选择[1]);
selectAll(“rect.selection”).remove();
if(选择[0]。indexOf(此)==-1){
选择=d3。选择(本);
selection.classed(“selected”,true);
} 
selection.attr(“cx”,函数(d){d.x+=d3.event.dx;返回d.x;})
attr(“cy”,函数(d,i){d.y+=d3.event.dy;返回d.y;})
});
gStates=svg.selectAll('circle')
.数据(转换的_数据)
.输入()
.附加(“圆圈”)
.attr(“类别”、“状态”)
.attr(“id”,函数(d,i){return“id_”+i.toString();})
.attr(“cx”,函数(d,i){返回d.x;})
.attr(“cy”,函数(d,i){返回d.y;})
.attr(“r”,10)
.呼叫(拖动);
sv