2012-11-05 45 views
60

我使用D3生成條形圖(我修改了this example的代碼)。我在x軸上使用的標籤每個都是幾個字,並且由於這會使所有標籤重疊,所以我需要在這些線之間打破這些標籤。 (這將是很好,如果我可以代替用換行每個標籤的所有空間。)如何在D3圖表中的標籤中包含換行符?

我原本想這與文字換行(&#xA;)替換空間和設置在標籤上<text>元素xml:space="preserve"。不幸的是,事實證明,SVG不尊重這個屬性。接下來,我嘗試將每個單詞包裝在一個<tspan>中,以便以後可以使用。我通過每個標籤通過這個功能:

function (text) { 
    return '<tspan>' + text.replace(/ /g, '</tspan><tspan>') + '</tspan>'; 
} 

但這只是把文字<tspan> s轉換輸出。如何將我的文字標籤包裹在tspan(或做其他事情)以便我的標籤不重疊?

+0

這是一個重複的問題? http://stackoverflow.com/questions/4991171/auto-line-wrapping-in-svg-text –

+1

@PaulArmstrong不是真的,OP需要插入'tspan'不是自動翻譯文本與foreignObject(這是一個矯枉過正和不受支持這是我所需要的,謝謝。對於那些可能處於類似情況的人,我應該指出'd'這裏是一個數據點(通過IE9(和10?)。) – Duopixel

回答

81

我結束了使用下面的代碼跨行打破各X軸標籤:

var insertLinebreaks = function (d) { 
    var el = d3.select(this); 
    var words = d.split(' '); 
    el.text(''); 

    for (var i = 0; i < words.length; i++) { 
     var tspan = el.append('tspan').text(words[i]); 
     if (i > 0) 
      tspan.attr('x', 0).attr('dy', '15'); 
    } 
}; 

svg.selectAll('g.x.axis g text').each(insertLinebreaks); 

注意,這個假設的標籤已經被創建。 (如果您按照the canonical histogram example那麼標籤將按照您需要的方式設置。)也沒有任何真正的換行邏輯存在;該函數將每個空間轉換爲換行符。這符合我的目的,但您可能需要編輯split()行,以便將字符串的各個部分劃分爲多行。

+5

和* not *你正在格式化的字符串,所以'.split()'(至少對我來說)需要修改'd.description.split(「\ n」);'。 –

+1

很好。 – aendrew

+0

謝謝很多...它的工作很完美 – GSD

7

SVG的文本元素不支持文字環繞,所以有兩種選擇:

  • 分裂文成多個SVG的文本元素
  • 對SVG的頂部使用的覆蓋HTML DIV

請參閱Mike Bostock對此的評論here

+0

感謝您對評論的鏈接 – ptim

-1

使用<tspan>

和nv.d3

nv.models.axis =函數(){

...

 .select('text') 
      .attr('dy', '0em') 
      .attr('y', -axis.tickPadding()) 
      .attr('text-anchor', 'middle') 
      .text(function(d,i) { 
       var v = fmt(d); 
       return ('' + v).match('NaN') ? '' : v; 
      }); 

變化的.text的所有匹配(到.html(

0

還有this回答w說唱長標籤。

<!DOCTYPE html> 
<meta charset="utf-8"> 
<style> 

.bar { 
    fill: steelblue; 
} 

.bar:hover { 
    fill: brown; 
} 

.title { 
    font: bold 14px "Helvetica Neue", Helvetica, Arial, sans-serif; 
} 

.axis { 
    font: 10px sans-serif; 
} 

.axis path, 
.axis line { 
    fill: none; 
    stroke: #000; 
    shape-rendering: crispEdges; 
} 

.x.axis path { 
    display: none; 
} 

</style> 
<body> 
<script src="http://d3js.org/d3.v3.min.js"></script> 
<script> 

var margin = {top: 80, right: 180, bottom: 80, left: 180}, 
    width = 960 - margin.left - margin.right, 
    height = 500 - margin.top - margin.bottom; 

var x = d3.scale.ordinal() 
    .rangeRoundBands([0, width], .1, .3); 

var y = d3.scale.linear() 
    .range([height, 0]); 

var xAxis = d3.svg.axis() 
    .scale(x) 
    .orient("bottom"); 

var yAxis = d3.svg.axis() 
    .scale(y) 
    .orient("left") 
    .ticks(8, "%"); 

var svg = d3.select("body").append("svg") 
    .attr("width", width + margin.left + margin.right) 
    .attr("height", height + margin.top + margin.bottom) 
    .append("g") 
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); 

d3.tsv("data.tsv", type, function(error, data) { 
    x.domain(data.map(function(d) { return d.name; })); 
    y.domain([0, d3.max(data, function(d) { return d.value; })]); 

    svg.append("text") 
     .attr("class", "title") 
     .attr("x", x(data[0].name)) 
     .attr("y", -26) 
     .text("Why Are We Leaving Facebook?"); 

    svg.append("g") 
     .attr("class", "x axis") 
     .attr("transform", "translate(0," + height + ")") 
     .call(xAxis) 
    .selectAll(".tick text") 
     .call(wrap, x.rangeBand()); 

    svg.append("g") 
     .attr("class", "y axis") 
     .call(yAxis); 

    svg.selectAll(".bar") 
     .data(data) 
    .enter().append("rect") 
     .attr("class", "bar") 
     .attr("x", function(d) { return x(d.name); }) 
     .attr("width", x.rangeBand()) 
     .attr("y", function(d) { return y(d.value); }) 
     .attr("height", function(d) { return height - y(d.value); }); 
}); 

function wrap(text, width) { 
    text.each(function() { 
    var text = d3.select(this), 
     words = text.text().split(/\s+/).reverse(), 
     word, 
     line = [], 
     lineNumber = 0, 
     lineHeight = 1.1, // ems 
     y = text.attr("y"), 
     dy = parseFloat(text.attr("dy")), 
     tspan = text.text(null).append("tspan").attr("x", 0).attr("y", y).attr("dy", dy + "em"); 
    while (word = words.pop()) { 
     line.push(word); 
     tspan.text(line.join(" ")); 
     if (tspan.node().getComputedTextLength() > width) { 
     line.pop(); 
     tspan.text(line.join(" ")); 
     line = [word]; 
     tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); 
     } 
    } 
    }); 
} 

function type(d) { 
    d.value = +d.value; 
    return d; 
} 

</script> 

和數據文件「data.tsv」:

name value 
Family in feud with Zuckerbergs .17 
Committed 671 birthdays to memory .19 
Ex is doing too well .10 
High school friends all dead now .15 
Discovered how to 「like」 things mentally .27 
Not enough politics .12 
6

事情我已經發現有用的是使用「foreignObject」的標籤,而不是文本或TSPAN元素。這允許HTML的簡單嵌入,允許單詞自然地被打破。需要說明的是對象符合特定需求的整體尺寸:

var myLabel = svg.append('foreignObject') 
    .attr({ 
     height: 50, 
     width: 100, // dimensions determined based on need 
     transform: 'translate(0,0)' // put it where you want it... 
    }) 
    .html('<div class"style-me"><p>My label or other text</p></div>'); 

你把這個對象的內部無論元素可以在以後使用d3.select/selectAll更新文本值動態也可以獲得。

1

環顧四周,我發現Mike Bostock提供了一個解決方案,可以讓您將文字換成圓形。

http://bl.ocks.org/mbostock/7555321

要實現它在我的代碼(我用摺疊的樹圖)。我只是複製了「包裝」方法。

然後附加以下

// Standard code for a node  
    nodeEnter.append("text") 
     .attr("x", function(d) { return d.children || d._children ? -10 : 10; }) 
     .attr("dy", ".35em") 
     .text(function(d) { return d.text; }) 
     // New added line to call the function to wrap after a given width 
     .call(wrap, 40); 

我看不出有任何理由這應該不是一個力執導,酒吧或任何其他模式工作

修訂:

我已經任何閱讀本文並使用可摺疊圖形的人都可以將wrap函數修改爲以下內容。 「x」屬性的更改正確設置了分配,隨着問題在原始代碼中出現,「y」已被硬設置爲零,在單獨的行上執行增加的布料數量,否則會發生行間距增加每一行。

function wrap(text, width) { 
    text.each(function() { 
     var text = d3.select(this), 
     words = text.text().split(/\s+/).reverse(), 
     word, 
     line = [], 
     lineNumber = 0, 
     y = text.attr("y"), 
     dy = parseFloat(text.attr("dy")), 
     lineHeight = 1.1, // ems 
     tspan = text.text(null).append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", y).attr("dy", dy + "em");  
     while (word = words.pop()) { 
      line.push(word); 
      tspan.text(line.join(" ")); 
      var textWidth = tspan.node().getComputedTextLength(); 
      if (tspan.node().getComputedTextLength() > width) { 
       line.pop(); 
       tspan.text(line.join(" ")); 
       line = [word]; 
       ++lineNumber; 
       tspan = text.append("tspan").attr("x", function(d) { return d.children || d._children ? -10 : 10; }).attr("y", 0).attr("dy", lineNumber * lineHeight + dy + "em").text(word); 
      } 
     } 
    }); 
} 
相關問題