font - svg y javascript
Cómo linebreak un svg texto dentro de javascript? (5)
Con la solución tspan, digamos que no sabes de antemano dónde ubicar tus saltos de línea: puedes usar esta bonita función que encontré aquí: http://bl.ocks.org/mbostock/7555321
Eso automáticamente hace saltos de línea para svg largo de texto para un ancho determinado en píxeles.
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);
}
}
});
}
Entonces aquí está lo que tengo:
<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 ...
}
...
Ahora mi texto de información muy larga no tiene un salto de línea, aunque si uso alert (); me muestra que el texto realmente TIENE dos líneas. (Sin embargo, contiene una "/", ¿cómo elimino esa?)
No puedo hacer que CDATA funcione en ninguna parte.
Creo que esto hace lo que quieres:
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");
}
Divide el texto en ///n
y para cada uno coloca cada fragmento en un tspan. Luego calcula el tamaño de la caja requerida en función de la longitud de texto más larga y el número de líneas. También necesitará cambiar el elemento de texto de información sobre herramientas para que contenga tres 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>
Esto supone que nunca tienes más de tres líneas. Si desea más de tres líneas, puede agregar más tspans y aumentar la longitud del bucle for.
Esto no es algo que SVG 1.1 admite. SVG 1.2 tiene el elemento textArea
, con textArea
palabra automático, pero no está implementado en todos los navegadores. SVG 2 no planea implementar textArea
, pero sí tiene texto envuelto automáticamente .
Sin embargo, dado que ya sabe dónde deberían ocurrir los saltos de línea, puede dividir su texto en múltiples <tspan>
s, cada uno con x="0"
y dy="1.4em"
para simular líneas reales de texto. Por ejemplo:
<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>
Por supuesto, como quiera hacer eso desde JavaScript, deberá crear e insertar manualmente cada elemento en el DOM.
He adaptado un poco la solución mediante @steco, eliminando la dependencia de d3
y agregando la height
del elemento de texto como parámetro
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);
}
}
});
}
Supongo que ya se las arregló para resolverlo, pero si alguien está buscando una solución similar, esto funcionó para mí:
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; })
Hay 3 líneas separadas con linebreak.