2012-11-05 31 views
60

Tôi đang sử dụng D3 để tạo biểu đồ thanh (Tôi đã điều chỉnh mã từ this example). Các nhãn tôi đang sử dụng trên x -axis là một vài từ dài mỗi từ và vì điều này làm cho tất cả các nhãn trùng lặp, tôi cần phải phá vỡ các nhãn này trên các dòng. (Sẽ tốt nếu tôi có thể thay thế tất cả các khoảng trống trong mỗi nhãn bằng dòng mới.)Làm cách nào để bao gồm dòng mới trong nhãn trong biểu đồ D3?

Ban đầu tôi đã thử bằng cách thay thế các khoảng trắng bằng các dòng mới (&#xA;) và đặt xml:space="preserve" trên các yếu tố của nhãn '<text>. Thật không may, nó chỉ ra rằng SVG không tôn trọng tài sản này. Tiếp theo, tôi đã cố gắng bọc mỗi từ trong một <tspan> mà sau này tôi có thể tạo kiểu. Tôi qua mỗi nhãn thông qua chức năng này:

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

nhưng điều này chỉ đặt theo nghĩa đen <tspan> s vào đầu ra. Làm thế nào tôi có thể bọc nhãn văn bản của tôi trong tspan s (hoặc làm điều gì đó khác) để nhãn của tôi không trùng lặp?

+0

Đây có phải là câu hỏi trùng lặp không? http://stackoverflow.com/questions/4991171/auto-line-wrapping-in-svg-text –

+1

@PaulArmstrong không thực sự, OP cần chèn văn bản không phải là autowrap của 'tspan' với externalObject (đó là quá mức cần thiết và không được hỗ trợ bởi IE9 (và 10?) – Duopixel

Trả lời

81

tôi đã kết thúc bằng cách sử dụng đoạn mã sau để phá vỡ mỗi x trục nhãn trên dòng:

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

Lưu ý rằng điều này giả định rằng các nhãn đã được tạo ra. (Nếu bạn theo dõi the canonical histogram example thì các nhãn sẽ được thiết lập theo cách bạn cần.) Cũng không có bất kỳ logic ngắt dòng thực nào; chức năng chuyển đổi mọi không gian thành một dòng mới. Điều này phù hợp với mục đích của tôi tốt nhưng bạn có thể cần phải chỉnh sửa dòng split() để thông minh hơn về cách phân đoạn các phần của chuỗi thành các dòng.

+5

Đây chính xác là những gì tôi cần, cảm ơn bạn Đối với những người có thể ở trong tình huống tương tự, tôi nên chỉ ra rằng 'd' đây là một điểm dữ liệu và * không * chuỗi bạn đang định dạng, vì vậy '.split()' (ít nhất là đối với tôi) yêu cầu thay đổi thành 'd.description.split (" \ n ");'. –

+1

Hoàn toàn độc đáo. – aendrew

+0

thanks – GSD

7

yếu tố văn bản SVG không hỗ trợ văn bản và đóng gói, do đó, có hai lựa chọn:

  • chia văn bản thành nhiều yếu tố văn bản SVG
  • sử dụng một div overlay HTML trên đầu trang của SVG

Xem nhận xét của Mike Bostock về điều này here.

+0

nhờ liên kết tới nhận xét – ptim

-1

sử dụng <tspan>

và trong nv.d3

nv.models.axis = function() {

...

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

thay đổi tất cả các lần xuất hiện của .text (.html (

0

Ngoài ra còn có this câu trả lời trên w cắt nhãn dài.

<!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> 

và file dữ liệu "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

Cái gì tôi đã tìm thấy là hữu ích được sử dụng một 'foreignObject' thẻ thay vì văn bản hoặc các yếu tố tspan. Điều này cho phép nhúng HTML đơn giản, cho phép các từ tự động ngắt.Thông báo trước là kích thước tổng thể của nhu cầu cụ thể cuộc họp đối tượng:

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

Dù yếu tố mà bạn đặt bên trong của đối tượng này sau đó có thể thu được bằng d3.select/selectAll để cập nhật giá trị văn bản tự động là tốt.

1

Nhìn xung quanh, tôi thấy rằng Mike Bostock đã cung cấp giải pháp cho phép bạn bao quanh văn bản.

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

Để thực hiện nó trên mã của tôi (Tôi đang sử dụng sơ đồ cây sụp đổ). Tôi chỉ đơn giản là sao chép phương pháp "bọc".

Sau đó nối sau

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

Tôi không thấy bất kỳ lý do này không nên làm việc cho một lực lượng trực tiếp, thanh hoặc bất kỳ mô hình khác

Sửa đổi:

Tôi đã sửa đổi chức năng bọc sau đây cho bất cứ ai đọc này và đang sử dụng đồ thị collapisible. Sự thay đổi trong thuộc tính "x" thiết lập sự sắp xếp một cách chính xác, gia tăng linenumber được thực hiện trên một dòng riêng biệt như các vấn đề đã được ghi trong mã ban đầu và "y" đã được thiết lập thành 0 nếu không vấn đề sẽ xảy ra trong đó khoảng cách dòng tăng lên mỗi dòng.

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); 
      } 
     } 
    }); 
} 
Các vấn đề liên quan