簡體   English   中英

無法在D3條形圖中的x軸上包裝中文文本

[英]Unable to wrap the Chinese text on x-axis in D3 bar chart

我有一個D3條形圖,x軸上有中文和英文文本。 每當中文文本出現時,標簽就會重疊。 我無法將文本包裝成多行。 如果只是英文文本,我可以將其包裝。 如果也有中文文字,是否可以包裝文字?

片段

 var margin = { top: 10, right: 0, bottom: 58, left: 40 }; var width = 400 - margin.left - margin.right; var height = 400 - margin.top - margin.bottom; var barWidth = 40; var graph; var xScale; var yScale; var dataSet; dataSet = [{ desc: '即使句子沒有空格', val: 20 }, { desc: 'Sample text.即使句子沒有空格', val: 40 }, { desc: 'test3', val: 60 }, { desc: 'test4', val: 80 }, { desc: 'some dummy text here', val: 120 } ]; xScale = d3.scaleBand() .domain(dataSet.map(function(d) { return d.desc; })) .range([0, width]); yScale = d3.scaleLinear() .range([height, 0]) .domain([0, 1.15 * d3.max(dataSet, function(d) { return d.val; })]); graph = d3.select("#graph") .append("svg") .attr("class", "bar-chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); graph.append("g") .attr("class", "x-scale") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(xScale)) .selectAll(".tick text") .call(wrap, xScale.bandwidth()); graph.append("g") .attr("class", "y-scale") .call(d3.axisLeft(yScale).tickPadding(10)); graph .append("g") .attr('class', 'graph-placeholder') .selectAll("rect") .data(dataSet) .enter() .append("rect") .attr("class", "bar1") .attr("height", height) .attr("width", barWidth) .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2); graph .append("g") .attr('class', 'graph-main') .selectAll("bar1") .data(dataSet) .enter() .append("rect") .attr("class", "bar2") .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2) .attr("y", function(d) { return yScale(d.val); }) .attr("height", function(d) { return height - yScale(d.val); }) .attr("width", barWidth); graph .append("g") .attr('class', 'bar-label') .selectAll("text") .data(dataSet) .enter() .append("text") .text(d => d.val + '%') .attr("y", function(d) { return yScale(d.val) - 5; }).attr('x', function(d) { return xScale(d.desc) + ((xScale.bandwidth() - barWidth) / 2); }); function wrap(text, width) { text.each(function() { var text = d3.select(this), words = text.text().split(/\\s+/).reverse(), word, line = [], lineNumber = 0, lineHeight = 1, 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); } } }); } 
 .bar-chart { background-color: #ccc; } .bar2 { fill: steelblue; } .bar1 { fill: #f2f2f2; } text { font-size: 12px; /* text-anchor: middle; */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div class="container"> <div id="graph"></div> </div> 

提琴相同的片段。

您的wrap函數當前在空格( /\\s+/ )上分割,並將這些部分包裝在自己的<tspan>元素中。
它需要更智能才能包裝文字。

簡單的解決方法是將每個字符包裝在自己的<tspan>中。

 var margin = { top: 10, right: 0, bottom: 58, left: 40 }; var width = 400 - margin.left - margin.right; var height = 400 - margin.top - margin.bottom; var barWidth = 40; var graph; var xScale; var yScale; var dataSet; dataSet = [{ desc: '即使句子沒有空格', val: 20 }, { desc: 'Sample text.即使句子沒有空格', val: 40 }, { desc: 'test3', val: 60 }, { desc: 'test4', val: 80 }, { desc: 'some dummy text here', val: 120 } ]; xScale = d3.scaleBand() .domain(dataSet.map(function(d) { return d.desc; })) .range([0, width]); yScale = d3.scaleLinear() .range([height, 0]) .domain([0, 1.15 * d3.max(dataSet, function(d) { return d.val; })]); graph = d3.select("#graph") .append("svg") .attr("class", "bar-chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); graph.append("g") .attr("class", "x-scale") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(xScale)) .selectAll(".tick text") .call(wrap, xScale.bandwidth()); graph.append("g") .attr("class", "y-scale") .call(d3.axisLeft(yScale).tickPadding(10)); graph .append("g") .attr('class', 'graph-placeholder') .selectAll("rect") .data(dataSet) .enter() .append("rect") .attr("class", "bar1") .attr("height", height) .attr("width", barWidth) .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2); graph .append("g") .attr('class', 'graph-main') .selectAll("bar1") .data(dataSet) .enter() .append("rect") .attr("class", "bar2") .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2) .attr("y", function(d) { return yScale(d.val); }) .attr("height", function(d) { return height - yScale(d.val); }) .attr("width", barWidth); graph .append("g") .attr('class', 'bar-label') .selectAll("text") .data(dataSet) .enter() .append("text") .text(d => d.val + '%') .attr("y", function(d) { return yScale(d.val) - 5; }).attr('x', function(d) { return xScale(d.desc) + ((xScale.bandwidth() - barWidth) / 2); }); function wrap(text, width) { text.each(function() { var text = d3.select(this), // split on each character words = text.text().split('').reverse(), word, line = [], lineNumber = 0, lineHeight = 1, 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); // join with empty string tspan.text(line.join("")); if (tspan.node().getComputedTextLength() > width) { line.pop(); // join with empty string tspan.text(line.join("")); line = [word]; tspan = text.append("tspan").attr("x", 0).attr("y", y).attr("dy", ++lineNumber * lineHeight + dy + "em").text(word); } } }); } 
 .bar-chart { background-color: #ccc; } .bar2 { fill: steelblue; } .bar1 { fill: #f2f2f2; } text { font-size: 12px; /* text-anchor: middle; */ } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div class="container"> <div id="graph"></div> </div> 

但是這樣做的話,我們的行為與word-break: break-all相同word-break: break-all ,也就是說,它會破壞非CJK文本。
我們想要的就是word-break: normal行為。 為此,最好是使用HTML和CSS。

通過生成一個虛擬HTML元素,借助Range.getBoundingClientRect方法,我們可以檢查每個字符應在何處呈現:

 var margin = { top: 10, right: 0, bottom: 58, left: 40 }; var width = 400 - margin.left - margin.right; var height = 400 - margin.top - margin.bottom; var barWidth = 40; var graph; var xScale; var yScale; var dataSet; dataSet = [{ desc: '即使句子沒有空格', val: 20 }, { desc: 'Sample text.即使句子沒有空格', val: 40 }, { desc: 'test3', val: 60 }, { desc: 'test4', val: 80 }, { desc: 'some dummy text here', val: 120 } ]; xScale = d3.scaleBand() .domain(dataSet.map(function(d) { return d.desc; })) .range([0, width]); yScale = d3.scaleLinear() .range([height, 0]) .domain([0, 1.15 * d3.max(dataSet, function(d) { return d.val; })]); graph = d3.select("#graph") .append("svg") .attr("class", "bar-chart") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); graph.append("g") .attr("class", "x-scale") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(xScale)) .selectAll(".tick text") .call(wrap, xScale.bandwidth()); graph.append("g") .attr("class", "y-scale") .call(d3.axisLeft(yScale).tickPadding(10)); graph .append("g") .attr('class', 'graph-placeholder') .selectAll("rect") .data(dataSet) .enter() .append("rect") .attr("class", "bar1") .attr("height", height) .attr("width", barWidth) .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2); graph .append("g") .attr('class', 'graph-main') .selectAll("bar1") .data(dataSet) .enter() .append("rect") .attr("class", "bar2") .attr('x', d => xScale(d.desc) + (xScale.bandwidth() - barWidth) / 2) .attr("y", function(d) { return yScale(d.val); }) .attr("height", function(d) { return height - yScale(d.val); }) .attr("width", barWidth); graph .append("g") .attr('class', 'bar-label') .selectAll("text") .data(dataSet) .enter() .append("text") .text(d => d.val + '%') .attr("y", function(d) { return yScale(d.val) - 5; }).attr('x', function(d) { return xScale(d.desc) + ((xScale.bandwidth() - barWidth) / 2); }); function getLines(text, width) { // create a dummy element var dummy = d3.select('body') .append('p') .classed('dummy-text-wrapper', true) // set its size to the one we want .style('width', width + 'px') .text(text); var textNode = dummy.node().childNodes[0]; var lines = ['']; var range = document.createRange(); var current = 0; // get default top value range.setStart(textNode, 0); var prevTop = range.getBoundingClientRect().top; var nextTop = prevTop; // iterate through all characters while (current < text.length) { // move the cursor range.setStart(textNode, current+1); // check top position nextTop = range.getBoundingClientRect().top; if(nextTop !== prevTop) { // new line lines.push(""); } // add the current character to the last line lines[lines.length - 1] += text[current++]; prevTop = nextTop; } // clean up the DOM dummy.remove(); return lines; } function wrap(text, width) { text.each(function() { var text = d3.select(this), words = text.text(), lines = getLines(words, width), line = [], lineHeight = 1, y = text.attr("y"), dy = parseFloat(text.attr("dy")); text.text(''); lines.forEach(function(words, lineNumber) { text.append("tspan") .attr("x", 0) .attr("y", y) .attr("dy", lineNumber * lineHeight + dy + "em") .text(words); }); }); } 
 .bar-chart { background-color: #ccc; } .bar2 { fill: steelblue; } .bar1 { fill: #f2f2f2; } text { font-size: 12px; /* text-anchor: middle; */ } .dummy-text-wrapper { word-break: normal; display: inline-block; opacity: 0; position: absolute; } 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/d3/5.7.0/d3.min.js"></script> <div class="container"> <div id="graph"></div> </div> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM