programing

d3.js의 노드 중앙에 레이블 배치

firstcheck 2021. 1. 14. 08:33
반응형

d3.js의 노드 중앙에 레이블 배치


나는 d3.js로 시작하고 각각 중앙 번호 레이블을 포함하는 노드 행을 만들려고합니다.

원하는 결과를 시각적으로 생성 할 수는 있지만 각 텍스트 요소에 대한 xy 좌표를 하드 코딩해야하므로 내가 한 방식은 최적이 아닙니다. 다음은 코드입니다.

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

node클래스는 사용자 정의 CSS 클래스 I는 별도로 정의한입니다 circle클래스 반면, 요소 nodes와는 labels명시 적으로 정의되지 않으며 그들은이에서 빌린 대답 .

보시다시피 각 텍스트 레이블의 위치는 하드 코딩되어 각 노드의 중앙에 나타납니다. 분명히 이것은 올바른 해결책이 아닙니다.

내 질문은 레이블의 위치가 원의 위치와 함께 자동으로 변경되도록 각 텍스트 레이블을 각 노드 원과 동적으로 올바르게 연결하는 방법입니다. 개념 설명은 코드 예제로 매우 환영합니다.


텍스트 앵커 D3에 의해 생성 된 SVG 요소에서 예상대로 속성이 작동합니다. 그러나 추가 할 필요가 text와를 circle공통으로 g수 있도록 요소 text와는 circle서로를 중심으로한다.

이를 위해 nodes변수를 다음과 같이 변경할 수 있습니다 .

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.yd.x문자열 단지 목록 대신 사용할 수 있습니다.

그런 다음, 교체 circletext다음 추가 인 코드를 :

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

Now, instead of changing the position of the circle you change the position of the g element which moves both the circle and the text.

Here is a JSFiddle showing centered text on circles.

If you want to have your text be in a separate g element so that it always appears on top, then use the d.x and d.y values set in the first g element's creation to transform the text.

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

The best answer came from the asker himself:

just a further observation: with only .attr("text-anchor", "middle") for each text element, the label is at the middle horizontally but slightly off vertically. I fixed this by adding attr("y", ".3em") (borrowed from examples at d3.js website), which seems to work well even for arbitrary size of node circle. However, what exactly this additional attribute does eludes my understanding. Sure, it does something to the y-coordinate of each text element, but why .3em in particular? It seems almost magical to me...

Just add .attr("text-anchor", "middle") to each text element.

Example:

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

This page describes what's going on under the svg hood when it comes to text elements. Understanding the underlying machinery and data structures helped me get a better handle on how I had to modify my code to get it working.

ReferenceURL : https://stackoverflow.com/questions/11857615/placing-labels-at-the-center-of-nodes-in-d3-js

반응형