Как разрыв строки в текст СВГ в JavaScript?
вот что у меня есть:
<path class="..." onmousemove="show_tooltip(event,'very long text
\n I would like to linebreak')" onmouseout="hide_tooltip()" d="..."/>
<rect class="tooltip_bg" id="tooltip_bg" ... />
<text class="tooltip" id="tooltip" ...>Tooltip</text>
<script>
<![CDATA[
function show_tooltip(e,text) {
var tt = document.getElementById('tooltip');
var bg = document.getElementById('tooltip_bg');
// set position ...
tt.textContent=text;
bg.setAttribute('width',tt.getBBox().width+10);
bg.setAttribute('height',tt.getBBox().height+6);
// set visibility ...
}
...
теперь мой очень длинный текст подсказки не имеет linebreak, даже если я использую alert(); он показывает мне, что текст на самом деле имеет две строки. (Он содержит"", хотя, как я могу удалить это, кстати?)
Я не могу заставить CDATA работать где угодно.
5 ответов:
это не то, что поддерживает SVG 1.1. SVG 1.2 имеет
textArea
элемент, с автоматическим переносом слов, но он не реализован во всех браузерах. SVG 2 не планирует реализациюtextArea
, но у него есть автоматический перенос текста.однако, учитывая, что вы уже знаете, где переносы строк должно происходить, вы можете разбить ваш текст на несколько
<tspan>
С каждогоx="0"
иdy="1.4em"
для имитации реальных строк текста. Для пример:<g transform="translate(123 456)"><!-- replace with your target upper left corner coordinates --> <text x="0" y="0"> <tspan x="0" dy="1.2em">very long text</tspan> <tspan x="0" dy="1.2em">I would like to linebreak</tspan> </text> </g>
конечно, поскольку вы хотите сделать это из JavaScript, вам придется вручную создавать и вставлять каждый элемент в DOM.
Я suppese вам уже удалось решить это, но если кто-то ищет подобное решение, то это сработало для меня:
g.append('svg:text') .attr('x', 0) .attr('y', 30) .attr('class', 'id') .append('svg:tspan') .attr('x', 0) .attr('dy', 5) .text(function(d) { return d.name; }) .append('svg:tspan') .attr('x', 0) .attr('dy', 20) .text(function(d) { return d.sname; }) .append('svg:tspan') .attr('x', 0) .attr('dy', 20) .text(function(d) { return d.idcode; })
есть 3 строки, разделенные linebreak.
С помощью решения tspan, скажем, вы не знаете заранее, где разместить свои разрывы строк: вы можете использовать эту приятную функцию, которую я нашел здесь: http://bl.ocks.org/mbostock/7555321
что автоматически делает разрывы строк для длинного текста svg для заданной ширины в пикселях.
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 ShowTooltip(evt, mouseovertext){ // Make tooltip text var tooltip_text = tt.childNodes.item(1); var words = mouseovertext.split("\\n"); var max_length = 0; for (var i=0; i<3; i++){ tooltip_text.childNodes.item(i).firstChild.data = i<words.length ? words[i] : " "; length = tooltip_text.childNodes.item(i).getComputedTextLength(); if (length > max_length) {max_length = length;} } var x = evt.clientX + 14 + max_length/2; var y = evt.clientY + 29; tt.setAttributeNS(null,"transform", "translate(" + x + " " + y + ")") // Make tooltip background bg.setAttributeNS(null,"width", max_length+15); bg.setAttributeNS(null,"height", words.length*15+6); bg.setAttributeNS(null,"x",evt.clientX+8); bg.setAttributeNS(null,"y",evt.clientY+14); // Show everything tt.setAttributeNS(null,"visibility","visible"); bg.setAttributeNS(null,"visibility","visible"); }
он разбивает текст на
\\n
и для каждого помещает каждый фрагмент в tspan. Затем он вычисляет размер требуемого поля на основе самой длинной длины текста и количества строк. Вам также нужно будет изменить текстовый элемент всплывающей подсказки, чтобы он содержал три tspans:<g id="tooltip" visibility="hidden"> <text><tspan>x</tspan><tspan x="0" dy="15">x</tspan><tspan x="0" dy="15">x</tspan></text> </g>
это предполагает, что у вас никогда не будет больше трех строк. Если вы хотите более трех строк, вы можете добавить больше tspans и увеличить длину из цикла for.
Я немного адаптировал решение от @steco, удалив зависимость от
d3
и добавитьheight
текста элемента в качестве параметраfunction wrap(text, width, height) { text.each(function(idx,elem) { var text = $(elem); text.attr("dy",height); var 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 (elem.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); } } }); }