2012-08-08 64 views
51

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

node類是我爲circle元素單獨定義自定義CSS類,而類nodeslabels沒有明確定義,他們是從這個answer借來的。

如圖所示,每個文本標籤的位置都是硬編碼的,因此它出現在每個節點的中心。顯然,這不是正確的解決方案。

我的問題是,我應該如何正確地將每個文本標籤與每個節點圓圈動態關聯,以便如果標籤的位置隨着圓的位置自動變化。代碼示例非常歡迎概念性解釋。

+1

錨文本似乎沒有直接D3工作還沒有,但你嘗試作爲CSS文本對齊簡單的東西?這應該做的伎倆! http://www.w3schools.com/cssref/pr_text_text-align.asp另請嘗試查看d3 Google羣組中的這類帖子:https://groups.google.com/forum/#!searchin/d3 -js/text-align/d3-js/M6a-97ajkWs/rHJV4_WrhX0J%5B1-25%5D – paxRoman 2012-08-08 08:39:59

+1

你在哪裏得到文字定位符在d3中不起作用的想法? – 2012-08-08 13:56:54

+0

幾個月前,他們沒有工作......感謝澄清:)很高興看到這個問題的簡單方法 – paxRoman 2012-08-08 14:51:37

回答

61

text-anchor屬性按預期在D3創建的svg元素上工作。但是,您需要將textcircle附加到常見的g元素中,以確保textcircle相互居中。

要做到這一點,您可以在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; 
     }); 

現在,而不是改變的位置circle如果改變了移動既circletextg元素的位置。

這裏是一個JSFiddle顯示圓圈上居中的文字。

如果您希望您的文字是在一個單獨的g元素,使其始終在頂部出現,然後使用d.xd.y值在第一g元素的創作設置爲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 + ")"; 
    }); 
+0

感謝您的答案!看起來你的方法類似於[答案](http://stackoverflow.com/questions/11102795/d3-node-labeling/11109803#11109803)中概述的第一種方法,這意味着每個標籤將被繪製*在其頂部僅限於其圓*,但將被繪製*在其他圓圈之下*。是否可以使用相同答案中概述的雙數據連接方法來完成? (這是我模仿我的嘗試)。謝謝! – skyork 2012-08-08 14:35:09

+0

我爲此做了更新。你需要改變的兩件事情是讓你的數據成爲一個對象列表而不是一串字符串,這樣就可以爲每個字符串存儲'y'和'x',並將你的文本放在一個'g'元素中,這樣'g'元素可以被轉換。 – 2012-08-08 14:52:00

+0

如果我正確地理解了上面更新的代碼,首先創建一個'g'元素,並在其中爲數組中的數據創建一系列'g'元素,然後在這些''' g'元素?有什麼讓我困惑的是'text.append(「svg:text」)...',這裏的'text'代表一系列'g'元素嗎?如果是這樣,D3如何爲這些'g'元素*創建一個'text'元素?語法有點誤導。 – skyork 2012-08-08 17:04:50

23

最佳答案came from the asker自己:

只是進一步的觀察:只。attr(「text-anchor」,「middle」) 對於每個文本元素,標籤位於水平中間,但是垂直略微偏離 。我通過添加attr(「y」,「.3em」) (從d3.js網站上的示例中借用)來解決此問題,即使對於任意大小的節點圓,似乎也能很好地運行 。然而,這個額外的屬性究竟是怎麼迴避我的理解。當然,它確實對每個文本元素的y座標有一些東西,但是爲什麼.3em在 特別是?對我來說這似乎很神奇...

只需將.attr("text-anchor", "middle")添加到每個文本元素。

例子:

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

忽略選定的答案。這是一個更好的方法。 – Matt 2017-02-04 04:54:40

+0

哇。好事我滾動到下一個答案。我懶惰沒有閱讀所選擇的答案。 – Martin 2017-03-22 04:57:34

+0

使用這個時,我的HTML有文本,但它並沒有出現在我的實際節點中。 – 2017-12-16 06:20:54