javascript - 限制每个节点的拖动区域 d3.js

标签 javascript d3.js

我有一个 d3.js 应用程序,我需要通过圆形/矩形限制每个节点的拖动区域。该拖动区域对于每个节点可以是静态的,可以包括在其json数据中。 这里http://jsfiddle.net/InferOn/5wssqqdw/1/我找到了一个例子,但它不能满足我的要求。

我想要这样的:

enter image description here

这是我需要做这些事情的例子。

<!DOCTYPE html>
<meta charset="utf-8">

<body>
<script
  src="https://code.jquery.com/jquery-3.1.1.min.js" 
  integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
  crossorigin="anonymous"></script>
  <script src="http://d3js.org/d3.v3.min.js"></script>
  <style>
  body{
	background:url(images/bg.jpg) repeat;
}
	svg{
	margin: 0 auto;
	display: block;
}
.link{
	stroke: #51565b;
	stroke-width:20;	
	stroke-opacity: 1;
	
}
  </style>
  <script>
   var width = 800,
   height = 600

 var svg = d3.select("body").append("svg")
   .attr("width", width)
   .attr("height", height);


 var force = d3.layout.force()
   .gravity(1)
   .linkDistance(function (d) {
   return d.distance;
	})
 .charge(-40000)
 .size([width, height]);

 var datajson = {
    "nodes": [{
     "name": "a",
     "node_id": "10",
     "group": 2,
	 "node_img" : "http://loremflickr.com/320/240/dog"
   }, {
     "name": "b",
     "group": 1,
	 "node_id": "11",
	 "node_img" : "http://loremflickr.com/320/240/dog"
   }, {
     "name": "c",
     "group": 1,
	 "node_id": "12",
	 "node_img" : "http://loremflickr.com/320/240/dog"
   }
   ],
   "links": [{
     "source": 0,
     "target": 1,
     "value": 1,
     "distance": 400
   }, {
     "source": 1,
     "target": 2,
     "value": 2,
     "distance": 300
   }, {
     "source": 2,
     "target": 0,
     "value": 3,
     "distance": 300
   }]
 }

 var numNodes = datajson.nodes.length
 var r = 20;
 datajson.nodes.forEach(function(node, i) {
   node.x = width/2  + r * Math.sin(2 * Math.PI * i / numNodes)
   node.y = height/2 + r * Math.cos(2 * Math.PI * i / numNodes)
 })

 force
   .nodes(datajson.nodes)
   .links(datajson.links)
   .start();

 var drag = force.drag()
   .on("drag", dblclick);

 var link = svg.selectAll(".link")
   .data(datajson.links)
   .enter().append("line")
   .attr("class", "link");

 var node = svg.selectAll(".node")
   .data(datajson.nodes)
   .enter().append("g")
   .attr("class", function(d) { return "node "+"class_"+d.node_id})
   .call(force.drag);

	
   	//circle
	var circle = node.append("circle")
	.attr("r", 55)
	.attr("id", function(d) { return d.node_id })
	.style("fill", function (d) { return 'rgba(81,86,91,1)'; })
	.attr("class", function(d) { return "circle circle_"+d.node_id });
	
	//image
 node.append("image")
   .attr("x", -37)
   .attr("y", -37)
   .attr("width", 75)
   .attr("height", 75)
   .attr("xlink:href", function(d) {
    return d.node_img;
   });
   
 force.on("tick", function() {
   link.attr("x1", function(d) {
       return d.source.x;
     })
     .attr("y1", function(d) {
       return d.source.y;
     })
     .attr("x2", function(d) {
       return d.target.x;
     })
     .attr("y2", function(d) {
       return d.target.y;
     });

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


 function dblclick(d) {

 }
 
  </script>
</body>

最佳答案

这是执行此操作的一种方法:

<!DOCTYPE html>
<meta charset="utf-8">

<body>
  <script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
  <script src="http://d3js.org/d3.v3.min.js"></script>
  <style>
    body {
      background: url(images/bg.jpg) repeat;
    }
    
    svg {
      margin: 0 auto;
      display: block;
    }
    
    .link {
      stroke: #51565b;
      stroke-width: 20;
      stroke-opacity: 1;
    }
  </style>
  <script>
    var width = 800,
      height = 600

    var svg = d3.select("body").append("svg")
      .attr("width", width)
      .attr("height", height);

    var force = d3.layout.force()
      .gravity(1)
      .linkDistance(function(d) {
        return d.distance;
      })
      .charge(-40000)
      .size([width, height]);

    var datajson = {
      "nodes": [{
        "name": "a",
        "node_id": "10",
        "group": 2,
        "node_img": "http://loremflickr.com/320/240/dog",
        "drag_radius": 150
      }, {
        "name": "b",
        "group": 1,
        "node_id": "11",
        "node_img": "http://loremflickr.com/320/240/dog",
        "drag_radius": 200
      }, {
        "name": "c",
        "group": 1,
        "node_id": "12",
        "node_img": "http://loremflickr.com/320/240/dog",
        "drag_radius": 100
      }],
      "links": [{
        "source": 0,
        "target": 1,
        "value": 1,
        "distance": 400
      }, {
        "source": 1,
        "target": 2,
        "value": 2,
        "distance": 300
      }, {
        "source": 2,
        "target": 0,
        "value": 3,
        "distance": 300
      }]
    }

    var numNodes = datajson.nodes.length
    var r = 20;
    datajson.nodes.forEach(function(node, i) {
      node.x = width / 2 + r * Math.sin(2 * Math.PI * i / numNodes)
      node.y = height / 2 + r * Math.cos(2 * Math.PI * i / numNodes)
    })

    force
      .nodes(datajson.nodes)
      .links(datajson.links)
      .start();

    var drag = force.drag()
      .on("drag", drag)
      .on("dragstart", dragstart)
      .on("dragend", dragend);

    var link = svg.selectAll(".link")
      .data(datajson.links)
      .enter().append("line")
      .attr("class", "link");

    var node = svg.selectAll(".node")
      .data(datajson.nodes)
      .enter().append("g")
      .attr("class", function(d) {
        return "node " + "class_" + d.node_id
      })
      .call(force.drag);


    //circle
    var circle = node.append("circle")
      .attr("r", 55)
      .attr("id", function(d) {
        return d.node_id
      })
      .style("fill", function(d) {
        return 'rgba(81,86,91,1)';
      })
      .attr("class", function(d) {
        return "circle circle_" + d.node_id
      });

    //image
    node.append("image")
      .attr("x", -37)
      .attr("y", -37)
      .attr("width", 75)
      .attr("height", 75)
      .attr("xlink:href", function(d) {
        return d.node_img;
      });

    force.on("tick", function() {
      link.attr("x1", function(d) {
          return d.source.x;
        })
        .attr("y1", function(d) {
          return d.source.y;
        })
        .attr("x2", function(d) {
          return d.target.x;
        })
        .attr("y2", function(d) {
          return d.target.y;
        });

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

    function drag(d) {
      var dx = d.orig_x - d.px
          dy = d.orig_y - d.py,
          dd = Math.sqrt((dx * dx) + (dy * dy));
      // am I out of bounds
      if (dd >= d.drag_radius - 55){
        // set to previous values
        d.px = d.last_x;
        d.py = d.last_y;
      }
      // remember previous values
      d.last_x = d.px;
      d.last_y = d.py;
    }
    
    function dragstart(d) {
      // original position
      if (!d.orig_x) d.orig_x = d.x;
      if (!d.orig_y) d.orig_y = d.y;
    
      // draw bounds circle
      d.bounds_obj = svg.append('circle')
        .attr("transform", "translate(" + d.orig_x + "," + d.orig_y + ")")
        .attr("r", d.drag_radius)
        .style("fill", "none")
        .style("stroke", "steelblue")
        .style("stroke-width", "2px");
    }
    function dragend(d) {
      // remove circle and clean-up
      d.bounds_obj.remove();
      d.bounds_obj = undefined;
    }
  </script>
</body>

关于javascript - 限制每个节点的拖动区域 d3.js,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42485238/

相关文章:

javascript - 使用 d3 自定义气泡位置

javascript - 有没有办法访问函数的预绑定(bind)值?

javascript - 使用标签样式的复选框的不确定 CSS 样式

javascript - 读取数据对象的单元格内容

javascript - 当从 Controller 调用 api 时,在回调中获取返回值(在 Angular Directive(指令)中)

javascript - ReactJS componentDidMount + 渲染

javascript - 如何防止剪裁使用 D3 库(在 Javascript 中)绘制的 SVG?

javascript - 收到新数据时如何更新 d3 图表

javascript - 引用错误: event is not defined on keyup event in firefox

d3.js - 在 d3 中是否可以动态更改路径位置开始补间的位置?