Question

I've see the Example of D3.js-Voronoi Tessellation.But I want to put some text in each of polygons instead of a circle,Here is my js code:

var width = 600, height = 400;

var vertices = d3.range(20).map(function(d){
  return [Math.random() * width, Math.random() * height]
});

var voronoi = d3.geom.voronoi();

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

path = svg.append("g").selectAll("path");

svg.selectAll("info")
    .data(vertices.slice(1))
    .enter().append("text")
    .attr("transform", function(d) {
      return "translate(" + d + ")";
    })
    .text("someText")
    .attr("shape-rendering","crispEdges")
    .style("text-anchor","middle");

redraw();

function redraw(){
  path = path
      .data(voronoi(vertices), polygon);

  path.exit().remove();

  path.enter().append("path")
      .attr("class", function(d, i) {return "q" + (i % 9) + "-9";})
      .attr("d", polygon);

  path.order();
}

function polygon(d){
  return "M" + d.join("L") + "Z";
}

I have a JSFiddle for that basic example here: my voronoi code

now, I want each of the polygons' text in the center of the polygon, and don't cross with the polygon's border. If the polygon have not enough space to contain the all text, just contain the first part of it! Let me know if there is anything I can do to solve this issue, thank you!

PS:I'm so sorry to my English, yes, it's so poor! :)

Was it helpful?

Solution

Have a look at this example http://bl.ocks.org/mbostock/6909318 , you probably want to place the text at the polygon centroid and not the seed (point) used to determine the voronoi tessellation.

That should fix the majority of your layout issues.

Automatically scaling the text to fit is a little bit harder, if you are willing to scale and rotate the text you can use a technique similar to the following to determine the length of the line at that point:

https://mathoverflow.net/questions/116418/find-longest-segment-through-centroid-of-2d-convex-polygon

Then you need to determine the angle of the line. I have a plugin that should help with that: http://bl.ocks.org/stephen101/7640188/3ffe0c5dbb040f785b91687640a893bae07e36c3

Lastly you need to scale and rotate the text to fit. To determine the width of the text use getBBox() on the text element:

var text = svg.append("svg:text")
    .attr("x", 480)
    .attr("y", 250)
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .style("font", "300 128px Helvetica Neue")
    .text("Hello, getBBox!");

var bbox = text.node().getBBox();

Then you use the angle you calculated earlier to scale and rotate your text:

text.attr("transform", "rotate(40) scale(7)")

I would love to give a complete example but this is quite a bit of work to get it right.

There are other options to achieve the same effect but none of them are simple (ie you could anneal the layout similar to the way d3 does the Sankey layout)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top