2009-10-28 11 views
83

Pracuję nad niektóre ECMAScript/JavaScript dla pliku SVG i trzeba uzyskać width i height elementu text, dzięki czemu można zmienić rozmiar prostokąta, który go otacza. W HTMLu będę mógł używać atrybutów offsetWidth i offsetHeight na elemencie, ale wydaje się, że te właściwości są niedostępne.SVG uzyskać szerokość elementu tekstowego

Oto fragment, że muszę pracować. Potrzebuję zmienić szerokość prostokąta za każdym razem, gdy zmieniam tekst, ale nie wiem, jak uzyskać rzeczywisty width (w pikselach) elementu text.

<rect x="100" y="100" width="100" height="100" /> 
<text>Some Text</text> 

Wszelkie pomysły?

Odpowiedz

125
var bbox = textElement.getBBox(); 
var width = bbox.width; 
var height = bbox.height; 

, a następnie odpowiednio ustaw atrybuty rect.

Link: getBBox() w standardzie SVG v1.1.

+1

Dzięki. Znalazłem także inną funkcję, która mogła pomóc w szerokości. textElement.getComputedTextLength(). Wypróbuję oba dziś wieczorem i zobaczę, które działa lepiej dla mnie. – spudly

+4

Grałem z tymi w zeszłym tygodniu; Metoda getComputedTextLength() zwróciła ten sam wynik co getBBox(). width dla rzeczy, na których go wypróbowałem, więc po prostu wybrałem ramkę ograniczającą, ponieważ potrzebowałem zarówno szerokości jak i wysokości. Nie jestem pewien, czy istnieją jakiekolwiek okoliczności, gdy długość tekstu byłaby inna niż szerokość: myślę, że być może ta metoda jest dostarczana, aby pomóc w układaniu tekstu, na przykład dzieleniu tekstu na wiele linii, podczas gdy ramka ograniczająca jest dostępną ogólną metodą na wszystkich (?) elementach. – NickFitz

+0

Link do 'getBBox()' został przeniesiony na http://wiki.svg.org/index.php/GetBBox – RobM

5

Odnośnie długości tekstu link wydaje się wskazywać BBox i getComputedTextLength() może zwrócić nieco inne wartości, ale te, które są dość blisko siebie.

http://bl.ocks.org/MSCAU/58bba77cdcae42fc2f44

+0

Dziękuję za ten link !! Musiałem sam przejść przez wszystkie scenariusze, ale to jest naprawdę dobre podsumowanie ... Mój problem polegał na użyciu getBBox() na elemencie Tspan na firefoxie ... To nie może być bardziej specyficzny i denerwujący problem .. . dzięki jeszcze raz! –

2

Jak o czymś takim dla Kompatybilność:

function svgElemWidth(elem) { 
    var methods = [ // name of function and how to process its result 
     { fn: 'getBBox', w: function(x) { return x.width; }, }, 
     { fn: 'getBoundingClientRect', w: function(x) { return x.width; }, }, 
     { fn: 'getComputedTextLength', w: function(x) { return x; }, }, // text elements only 
    ]; 
    var widths = []; 
    var width, i, method; 
    for (i = 0; i < methods.length; i++) { 
     method = methods[i]; 
     if (typeof elem[method.fn] === 'function') { 
      width = method.w(elem[method.fn]()); 
      if (width !== 0) { 
       widths.push(width); 
      } 
     } 
    } 
    var result; 
    if (widths.length) { 
     result = 0; 
     for (i = 0; i < widths.length; i++) { 
      result += widths[i]; 
     } 
     result /= widths.length; 
    } 
    return result; 
} 

ta zwraca średnią wszelkich ważnych wyników z trzech metod. Możesz go poprawić, aby odrzucić wartości odstające lub faworyzować getComputedTextLength, jeśli element jest elementem tekstowym.

Ostrzeżenie: Zgodnie z komentarzem, getBoundingClientRect jest trudne. Albo usunąć go z metodami lub korzystać z tego tylko na elementach gdzie getBoundingClientRect powrócą dobre wyniki, więc nie ma rotacji i prawdopodobnie bez skalowania (?)

+0

Funkcja getBoundingClientRect działa w potencjalnie różnicowym systemie współrzędnych na dwa pozostałe. –

0

Nie wiem dlaczego, ale żadna z powyższych metod pracy dla mnie. Osiągnąłem sukces dzięki metodzie canvas, ale musiałem zastosować wszystkie rodzaje współczynników skali. Nawet przy współczynnikach skalowania wciąż miałem niespójne wyniki między przeglądarkami Safari, Chrome i Firefox.

Tak, próbowałem następujące:

  var div = document.createElement('div'); 
 
      div.style.position = 'absolute'; 
 
      div.style.visibility = 'hidden'; 
 
      div.style.height = 'auto'; 
 
      div.style.width = 'auto'; 
 
      div.style.whiteSpace = 'nowrap'; 
 
      div.style.fontFamily = 'YOUR_FONT_GOES_HERE'; 
 
      div.style.fontSize = '100'; 
 
      div.style.border = "1px solid blue"; // for convenience when visible 
 

 
      div.innerHTML = "YOUR STRING"; 
 
      document.body.appendChild(div); 
 
      
 
      var offsetWidth = div.offsetWidth; 
 
      var clientWidth = div.clientWidth; 
 
      
 
      document.body.removeChild(div); 
 
      
 
      return clientWidth;

Pracował niesamowite i bardzo precyzyjny, ale tylko w Firefoksie. Skaluj czynniki na ratunek dla Chrome i Safari, ale bez radości. Okazuje się, że błędy przeglądarki i Chrome nie są liniowe ani z długością ani z rozmiarem czcionki.

więc podejście numer dwa. Nie przejmuję się brutalnym podejściem, ale po wielu latach próbowałem z nim walczyć i postanowiłem spróbować. Postanowiłem wygenerować stałe wartości dla każdej indywidualnej postaci do druku. Normalnie byłoby to trochę nudne, ale na szczęście Firefox okazał się bardzo dokładny.Oto moje dwie części brute force rozwiązanie:

<body> 
 
     <script> 
 
      
 
      var div = document.createElement('div'); 
 
      div.style.position = 'absolute'; 
 
      div.style.height = 'auto'; 
 
      div.style.width = 'auto'; 
 
      div.style.whiteSpace = 'nowrap'; 
 
      div.style.fontFamily = 'YOUR_FONT'; 
 
      div.style.fontSize = '100';   // large enough for good resolution 
 
      div.style.border = "1px solid blue"; // for visible convenience 
 
      
 
      var character = ""; 
 
      var string = "array = ["; 
 
      for(var i=0; i<127; i++) { 
 
       character = String.fromCharCode(i); 
 
       div.innerHTML = character; 
 
       document.body.appendChild(div); 
 
       
 
       var offsetWidth = div.offsetWidth; 
 
       var clientWidth = div.clientWidth; 
 
       console.log("ASCII: " + i + ", " + character + ", client width: " + div.clientWidth); 
 
       
 
       string = string + div.clientWidth; 
 
       if(i<126) { 
 
        string = string + ", "; 
 
       } 
 

 
       document.body.removeChild(div); 
 
       
 
      } 
 
     
 
      var space_string = "! !"; 
 
      div.innerHTML = space_string; 
 
      document.body.appendChild(div); 
 
      console.log("space width: " + div.clientWidth - space_string.charCodeAt(0)*2); 
 
      document.body.removeChild(div); 
 

 
      string = string + "]"; 
 
      div.innerHTML = string; 
 
      document.body.appendChild(div); 
 
      </script> 
 
    </body>

Uwaga: Powyższy fragment został wykonany w Firefoksie do generować dokładny tablicę wartości. Musisz również zastąpić element tablicy 32 wartością szerokości spacji w dzienniku konsoli.

Po prostu skopiuj tekst na ekranie Firefoksa i wklej go do kodu javascript. Teraz, gdy mam tablicę długości znaków do wydrukowania, mogę zaimplementować funkcję get get. Oto kod:

const LCARS_CHAR_SIZE_ARRAY = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 26, 46, 63, 42, 105, 45, 20, 25, 25, 47, 39, 21, 34, 26, 36, 36, 28, 36, 36, 36, 36, 36, 36, 36, 36, 27, 27, 36, 35, 36, 35, 65, 42, 43, 42, 44, 35, 34, 43, 46, 25, 39, 40, 31, 59, 47, 43, 41, 43, 44, 39, 28, 44, 43, 65, 37, 39, 34, 37, 42, 37, 50, 37, 32, 43, 43, 39, 43, 40, 30, 42, 45, 23, 25, 39, 23, 67, 45, 41, 43, 42, 30, 40, 28, 45, 33, 52, 33, 36, 31, 39, 26, 39, 55]; 
 

 

 
    static getTextWidth3(text, fontSize) { 
 
     let width = 0; 
 
     let scaleFactor = fontSize/100; 
 
     
 
     for(let i=0; i<text.length; i++) { 
 
      width = width + LCARS_CHAR_SIZE_ARRAY[text.charCodeAt(i)]; 
 
     } 
 
     
 
     return width * scaleFactor; 
 
    }

Cóż, to jest to. Brutalna siła, ale jest super dokładna we wszystkich trzech przeglądarkach, a mój poziom frustracji spadł do zera. Nie wiem, jak długo potrwa, gdy przeglądarki będą się rozwijać, ale powinienem być wystarczająco długi, aby opracować solidną technikę pomiarów czcionek dla mojego tekstu SVG.

1
document.getElementById('yourTextId').getComputedTextLength(); 

pracował dla mnie w

Powiązane problemy