D3.js
を使用しています。このCSSクラスに相当するSVGを見つけたいと思います。これにより、含まれているdivからテキストが流出した場合に省略記号が追加されます。
.ai-Ellipsis {
display: block;
white-space: nowrap;
overflow: hidden;
text-overflow: Ellipsis;
-o-text-overflow: Ellipsis;
-moz-binding: url(<q>assets/xml/Ellipsis.xml#Ellipsis</q>);
}
これは私のSVGです。
<g class="bar" transform="translate(0,39)">
<text class="label" x="-3" y="6.5" dy=".35em" text-anchor="start">Construction</text>
<rect height="13" width="123"></rect>
</g>
次のように生成されます。
barEnter.append("text").attr("class", "label")
.attr("x", -3).attr("y", function() { return y.rangeBand() / 2})
.attr("dy", ".35em").attr("text-anchor", "start")
.text(function(d) {
return d.Name;
});
現在、テキストはオーバーフローしており、rect要素と重なっています。
「テキストが特定の幅を超える場合は、トリミングして楕円を追加する」と言える方法はありますか?
私はSVGの同等のCSSクラスを認識していませんが、foreignObject
を使用してSVGにHTMLを埋め込むことができます。これにより、この機能にアクセスできるようになり、一般に柔軟性が高まります(たとえば、自動改行を簡単に行うことができます)。
完全な例については here を参照してください。
テキストをオーバーフローさせるラッパー関数:
function wrap() {
var self = d3.select(this),
textLength = self.node().getComputedTextLength(),
text = self.text();
while (textLength > (width - 2 * padding) && text.length > 0) {
text = text.slice(0, -1);
self.text(text + '...');
textLength = self.node().getComputedTextLength();
}
}
使用法:
text.append('tspan').text(function(d) { return d.name; }).each(wrap);
私はd3に依存しないネイティブ関数を実装しました。この関数は3つの方法のフォールバックを実装します。
function textEllipsis(el, text, width) {
if (typeof el.getSubStringLength !== "undefined") {
el.textContent = text;
var len = text.length;
while (el.getSubStringLength(0, len--) > width) {}
el.textContent = text.slice(0, len) + "...";
} else if (typeof el.getComputedTextLength !== "undefined") {
while (el.getComputedTextLength() > width) {
text = text.slice(0,-1);
el.textContent = text + "...";
}
} else {
// the last fallback
while (el.getBBox().width > width) {
text = text.slice(0,-1);
// we need to update the textContent to update the boundary width
el.textContent = text + "...";
}
}
}
function trimText(text, threshold) {
if (text.length <= threshold) return text;
return text.substr(0, threshold).concat("...");
}
この関数を使用して、SVGノードのテキストを設定します。しきい値の値(20など)はユーザーによって異なります。これは、ノードテキストから最大20文字を表示することを意味します。 20文字を超えるテキストはすべてトリムされ、トリムテキストの最後に「...」が表示されます。
使用例:
var self = this;
nodeText.text(x => self.trimText(x.name, 20)) // nodeText is the text element of the SVG node
User2846569によって提案されたwrap関数の単なる更新。 getComputedTextLength()は非常に遅くなる傾向があるため、...
[〜#〜]編集[〜#〜]
私はuser2846569のアドバイスを熱心に適用し、「バイナリ」検索を使用して、いくつかのキャリブレーションとパラメーター化された精度でバージョンを作成しました。
'use strict';
var width = 2560;
d3.select('svg').attr('width', width);
// From http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript
function randomString(length, chars) {
var result = '';
for (var i = length; i > 0; --i)
result += chars[Math.floor(Math.random() * chars.length)];
return result;
}
function wrap() {
var self = d3.select(this),
textWidth = self.node().getComputedTextLength(), // Width of text in pixel.
initialText = self.text(), // Initial text.
textLength = initialText.length, // Length of text in characters.
text = initialText,
precision = 10, //textWidth / width, // Adjustable precision.
maxIterations = 100; // width; // Set iterations limit.
while (maxIterations > 0 && text.length > 0 && Math.abs(width - textWidth) > precision) {
text = /*text.slice(0,-1); =*/(textWidth >= width) ? text.slice(0, -textLength * 0.15) : initialText.slice(0, textLength * 1.15);
self.text(text + '...');
textWidth = self.node().getComputedTextLength();
textLength = text.length;
maxIterations--;
}
console.log(width - textWidth);
}
var g = d3.select('g');
g.append('text').append('tspan').text(function(d) {
return randomString(width, 'a');
}).each(wrap);
CSSを書いても動作しません。その代わりにロジックを記述し、文字列に「...」を追加します。