2013-05-22 13 views
78

Więc tutaj jest to, co mam:Jak przełamać tekst svg w 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 ... 
} 
... 

Teraz moja bardzo długi tekst podpowiedzi nie posiada linebreak, nawet jeśli używam alert(); pokazuje mi, że tekst rzeczywiście ma dwie linie. (Zawiera on znak "\", ale jak to usunąć?)
Nie mogę pobrać CDATA do pracy w dowolnym miejscu.

+2

Każda szansa to http://svgjs.com/ textflow/może pomóc w twojej podpowiedzi? –

Odpowiedz

103

To nie jest coś, co obsługuje SVG 1.1. SVG 1.2 ma element textArea z automatycznym zawijaniem słów, ale nie jest zaimplementowany we wszystkich przeglądarkach. SVG 2 does not plan on implementing textArea, ale ma on wartość auto-wrapped text.

Biorąc jednak pod uwagę, że już wie, gdzie powinien pojawić się swoimi linebreaks można złamać tekst w wielu <tspan> S, każda z x="0" i dy="1.4em" symulować rzeczywiste linie tekstu. Na przykład:

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

Oczywiście, skoro chcesz zrobić z JavaScript, będziesz musiał ręcznie utworzyć i wstawić każdy element do DOM.

+2

A jak rozpoznać, gdzie umieścić ' s'? Zastąpić? Rozdzielać? – sollniss

+1

Wypróbowałem 'var tspan = document.createElement ('tspan') \t \t tspan.setAttribute ('x', '0'); \t \t tspan.setAttribute ("dy", "1.2em "); \t \t tspan.textContent = tekst; \t tt.appendChild (tspan); ' nie pokazuje żadnego tekstu. – sollniss

+1

Czy chciałbyś wyjaśnić, dlaczego potrzebne jest * x = '0' dy = '1.2em' *? Rzeczywiście działa, tak jak powiedziałeś. Spodziewałem się jednak, że zadziała nawet bez tych atrybutów. Zamiast tego, nic nie jest wyświetlane ... Ponadto, nie jestem całkowicie jasny ** dlaczego ** w ogóle występuje rozłączenie linii. To nie jest tak, że ustawiliśmy szerokość kontenera na coś naprawionego, żeby mógł narzucić łamanie linii, prawda? –

8

myślę, że robi to, co chcesz:

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

Dzieli tekst na \\\n i każdy stawia każdy fragment w tspan. Następnie oblicza rozmiar wymaganego pudełka na podstawie najdłuższej długości tekstu i liczby linii. Potrzebny będzie również zmienić element tekstowy podpowiedzi zawierają trzy 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> 

ta zakłada, że ​​nie masz więcej niż trzy linie. Jeśli chcesz więcej niż trzy linie, możesz dodać więcej tspanów i zwiększyć długość pętli for.

18

I suppese ty alredy udało się go rozwiązać, ale jeśli ktoś szuka podobnego rozwiązania to ten pracował dla mnie:

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

Istnieją 3 linie oddzielone LINEBREAK.

+11

FWIW: wygląda na to, że OP był w użyciu czysty JavaScript; ta odpowiedź wydaje się być dźwiganiem [D3] (http://d3js.org/). –

+0

Używam D3, a Twoje podejście zadziałało dla mnie. Dziękujemy za przesłanie wiadomości. Zauważyłem, że najpierw muszę usunąć stare tspany, zanim dodałem nowe, takie jak to: focus.selectAll ("tspan"). Remove(); –

+0

Należy się wystrzegać tego podejścia, ponieważ zakłada on znaczniki , ponieważ prowadzi łańcuch .append(). Może to powodować niewielkie bóle głowy za pomocą CSS w zależności od tego, co chcesz zrobić. – seneyr

9

Dzięki rozwiązaniu tspan, powiedzmy, że nie wiem z góry gdzie umieścić swoje podziały wierszy: można wykorzystać ten miły funkcji, które znalazłem tutaj: http://bl.ocks.org/mbostock/7555321

który automatycznie robi podziały wiersza na długo tekst svg dla danej szerokości w pikselach.

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

I przystosowany nieco roztworu przez @steco usunięcie zależność od d3 i dodanie height elementu tekstu jako parametr

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); 
     } 
    } 
    }); 
} 
Powiązane problemy