2012-06-19 4 views
39

Я использовал образец кода от this d3 project, чтобы узнать, как отображать графики d3, и я не могу заставить текст отображаться в середине кругов (аналогично this example и this example). Я посмотрел на другие примеры и попытался добавитьd3 Маркировка узлов

node.append("title").text("Node Name To Display") 

и

node.append("text") 
    .attr("text-anchor", "middle") 
    .attr("dy", ".3em").text("Node Name To Display") 

сразу после узла определяется, но только результаты, которые я вижу это «Node Name Для отображения» показывает, когда я зависать над каждым узлом. Он не отображается как текст внутри круга. Должен ли я писать свой собственный текстовый объект svg и определять координаты того, что он должен быть размещен на основе координат радиуса круга? Из двух других примеров, похоже, d3 уже так или иначе заботится об этом. Я просто не знаю подходящего атрибута для вызова/набора.

ответ

76

Есть lots of examples, показывающий, как добавить метки к граф и дерево визуализации, но я бы, вероятно, начать с этим, как наиболее простой:

Вы не разместил ссылку на ваш код, но я предполагаю, что node относится к выбору элементов окружения SVG. Вы не можете добавлять текстовые элементы в элементы окружности, потому что элементы окружности не являются containers; добавление текстового элемента в круг будет проигнорировано.

Обычно вы используете элемент G для группировки элемента окружности (или элемента изображения, как указано выше) и текстового элемента для каждого узла. Полученная структура выглядит следующим образом:

<g class="node" transform="translate(130,492)"> 
    <circle r="4.5"/> 
    <text dx="12" dy=".35em">Gavroche</text> 
</g> 

Используйте data-join для создания элементов G для каждого узла, а затем использовать selection.append, чтобы добавить круг и текстовый элемент для каждого. Что-то вроде этого:

var node = svg.selectAll(".node") 
    .data(nodes) 
    .enter().append("g") 
    .attr("class", "node") 
    .call(force.drag); 

node.append("circle") 
    .attr("r", 4.5); 

node.append("text") 
    .attr("dx", 12) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name }); 

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

<g class="nodes"> 
    <circle transform="translate(130,492)" r="4.5"/> 
    <circle transform="translate(110,249)" r="4.5"/> 
    … 
</g> 
<g class="labels"> 
    <text transform="translate(130,492)" dx="12" dy=".35em">Gavroche</text> 
    <text transform="translate(110,249)" dx="12" dy=".35em">Valjean</text> 
    … 
</g> 

И соответствующий JavaScript:

var circle = svg.append("g") 
    .attr("class", "nodes") 
    .selectAll("circle") 
    .data(nodes) 
    .enter().append("circle") 
    .attr("r", 4.5) 
    .call(force.drag); 

var text = svg.append("g") 
    .attr("class", "labels") 
    .selectAll("text") 
    .data(nodes) 
    .enter().append("text") 
    .attr("dx", 12) 
    .attr("dy", ".35em") 
    .text(function(d) { return d.name }); 

Этот метод используется в Mobile Patent Suits примере (с дополнительным текстовым элементом, используемым для создания белой тени).

1

Я нашел это руководство очень полезным в попытке сделать что-то подобное:

https://www.dashingd3js.com/svg-text-element

Основываясь на ссылке выше, этот код будет генерировать круг метки:

<!DOCTYPE html> 
<html> 
    <head> 
     <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> 
     <script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script> 
    </head> 
<body style="overflow: hidden;"> 
<div id="canvas" style="overflow: hidden;"></div> 

<script type="text/javascript"> 

    var graph = { 
     "nodes": [ 
      {name: "1", "group": 1, x: 100, y: 90, r: 10 , connected : "2"}, 
      {name: "2", "group": 1, x: 200, y: 50, r: 15, connected : "1"}, 
      {name: "3", "group": 2, x: 200, y: 130, r: 25, connected : "1"} 
     ] 
    } 

    $(document).ready(function() { 

     var width = 2000; 
     var height = 2000; 

     var svg = d3.select("#canvas").append("svg") 
       .attr("width", width) 
       .attr("height", height) 
       .append("g"); 

     var lines = svg.attr("class", "line") 
       .selectAll("line").data(graph.nodes) 
       .enter().append("line") 
       .style("stroke", "gray") // <<<<< Add a color 
       .attr("x1", function (d, i) { 
        return d.x 
       }) 
       .attr("y1", function (d) { 
        return d.y 
       }) 
       .attr("x2", function (d) { 
        return findAttribute(d.connected).x 
       }) 
       .attr("y2", function (d) { 
        return findAttribute(d.connected).y 
       }) 

     var circles = svg.selectAll("circle") 
       .data(graph.nodes) 
       .enter().append("circle") 
       .style("stroke", "gray") 
       .style("fill", "white") 
       .attr("r", function (d, i) { 
        return d.r 
       }) 
       .attr("cx", function (d, i) { 
        return d.x 
       }) 
       .attr("cy", function (d, i) { 
        return d.y 
       }); 

     var text = svg.selectAll("text") 
           .data(graph.nodes) 
           .enter() 
           .append("text"); 

     var textLabels = text 
      .attr("x", function(d) { return d.x; }) 
      .attr("y", function(d) { return d.y; }) 
      .text(function (d) { return d.name }) 
      .attr("font-family", "sans-serif") 
      .attr("font-size", "10px") 
      .attr("fill", "red"); 

    }); 

    function findAttribute(name) { 
     for (var i = 0, len = graph.nodes.length; i < len; i++) { 
      if (graph.nodes[i].name === name) 
       return graph.nodes[i]; // Return as soon as the object is found 
     } 
     return null; // The object was not found 
    } 


</script> 
</body> 
</html> 
+0

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

+0

@Whymarrh ответ обновлен –

2

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

nodes.forEach(function(v) { 
    var nd; 
    var cx = v.coord[0]; 
    var cy = v.coord[1]; 

    switch (v.shape) { 
    case "circle": 
     nd = svg.append("circle"); 
     break; 
    case "rectangle": 
     nd = svg.append("rect"); 
     break; 
    } 

    var w = 10; 
    var h = 10; 
    if (v.label != "") { 
    var lText = svg.append("text"); 

    lText.attr("x", cx) 
     .attr("y", cy + 5) 
     .attr("class", "labelText") 
     .text(v.label); 

    var bbox = lText.node().getBBox(); 
    w = Math.max(w,bbox.width); 
    h = Math.max(h,bbox.height); 
    } 

    var pad = 4; 

    switch (v.shape) { 
    case "circle": 
     nd.attr("cx", cx) 
     .attr("cy", cy) 
     .attr("r", Math.sqrt(w*w + h*h)/2 + pad); 
     break; 
    case "rectangle": 
     nd.attr("x", cx - w/2 - pad) 
     .attr("y", cy - h/2 - pad) 
     .attr("width", w + 2*pad) 
     .attr("height", h + 2*pad); 
     break; 
    } 

}); 

Обратите внимание, что форма добавляется текст добавляется, затем форма позиционируется для того, чтобы получить текст, чтобы показать сверху.