静态尺寸的圆形包装

Nav*_*eon 5 javascript d3.js

我正在尝试使用静态大小圆圈值实现D3 包布局,我希望 D3 只负责放置,但我发现 d3 覆盖了提供的圆圈大小。我不确定如何保持从数据传递的相同大小。请参阅下面的代码,其中,当我将带有标签的子项的大小RAD100to更改5000时,我看到其他圆圈的大小正在变化,如何使布局以从数据中获得的确切大小进行渲染?请给我一些指针或jsfiddle

链接到 codepen - https://codepen.io/navinleon/pen/mxZJWr

提前致谢。

var w = 1000,
    h = 500;

var data = {
    name: "root",
    children: [{
        label: 'RAD',
        size: 100,
        color: '#c99700'
    }, {
        label: 'BIL',
        size: 100,
        color: '#008ce6'
    }, {
        label: 'EEN',
        size: 100,
        color: '#007377'
    }, {
        label: 'INO',
        size: 100,
        color: '#b4975a'
    }, ]
};

var canvas = d3.select("#canvas")
    .append("svg:svg")
    .attr('width', w)
    .attr('height', h);

var nodes = d3.layout.pack()
    .value(function (d) {
        return d.size;
    }).padding(100)
    .size([w, h])
    .nodes(data);

// Get rid of root node
nodes.shift();

canvas.selectAll('circles')
    .data(nodes)
    .enter()
    .append('svg:circle')
    .attr('cx', function (d) {
        return d.x;
    })
    .attr('cy', function (d) {
        return d.y;
    })
    .attr('r', function (d) {
        return d.r;
    })
    .attr('fill', function (d) {
        return d.color;
    });
Run Code Online (Sandbox Code Playgroud)

Ger*_*ado 4

使用 d3.packSiblings():

\n\n

事实上,有一种方便的方法,名为d3.packSiblings,它似乎正是您所需要的(无需任何力模拟)来定位节点。

\n\n

根据API

\n\n
\n

打包指定的圆数组,每个圆都必须具有circle.r指定圆\xe2\x80\x99s 半径的属性。

\n
\n\n

因此,将size数据中的属性更改为r,您所需要的只是:

\n\n
var packed = d3.packSiblings(data.children);\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是演示:

\n\n

\r\n
\r\n
var packed = d3.packSiblings(data.children);\n
Run Code Online (Sandbox Code Playgroud)\r\n
var data = {\r\n  name: "root",\r\n  children: [{\r\n    label: \'RAD\',\r\n    r: 50,\r\n    color: \'#c99700\'\r\n  }, {\r\n    label: \'BIL\',\r\n    r: 75,\r\n    color: \'#008ce6\'\r\n  }, {\r\n    label: \'EEN\',\r\n    r: 20,\r\n    color: \'#007377\'\r\n  }, {\r\n    label: \'INO\',\r\n    r: 42,\r\n    color: \'#b4975a\'\r\n  }, ]\r\n};\r\n\r\nvar packed = d3.packSiblings(data.children);\r\n\r\nvar w = 500,\r\n  h = 400;\r\nvar svg = d3.select("body")\r\n  .append("svg")\r\n  .attr("width", w)\r\n  .attr("height", h)\r\n  .append("g")\r\n  .attr("transform", "translate(" + w / 2 + "," + h / 2 + ")");\r\n\r\nvar color = d3.scaleOrdinal(d3.schemeCategory10);\r\n\r\nvar nodes = svg.selectAll(null)\r\n  .data(data.children)\r\n  .enter()\r\n  .append("circle")\r\n  .attr("cx", function(d) {\r\n    return d.x\r\n  })\r\n  .attr("cy", function(d) {\r\n    return d.y\r\n  })\r\n  .attr("r", function(d) {\r\n    return d.r\r\n  })\r\n  .style("fill", function(_, i) {\r\n    return color(i)\r\n  })
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

使用力模拟

\n\n

您实际上不需要圆形包装布局。圆包布局必然适合数组指定区域中的所有圆pack.size

\n\n

由于您想自己设置圆圈的大小并且希望 D3 只负责放置,所以我想到的最明显的选择是使用力模拟

\n\n

forceX在此建议的解决方案中,我们将使用和将焦点设置为 SVG 的中心forceY。然后,我们将停止模拟并运行给定的次数(元素越少,需要的迭代就越少):

\n\n
var simulation = d3.forceSimulation(data.children)\n  .force("x", d3.forceX(w / 2))\n  .force("y", d3.forceY(h / 2))\n  .force("collide", d3.forceCollide(function(d) {\n    return d.size\n  }))\n  .stop();\n
Run Code Online (Sandbox Code Playgroud)\n\n

这是一些演示。

\n\n

首先,将所有圆的半径设置为 100:

\n\n

\r\n
\r\n
<script src="https://d3js.org/d3.v5.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
var simulation = d3.forceSimulation(data.children)\n  .force("x", d3.forceX(w / 2))\n  .force("y", d3.forceY(h / 2))\n  .force("collide", d3.forceCollide(function(d) {\n    return d.size\n  }))\n  .stop();\n
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

现在让我们将 3 个圆的大小减小到 20 个:

\n\n

\r\n
\r\n
var w = 500,\r\n  h = 400;\r\nvar svg = d3.select("body")\r\n  .append("svg")\r\n  .attr("width", w)\r\n  .attr("height", h);\r\n\r\nvar color = d3.scaleOrdinal(d3.schemeCategory10)\r\n\r\nvar data = {\r\n  name: "root",\r\n  children: [{\r\n    label: \'RAD\',\r\n    size: 100,\r\n    color: \'#c99700\'\r\n  }, {\r\n    label: \'BIL\',\r\n    size: 100,\r\n    color: \'#008ce6\'\r\n  }, {\r\n    label: \'EEN\',\r\n    size: 100,\r\n    color: \'#007377\'\r\n  }, {\r\n    label: \'INO\',\r\n    size: 100,\r\n    color: \'#b4975a\'\r\n  }, ]\r\n};\r\n\r\nvar simulation = d3.forceSimulation(data.children)\r\n  .force("x", d3.forceX(w / 2))\r\n  .force("y", d3.forceY(h / 2))\r\n  .force("collide", d3.forceCollide(function(d) {\r\n    return d.size\r\n  }))\r\n  .stop();\r\n\r\nfor (var i = 0; i < 100; ++i) simulation.tick();\r\n\r\nvar nodes = svg.selectAll(null)\r\n  .data(data.children)\r\n  .enter()\r\n  .append("circle")\r\n  .attr("cx", function(d) {\r\n    return d.x\r\n  })\r\n  .attr("cy", function(d) {\r\n    return d.y\r\n  })\r\n  .attr("r", function(d) {\r\n    return d.size\r\n  })\r\n  .style("fill", function(_, i) {\r\n    return color(i)\r\n  })
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://d3js.org/d3.v5.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

现在所有圆圈的大小均为 10:

\n\n

\r\n
\r\n
var w = 500,\r\n  h = 400;\r\nvar svg = d3.select("body")\r\n  .append("svg")\r\n  .attr("width", w)\r\n  .attr("height", h);\r\n\r\nvar color = d3.scaleOrdinal(d3.schemeCategory10)\r\n\r\nvar data = {\r\n  name: "root",\r\n  children: [{\r\n    label: \'RAD\',\r\n    size: 20,\r\n    color: \'#c99700\'\r\n  }, {\r\n    label: \'BIL\',\r\n    size: 100,\r\n    color: \'#008ce6\'\r\n  }, {\r\n    label: \'EEN\',\r\n    size: 20,\r\n    color: \'#007377\'\r\n  }, {\r\n    label: \'INO\',\r\n    size: 20,\r\n    color: \'#b4975a\'\r\n  }, ]\r\n};\r\n\r\nvar simulation = d3.forceSimulation(data.children)\r\n  .force("x", d3.forceX(w / 2))\r\n  .force("y", d3.forceY(h / 2))\r\n  .force("collide", d3.forceCollide(function(d) {\r\n    return d.size\r\n  }))\r\n  .stop();\r\n\r\nfor (var i = 0; i < 100; ++i) simulation.tick();\r\n\r\nvar nodes = svg.selectAll(null)\r\n  .data(data.children)\r\n  .enter()\r\n  .append("circle")\r\n  .attr("cx", function(d) {\r\n    return d.x\r\n  })\r\n  .attr("cy", function(d) {\r\n    return d.y\r\n  })\r\n  .attr("r", function(d) {\r\n    return d.size\r\n  })\r\n  .style("fill", function(_, i) {\r\n    return color(i)\r\n  })
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://d3js.org/d3.v5.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

最后,让其中一个圆的大小为 5000。您唯一看到的就是整个 SVG 为单一颜色...但这就是您所要求的:圆的半径为 5000 像素。核实:

\n\n

\r\n
\r\n
var w = 500,\r\n  h = 400;\r\nvar svg = d3.select("body")\r\n  .append("svg")\r\n  .attr("width", w)\r\n  .attr("height", h);\r\n\r\nvar color = d3.scaleOrdinal(d3.schemeCategory10)\r\n\r\nvar data = {\r\n  name: "root",\r\n  children: [{\r\n    label: \'RAD\',\r\n    size: 10,\r\n    color: \'#c99700\'\r\n  }, {\r\n    label: \'BIL\',\r\n    size: 10,\r\n    color: \'#008ce6\'\r\n  }, {\r\n    label: \'EEN\',\r\n    size: 10,\r\n    color: \'#007377\'\r\n  }, {\r\n    label: \'INO\',\r\n    size: 10,\r\n    color: \'#b4975a\'\r\n  }, ]\r\n};\r\n\r\nvar simulation = d3.forceSimulation(data.children)\r\n  .force("x", d3.forceX(w / 2))\r\n  .force("y", d3.forceY(h / 2))\r\n  .force("collide", d3.forceCollide(function(d) {\r\n    return d.size\r\n  }))\r\n  .stop();\r\n\r\nfor (var i = 0; i < 100; ++i) simulation.tick();\r\n\r\nvar nodes = svg.selectAll(null)\r\n  .data(data.children)\r\n  .enter()\r\n  .append("circle")\r\n  .attr("cx", function(d) {\r\n    return d.x\r\n  })\r\n  .attr("cy", function(d) {\r\n    return d.y\r\n  })\r\n  .attr("r", function(d) {\r\n    return d.size\r\n  })\r\n  .style("fill", function(_, i) {\r\n    return color(i)\r\n  })
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://d3js.org/d3.v5.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n