2013-12-07 26 views
4

用d3.js玩了一會兒,看了很多例子,我就可以畫出多條弧線。每個人都以特定的程度開始和結束,並給予半徑。如何使用d3.js沿着弧內的textPath居中(水平和垂直)文本?

var dataset = { 
    "2":[{"degree1":0,     "degree2":1.5707963267949, 
      "label":"Sample Text Test"},  
     {"degree1":1.5707963267949, "degree2":3.1415926535898, 
      "label":"Lorem ipsum sample text"}, 
     {"degree1":3.1415926535898, "degree2":4.7123889803847, 
      "label":"Sample Text Text"}, 
     {"degree1":4.7123889803847, "degree2":6.2831853071796, 
      "label":"Lorem ipsum"}], 
    "1":[{"degree1":0,     "degree2":3.1415926535898, 
      "label":"Sample"}, 
     {"degree1":3.1415926535898, "degree2":6.2831853071796, 
      "label":"Text"}], 
    "0":[{"degree1":0,     "degree2":6.2831853071796, 
      "label":""}] 
    }, 
    width = 450, 
    height = 450, 
    radius = 75; 

// Helper methods 
var innerRadius = function(d, i, j) { 
    return 1 + radius * j; 
}; 

var outerRadius = function(d, i, j) { 
    return radius * (j + 1); 
}; 

var startAngle = function(d, i, j) { 
    return d.data.degree1; 
}; 

var endAngle = function(d, i, j) { 
    return d.data.degree2; 
}; 

var pie = d3.layout.pie() 
    .sort(null); 

var arc = d3.svg.arc() 
    .innerRadius(innerRadius) 
    .outerRadius(outerRadius) 
    .startAngle(startAngle) 
    .endAngle(endAngle); 

var svg = d3.select('body').append('svg') 
    .attr('width', width) 
    .attr('height', height) 
    .append('g') 
    .attr('transform', 'translate(' + (width >> 1) + ',' + (height >> 1) + ')'); 

var level = svg.selectAll('g') 
    .data(function(d) { 
     return d3.values(dataset); 
    }) 
    .enter() 
    .append('g'); 

var entry = level.selectAll('g') 
    .data(function(d, i) { 
     return pie(d); 
    }) 
    .enter() 
    .append('g'); 

entry.append('path') 
    .attr('fill', '#aaa') 
    .attr('d', arc) 
    .attr('id', function(d, i, j) { 
     return 'arc' + i + '-' + j; 
    }); 

var label = entry.append('text') 
    .style('font-size', '20px') 
    .attr('dx', function(d, i, j) { 
     return Math.round((d.data.degree2 - d.data.degree1) * 180/Math.PI); 
    }) 
    .attr('dy', function(d, i, j) { 
     return ((radius * (j + 1)) - (1 + radius * j)) >> 1; 
    }); 


label.append('textPath') 
    .attr('xlink:href', function(d, i, j) { 
     return '#arc' + i + '-' + j; 
    }) 
    .style('fill', '#000') 
    .text(function(d) { 
     return d.data.label; 
    }); 

http://jsfiddle.net/3FP6P/2/

enter image description here

但一些問題依然存在:

  1. 如何中心(臥式UND垂直)的沿內部的一個任意長度的textpath文本arc由innerRadius,outerRadius,startAngle和endAngle描述?
  2. 文字有時會粗體,有時不會。爲什麼?
  3. 字符間距看起來不像寫入a中一樣。有些字母作爲其他字母粘在一起。爲什麼?
  4. 字母不直接位於路徑上。有些似乎有點滑落。爲什麼?

回答

9

垂直對齊

您可以使用另一種圓弧半徑爲(innerRadius + outerRadius)/2,並用它作爲textPath的標籤。

請注意,即使您設置了innerRadius == outerRadius,D3也會繪製一條順時針移動,然後逆時針移動的路徑,使其自身翻倍。這變得很重要,同時試圖找出路徑中心的水平:它位於25%75%點,而0%50%點位於弧的兩端。

水平對齊

文本元素上的使用text-anchor: middle並在textPath設置startOffset25%(或75%)。

Demo

這是比手工計算dxdy更可靠的方法。

您應該嘗試一下Lars的建議,以進一步提高文本的質量和居中,您可能需要將text-rendering設置爲optimizeLegibility並與基線一起播放。

+2

您可能的意思是'startOffset',而不是'offsetStart',請參閱http://www.w3.org/TR/SVG11/text.html#TextPathElementStartOffsetAttribute。 –

+0

@ErikDahlström謝謝。修復。 –

+1

這是整潔。謝謝! –

4

問題2-4是由於字體呈現。在我的瀏覽器中,間距和字符大小等是一致的。你可以嘗試玩text-rendering attribute來改善事情。

要使文本居中,您需要設置alignment-baseline和/或dominant-baseline屬性。

如果這仍然不能提供您正在尋找的結果,請嘗試減小字體大小。這可能會有所幫助,因爲角色的輕微旋轉將不太明顯。

+1

垂直對齊使用'alignment-baseline'適用於我。 –