javascript - d3js 拖动圆应该重新排列主边界圆中的其他圆

标签 javascript svg d3.js drag circle-pack

我有基于 this tutorial 的气泡图.

我已使用以下代码启用气泡拖动。这使得单个圆圈可拖动,但在拖动一个圆圈时,其他圆圈不会自动调整。我正在使用包圈算法,请告诉我这个算法是否可行。

这是我的拖动代码:

// draggable
if(this.dragging){
    var drag = d3.behavior.drag()
    .on("drag", function( d, i) {
        var selection = d3.selectAll( '.selected');

        if( selection[0].indexOf( this)==-1) {
            selection.classed( "selected", false);
            selection = d3.select( this);
            selection.classed( "selected", true);
        } 

        selection.attr("transform", function( d, i) {
            d.x += d3.event.dx;
            d.y += d3.event.dy;
            return "translate(" + [ d.x,d.y ] + ")"
        })
        // reappend dragged element as last 
        // so that its stays on top 
        this.parentNode.appendChild( this);
        d3.event.sourceEvent.stopPropagation();
    });
    node.call( drag);
}

最佳答案

这里有一些代码可能会达到您正在寻找的效果。这主要归功于 Mike Bostock 的 Bubble ChartCollision Detection示例。

这使用 D3 的 pack layout初始定位节点。然后一个force layout用于在拖动节点时“自动调整”其他圆圈。

Working example at bl.ocks.org

var width = 900;
var height = 500;

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

var nodes = d3.range(128).map(function () { return {radius: Math.random() * 16 + 8}; });
var nodesCopy = $.extend(true, [], nodes);

function dblclick(d) {
  d3.select(this).classed("fixed", d.fixed = false);
}

function dragstart(d) {
  d3.select(this).classed("fixed", d.fixed = true);
}

function collide(node) {
  var r = node.radius + 16;
  var nx1 = node.x - r;
  var nx2 = node.x + r;
  var ny1 = node.y - r;
  var ny2 = node.y + r;
  return function (quad, x1, y1, x2, y2) {
    if (quad.point && (quad.point !== node)) {
      var x = node.x - quad.point.x;
      var y = node.y - quad.point.y;
      var l = Math.sqrt(x * x + y * y);
      var npr = node.radius + quad.point.radius;
      if (l < npr) {
        l = (l - npr) / l * 0.5;
        x *= l;
        node.x -= x;
        y *= l;
        node.y -= y;
        quad.point.x += x;
        quad.point.y += y;
      }
    }
    return x1 > nx2 || x2 < nx1 || y1 > ny2 || y2 < ny1;
  };
}

function packup() {
  var pack = d3.layout.pack()
      .sort(null)
      .size([width, height])
      .padding(0)
      .value(function (d) { return d.radius; });

  svg.selectAll(".node")
      .data(pack.nodes({"children": nodes})
      .filter(function (d) { return !d.children; }))
    .enter().append("circle")
      .attr("r", function (d) { return d.radius; })
      .attr("cx", function (d) { return d.x; })
      .attr("cy", function (d) { return d.y; });
}

function forceup() {
  var force = d3.layout.force()
      .nodes(nodes)
      .gravity(0.05)
      .charge(0)
      .size([width, height])
      .start();

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

  force.on("tick", function () {
    var q = d3.geom.quadtree(nodes);
    var i = 0;
    var n = nodes.length;

    while (++i < n) {
      q.visit(collide(nodes[i]));
    }

    svg.selectAll("circle")
        .attr("cx", function (d) { return d.x; })
        .attr("cy", function (d) { return d.y; });
  });

  d3.selectAll("circle")
    .on("dblclick", dblclick)
    .call(drag);
}

function reset() {
  svg.selectAll("*").remove();
  nodes = $.extend(true, [], nodesCopy);
  packup();
  forceup();
}

packup();
forceup();

关于javascript - d3js 拖动圆应该重新排列主边界圆中的其他圆,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25195823/

相关文章:

javascript - 部署到 gh-pages 时找不到 Bundle.js

javascript - AJAX 可以从远程服务器请求数据吗?

javascript - 悬停时未出现元素

xml - SVG 圆角

javascript - 在 Anime.js 中使用 SVG 对象 HTML

javascript - 只渲染当前可见的数据的 SVG 节点?

javascript - jQuery:如果数字超过 3 位

ios - 是否可以在 iOS 中使用多色字体图标?

javascript - d3 json加载错误未捕获类型错误: Cannot read property 'length' of undefined

angularjs - 将 D3.js 导入 Angular 2 应用程序的正确方法