使用相同的数据集绘制各种符号

时间:2016-05-17 15:06:21

标签: javascript d3.js

我有一个如下所示的数据集:

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方式。感谢有关如何处理此问题的任何线索!

2 个答案:

答案 0 :(得分:2)

我会使用路径,以及一个返回有关d.type属性的路径的函数。

编辑:有点像that,虽然你必须以某种方式指定你想要的符号的位置,因为在这个例子中,它们只是在彼此之上绘制。

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);}
  });

答案 1 :(得分:0)

最终的解决方案是使用d3.svg.symbol()构造函数(假设shapes是数组,如介绍帖子中所述,typetriangle-up的差别很小},circlesquare

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()