2009-10-28 17 views
83

Sto lavorando su alcuni ECMAScript/JavaScript per un file SVG e ho bisogno di ottenere il width e height di un elemento text in modo da poter ridimensionare un rettangolo che lo circonda. In HTML sarei in grado di utilizzare gli attributi offsetWidth e offsetHeight sull'elemento, ma sembra che tali proprietà non siano disponibili.SVG ottiene larghezza elemento testo

Ecco un frammento con cui ho bisogno di lavorare. Devo modificare la larghezza del rettangolo ogni volta che cambio il testo, ma non so come ottenere l'effettivo width (in pixel) dell'elemento text.

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

Qualche idea?

risposta

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

e quindi impostare gli attributi del retto di conseguenza.

Collegamento: getBBox() nello standard SVG v1.1.

+1

Grazie. Ho anche trovato un'altra funzione che avrebbe potuto aiutare con la larghezza. textElement.getComputedTextLength(). Proverò entrambi stasera e vedrò quale funziona meglio per me. – spudly

+4

Stavo giocando con queste ultime settimane; il metodo getComputedTextLength() ha restituito lo stesso risultato di getBBox(). Larghezza per le cose che ho provato su, così ho appena andato con il rettangolo di selezione, come ho bisogno sia in larghezza che in altezza. Non sono sicuro se ci sono circostanze in cui la lunghezza del testo sarebbe stato diverso dalla larghezza: Penso che forse che metodo è fornito per aiutare con il layout di testo come testo frazionamento su più righe, mentre il rettangolo di selezione è un metodo generico disponibili su tutti gli elementi (?). – NickFitz

+0

Il collegamento a 'getBBox()' è spostato http://wiki.svg.org/index.php/GetBBox – RobM

5

Per quanto riguarda la lunghezza del testo, il collegamento sembra indicare che BBox e getComputedTextLength() potrebbero restituire valori leggermente diversi, ma piuttosto vicini tra loro.

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

+0

Grazie per questo link !! Ho dovuto passare attraverso tutti gli scenari da me, ma questo è davvero un buon riassunto ... Il mio problema stava usando getBBox() su un elemento tspan su Firefox ... Non potrebbe essere un problema più specifico e fastidioso .. . grazie ancora! –

2

Che ne dite di qualcosa di simile per la compatibilità:

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

Questo restituisce la media dei risultati validi di tre metodi. Potresti migliorarlo per escludere i valori anomali o per favorire getComputedTextLength se l'elemento è un elemento di testo.

Avviso: come dice il commento, getBoundingClientRect è difficile. Rimuoverlo dai metodi o utilizzare questo solo su elementi in cui getBoundingClientRect torneranno buoni risultati, in modo da nessuna rotazione e, probabilmente, nessun ridimensionamento (?)

+0

getBoundingClientRect funziona in un sistema di coordinate potenzialmente diverso dagli altri due. –

0

Non so perché, ma nessuno dei metodi di cui sopra lavoro per me. Ho avuto qualche successo con il metodo canvas, ma ho dovuto applicare tutti i tipi di fattori di scala. Anche con i fattori di scala ho ancora avuto risultati incoerenti tra Safari, Chrome e Firefox.

Così, ho provato la seguente:

  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;

lavorato impressionante e super preciso, ma solo in Firefox. Fattori di scala per il salvataggio per Chrome e Safari, ma nessuna gioia. Risulta che gli errori di Safari e Chrome non sono lineari con lunghezza della stringa o dimensione del carattere.

Quindi, l'approccio numero due. Non mi interessa molto l'approccio della forza bruta, ma dopo aver lottato con questo a intermittenza per anni ho deciso di provarlo. Ho deciso di generare valori costanti per ogni singolo carattere stampabile. Normalmente questo sarebbe un po 'noioso, ma fortunatamente Firefox sembra essere molto preciso.Ecco la mia parte di due soluzione di forza bruta:

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

Nota: Il frammento di cui sopra è per eseguito in Firefox per generare una serie accurata di valori. Inoltre, è necessario sostituire l'elemento 32 dell'array con il valore della larghezza dello spazio nel log della console.

ho semplicemente copiare il testo di Firefox su schermo, e incollarlo nel mio codice javascript. Ora che ho la matrice di lunghezze dei caratteri stampabili, posso implementare una funzione get width. Ecco il codice:

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

Beh, questo è tutto. Forza bruta, ma è super precisa in tutti e tre i browser, e il mio livello di frustrazione è andato a zero. Non sono sicuro per quanto tempo durerà come i browser si evolveranno, ma dovrebbe essere abbastanza lungo per me per sviluppare una tecnica di metrica dei caratteri robusta per il mio testo SVG.

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

ha lavorato per me in

Problemi correlati