JavaScript içinde bir svg metni nasıl satır kırılır?


107

İşte sahip olduğum şey:

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

Artık çok uzun araç ipucu metnimde satır sonu yok, alert () kullansam bile; bana metnin aslında iki satıra sahip olduğunu gösteriyor. (Yine de "\" içeriyor, bu arada bunu nasıl kaldırırım?)
CDATA'yı hiçbir yerde çalıştıramıyorum.


2
Bu svgjs.com/textflow'un ipucunuza yardımcı olma ihtimali var mı?
Alvin K.

@AlvinK. bağlantı koptu. Yeni konumu bulmaya çalıştım ama başarısız oldum.
guettli

Yanıtlar:


150

Bu, SVG 1.1'in desteklediği bir şey değil. SVG 1.2, textAreaotomatik kelime kaydırmalı öğesine sahiptir, ancak tüm tarayıcılarda uygulanmamıştır. SVG 2 , uygulamayı planlamaztextArea , ancak otomatik olarak kaydırılmış metni vardır .

Ancak, zaten satır aralıkları meydana nereye biliyoruz ki verilen, birden metninizi kırabilir <tspan>ile, s her x="0"ve dy="1.4em"metnin gerçek çizgilerini taklit etmek. Örneğin:

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

Elbette, bunu JavaScript'ten yapmak istediğiniz için, her bir öğeyi manuel olarak oluşturmanız ve DOM'a eklemeniz gerekir.


2
Ve nereye koyacağımı nasıl anlarım <tspan>s? Değiştirilsin mi? Bölünmüş?
sollniss

2
Denedim var tspan = document.createElement('tspan') tspan.setAttribute('x','0'); tspan.setAttribute('dy','1.2em'); tspan.textContent = text; tt.appendChild(tspan); hiçbir metin göstermiyor.
sollniss

2
Neden x = '0' dy = '1.2em' gerektiğine değinmek ister misiniz ? Dediğin gibi gerçekten işe yarıyor. Ancak, bu özellikler olmadan da çalışmasını bekliyordum. Bunun yerine, hiçbir şey görüntülenmiyor ... Ayrıca, satır kırılmasının neden oluştuğunu tam olarak bilmiyorum. Konteynırın genişliğini, satır kırmayı empoze edebilmesi için sabit bir şey ayarlamadık, değil mi?
Konrad Viltersten

4
x=0mutlak bir koordinattır: metin bölümünü mevcut koordinat sisteminin başlangıç ​​noktasına taşıyın . transformÖznitelik gelemanının yeni bir akım koordinat sistemi tanımlamaktadır ve metin sola dayalı olduğunu varsayarak, tspan sola hareket etmektedir. Bu, bir taşıma dönüş talimatı gibi davranır. dy=1.2ema, göreceli mevcut metin parçasına göre bu miktar, metin parçasını hareket ettirmek: koordinatı. Bu, satır besleme talimatı gibi davranır. Kombine, bir CR / LF elde edersiniz.
Sergiu Dumitriu

Henüz denemedim: Bunu grup olmadan da yapabilir misin? <text x = "100" y = "100"> <tspan x = "100" y = "100"> çok uzun metin </tspan> <tspan x = "100" y = "115"> linebreak </tspan> </text> ??
Richard

25

Sanırım siz alredy bunu çözmeyi başardınız, ancak birisi benzer bir çözüm arıyorsa, o zaman bu benim için çalıştı:

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

Satır sonu ile ayrılmış 3 satır vardır.


21
FWIW: Görünüşe göre OP saf JavaScript kullanıyordu; Bu cevap yararlanarak gibi görünüyor D3 .
Ben Mosher

D3 kullanıyorum ve yaklaşımınız benim için çalıştı. Gönderdiğiniz için teşekkürler. Yenilerini eklemeden önce eski çay aralıklarını şu şekilde silmem gerektiğini anladım: focus.selectAll ("tspan"). Remove ();
Darren Parker

1
Bu yaklaşımla, .append () zincirinden dolayı <tspan> etiketlerini iç içe geçirdiğine dikkat edin. Bu, ne yapmak istediğinize bağlı olarak CSS ile bazı küçük baş ağrılarına neden olabilir.
seneyr

@Seneyr tarafından açıklanan yuvalanmayı önleyen bir yaklaşım için buraya bakın
bszom

16

Tspan çözümüyle, satır sonlarınızı nereye koyacağınızı önceden bilmediğinizi varsayalım: burada bulduğum bu güzel işlevi kullanabilirsiniz: http://bl.ocks.org/mbostock/7555321

Bu, piksel cinsinden belirli bir genişlik için uzun metin svg için otomatik olarak satır kesmeleri yapar.

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

9

Sanırım bu istediğini yapıyor:

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

Metni böler ve \\\nher bir parçayı bir tspan'ye yerleştirir. Ardından, en uzun metin uzunluğuna ve satır sayısına bağlı olarak gerekli kutunun boyutunu hesaplar. Ayrıca araç ipucu metin öğesini de üç çay kaşığı içerecek şekilde değiştirmeniz gerekecektir:

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

Bu, asla üçten fazla satırınız olmadığını varsayar. Üçten fazla satır istiyorsanız, daha fazla çay kaşığı ekleyebilir ve for döngüsünün uzunluğunu artırabilirsiniz.


Neden "\\\n"değil "\n"mi?
ralien

3

javascript yerine HTML kullanın

<html>
  <head><style> * { margin: 0; padding: 0; } </style></head>
  <body>
    <h1>svg foreignObject to embed html</h1>

    <svg
      xmlns="http://www.w3.org/2000/svg"
      viewBox="0 0 300 300"
      x="0" y="0" height="300" width="300"
    >

      <circle
        r="142" cx="150" cy="150"
        fill="none" stroke="#000000" stroke-width="2"
      />

      <foreignObject
        x="50" y="50" width="200" height="200"
      >
        <div
          xmlns="http://www.w3.org/1999/xhtml"
          style="
            width: 196px; height: 196px;
            border: solid 2px #000000;
            font-size: 32px;
            overflow: auto; /* scroll */
          "
        >
          <p>this is html in svg 1</p>
          <p>this is html in svg 2</p>
          <p>this is html in svg 3</p>
          <p>this is html in svg 4</p>
        </div>
      </foreignObject>

    </svg>

</body></html>


Sanırım "JavaScript yerine SVG kullanın" demek istediniz
Valerio Bozz

"SVG'de HTML", benim için en iyi çözüm!
Kévin Berthommier

2

Çözümü @steco ile biraz uyarladım, bağımlılığı yerine d3değiştirdim jqueryve heightmetin elemanını parametre olarak ekledim

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);
      }
    }
  });
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.