Размещение меток в центре узлов в d3.js


я начинаю с d3.JS, и я пытаюсь создать ряд узлов, каждый из которых содержит по центру знака.

Я могу получить желаемый результат визуально, но способ, которым я это сделал, вряд ли является оптимальным, поскольку он включает в себя жесткое кодирование координат x-y для каждого текстового элемента. Ниже приведен код:

var svg_w = 800;
var svg_h = 400;
var svg = d3.select("body")
    .append("svg")
    .attr("width", svg_w)
    .attr("weight", svg_h);

var dataset = [];
for (var i = 0; i < 6; i++) {
    var datum = 10 + Math.round(Math.random() * 20);
    dataset.push(datum);
}

var nodes = svg.append("g")
               .attr("class", "nodes")
               .selectAll("circle")
               .data(dataset)
               .enter()
               .append("circle")
               .attr("class", "node")
               .attr("cx", function(d, i) {
                   return (i * 70) + 50;
               })
               .attr("cy", svg_h / 2)
               .attr("r", 20);

var labels = svg.append("g")
                .attr("class", "labels")
                .selectAll("text")
                .data(dataset)
                .enter()
                .append("text")
                .attr("dx", function(d, i) {
                    return (i * 70) + 42
                })
                .attr("dy", svg_h / 2 + 5)
                .text(function(d) {
                    return d;
                });

The node класс-это пользовательский класс CSS, который я определил отдельно для circle элементы, тогда как классы nodes и labels явно не определены и они заимствованы из этого ответа.

как видно, расположение каждой текстовой метки жестко закодировано так, что она появляется в центре каждого узла. Очевидно, что это не правильное решение.

мой вопрос заключается в том, как я должен правильно связать каждую текстовую метку с каждым узлом круга динамически, так что если позиционирование метки изменяется вместе с тем из круга автоматически. Концептуальное объяснение чрезвычайно приветствуется с примером кода.

3   51   2012-08-08 08:21:06

3 ответа:

The текст якоря атрибут работает, как ожидалось, на элементе svg, созданном D3. Однако вам нужно добавить text и circle в общей g элемент, чтобы гарантировать, что text и circle центрируются друг с другом.

для этого вы можете изменить свой nodes переменная to:

var nodes = svg.append("g")
           .attr("class", "nodes")
           .selectAll("circle")
           .data(dataset)
           .enter()
           // Add one g element for each data node here.
           .append("g")
           // Position the g element like the circle element used to be.
           .attr("transform", function(d, i) {
             // Set d.x and d.y here so that other elements can use it. d is 
             // expected to be an object here.
             d.x = i * 70 + 50,
             d.y = svg_h / 2;
             return "translate(" + d.x + "," + d.y + ")"; 
           });

отметим, что dataset теперь список объектов, так что d.y и d.x можно использовать вместо просто списка веревка.

затем заменить circle и text добавить код на следующий:

// Add a circle element to the previously added g element.
nodes.append("circle")
      .attr("class", "node")
      .attr("r", 20);

// Add a text element to the previously added g element.
nodes.append("text")
     .attr("text-anchor", "middle")
     .text(function(d) {
       return d.name;
      });
, вместо того, чтобы изменять положение circle вы меняете положение g элемент, который перемещает оба circle и text.

здесь JSFiddle отображение центрированного текста на кругах.

если вы хотите, чтобы ваш текст был в отдельном g элемент, так что он всегда появляется на вершине, а затем использовать элемент d.x и d.y значения, установленные в первом элемента transform текст.

var text = svg.append("svg:g").selectAll("g")
         .data(force.nodes())
         .enter().append("svg:g");

text.append("svg:text")
    .attr("text-anchor", "middle")
    .text(function(d) { return d.name; });

text.attr("transform",  function(d) {
      return "translate(" + d.x + "," + d.y + ")"; 
    });

лучший ответ пришел от Аскера:

просто дальнейшее наблюдение :только с.attr ("text-anchor", " middle") для каждого текстового элемента метка находится посередине горизонтально, но немного от вертикали. Я исправил это, добавив attr ("y",".3ем") (заимствовано из примеров на d3.JS website), который, кажется, работает хорошо даже для произвольного размера окружности узла. Впрочем, что именно это дополнительный атрибут действительно ускользает от моего понимания. Конечно что-то к y-координате каждого текстового элемента, но почему .В 3ем конкретно? Мне это кажется почти волшебным...

просто добавить .attr("text-anchor", "middle") к каждому текстовому элементу.

пример:

node.append("text")
    .attr("x", 0)
    .attr("dy", ".35em")
    .attr("text-anchor", "middle")
    .text(function(d) { return d.name; });

на этой странице описывает, что происходит под капотом svg когда дело доходит до текстовых элементов. Понимание основных механизмов и структур данных помогло мне лучше разобраться в том, как я должен был изменить свой код, чтобы заставить его работать.