Как сопоставить ширину текста с размером круга в пакете кругов D3

Используя D3, я отображаю кучу кругов разного размера, каждый из которых заполнен текстом. Я застрял в поиске правильного размера шрифта, чтобы текст правильно помещался в круг, в зависимости от его размера и длины текста. Длинный текст, возможно, следует разбивать на большее количество строк. Вот мой код:

var data = {
    "name": "",
    "children": [
        { "name": "This is a tag", "value": 242 },
        { "name": "Circle", "value": 162 },
        { "name": "Tree", "value": 80 },
        { "name": "My sentence is very long and needs breaks", "value": 80 },
    ]
}

var diameter = 300,
    format = d3.format(",d");

var bubble = d3.layout.pack()
    .sort(null)
    .size([diameter, diameter])
    .padding(1.5);

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

d3.json(data, function(error, root) {
  var node = svg.selectAll(".node")
      .data(bubble.nodes(data)
      .filter(function(d) { return !d.children; }))
    .enter().append("g")
      .attr("class", "node")
      .attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; });

  node.append("circle")
      .attr("r", function(d) { return d.r; })
      .style("fill", function(d) { return '#f88' });

  // text part
  node.append("text")
      .attr("dy", ".3em")
      .style("text-anchor", "middle")
      .style("font-size", function(d) { return Math.round(d.r/3)+'px'; })
      .text(function(d) { return d.name.substring(0, d.r / 3); });
});

d3.select(self.frameElement).style("height", diameter + "px");

Я также создал скрипт на http://jsfiddle.net/L4nMx/. Я думаю, что должен вычислить ширину текста и измените размер шрифта, пока он не будет соответствовать размеру круга или что-то в этом роде. Или есть какая-нибудь функция "strech", чтобы сделать это простым способом?


person quape    schedule 20.05.2014    source источник
comment
Этот вопрос касается аналогичной проблемы, он может быть полезен.   -  person Pablo Navarro    schedule 20.05.2014
comment
Привет @PabloNavarro, я просмотрел ответы и ссылку в комментарии @VividD, но ни один не говорит о методе переноса текста в этом популярном суть от Майка. Я знаю, что на самом деле он не использует круг, но имеет некоторую гибкость при разделении текста и не использует foreignObject, который не поддерживается IE... что вы думаете?   -  person FernOfTheAndes    schedule 20.05.2014
comment
Это немного сложнее, но в любом случае хорошее решение. Окончательное решение этой проблемы должно быть реализовано в SVG. Однако есть некоторые шаги в этом направлении.   -  person Pablo Navarro    schedule 20.05.2014
comment
Спасибо, эти решения полезны, хотя они касаются только переноса текста.   -  person quape    schedule 21.05.2014


Ответы (2)


Это решение меня пока устраивает. Это не точная математика, но в любом случае подходит.

Посмотрите его в действии на http://jsfiddle.net/L4nMx/3/.

  .style("font-size", function(d) {
      var len = d.name.substring(0, d.r / 3).length;
      var size = d.r/3;
      size *= 10 / len;
      size += 1;
      return Math.round(size)+'px';
  })
  .text(function(d) {
      var text = d.name.substring(0, d.r / 3);
      return text;
  });

Следующим шагом было бы разбить длинный текст на несколько строк, чтобы в таких случаях можно было увеличить размер шрифта, но мне не удалось решить эту проблему. В SVG это непросто, потому что невозможен простой разрыв строки. Возможно, сюда можно добавить решения для упаковки из комментариев в вопросе - как-то...

person quape    schedule 21.05.2014

Вот этот бл.окс https://bl.ocks.org/mbostock/1846692

что в основном

 node.append("circle")
      .attr("r", function(d) { return d.r; });

  node.append("text")
      .text(function(d) { return d.name; })
      .style("font-size", function(d) { return Math.min(2 * d.r, (2 * d.r - 8) / this.getComputedTextLength() * 24) + "px"; })
      .attr("dy", ".35em");
person Elise Chant    schedule 30.09.2017