score:2

Accepted answer

I'd go with paths, and a function that'd return the path regarding the d.type attribute.

Edit : something a little bit like that, although you'll have to specify somehow the way you want the symbols to be positioned because with this example, they'll just be drawn on top of each other.

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

score:0

The final solution was to use the d3.svg.symbol() constructor (given that shapes is the array as described in the introductory post, with the slight difference of type being either triangle-up, circle or 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])

they were then distributed by using a force directed graph:

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

Related Query

More Query from same tag