我有一个看起来像这样的数据集:
var shapes = [
{
type: 'rect', // which shape to draw
size: [ 1, 100 ], // width and height (for rect) or single number for lines, triangles or squares
color: color[0],
orientation: 0 // in degrees in interval [0, 360[
},
{
type: 'triangle',
size: 55,
color: color[1],
orientation: 0
},
{
type: 'triangle',
size: 96,
color: color[0],
orientation: 0
}
// etc …
]
我想做的是绘制数据集中的所有形状,数据集的长度可变,是随机生成的,由定义形状的不同对象中的各种属性定义。形状应均匀分布,且不得相互重叠。
数据绑定到周围的g
元素,如下所示:
var viewport = d3.select('body').append('svg').selectAll('g').data(shapes)
var group = viewport.append('g')
我该如何用d3的方式处理这个问题?我试过shapes.filter(shape => shape.type === 'rect').forEach(/* ... */)
,但感觉我没有用d3的方式。感谢您提供有关如何处理此问题的任何线索!
我会使用路径,以及一个返回与d.type属性有关的路径的函数。
编辑:有点像这样,尽管你必须以某种方式指定你想要的符号的定位方式,因为在这个例子中,它们只会被画在彼此的顶部。
var drawers = {
rect: function(d) {
return 'M 0 0 l '+ d.size[0] + ' 0 l 0 ' + d.size[1] + ' l -' + d.size[0] + ' 0 l 0 -' + d.size[1];
},
triangle: function(d) {},
};
var g = d3.select('#mySvg').append('g');
var symbols = g.selectAll('.symbol')
.data(shapes);
symbols.enter()
.append('path')
.classed('symbol', true)
.attr({
d: function(d) {return drawers[d.type](d);}
});
最终的解决方案是使用d3.svg.symbol()
构造函数(假设shapes
是介绍性文章中描述的数组,type
的细微差异是triangle-up
、circle
或square
:
const center = [ w / 2, h / 2 ]
const vis = d3.select(container)
.append('svg')
.attr('width', w)
.attr('height', h)
const symbols = vis.selectAll('.symbol').data(shapes)
const getPathForShape = d => d3.svg.symbol().type(d.type).size(d.size)()
const paths = symbols.enter()
.append('path')
.classed('symbol', true)
.attr('d', getPathForShape)
.attr('fill', d => d.color)
.attr('x', center[0])
.attr('y', center[1])
然后使用力定向图()对其进行分布
const force = d3.layout.force()
.size([w, h])
.charge(-100)
.nodes(shapes)
.gravity(0.1)
.on('tick', _ => paths.attr('transform', d =>
'translate(' + d.x + ',' + d.y + ')'))
// simulate a static graph:
force.start()
for (var i = 0; i < 100; i++) force.tick()
force.stop()