2009-10-28 44 views
83

Tôi đang làm việc trên một số ECMAScript/JavaScript cho tệp SVG và cần lấy các phần tử widthheight của một phần tử text để tôi có thể thay đổi kích thước hình chữ nhật bao quanh nó. Trong HTML, tôi có thể sử dụng các thuộc tính offsetWidthoffsetHeight trên phần tử nhưng dường như các thuộc tính đó không khả dụng.SVG nhận chiều rộng phần tử văn bản

Đây là một đoạn mà tôi cần phải làm việc. Tôi cần phải thay đổi chiều rộng của hình chữ nhật bất cứ khi nào tôi thay đổi văn bản nhưng tôi không biết làm thế nào để có được thực tế width (tính bằng pixel) của phần tử text.

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

Bất kỳ ý tưởng nào?

Trả lời

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

và sau đó đặt thuộc tính của rect cho phù hợp.

Liên kết: getBBox() trong tiêu chuẩn SVG v1.1.

+1

Cảm ơn. Tôi cũng tìm thấy một chức năng khác có thể giúp với chiều rộng. textElement.getComputedTextLength(). Tôi sẽ thử cả tối nay và xem cái nào hiệu quả hơn cho tôi. – spudly

+4

Tôi đã chơi với những tuần trước; phương thức getComputedTextLength() trả về kết quả tương tự như getBBox() chiều rộng cho những thứ tôi đã thử nó, vì vậy tôi chỉ cần đi với hộp giới hạn, vì tôi cần cả chiều rộng và chiều cao. Tôi không chắc liệu có bất kỳ trường hợp nào khi độ dài văn bản khác với chiều rộng: Tôi nghĩ có lẽ phương thức đó được cung cấp để trợ giúp bố cục văn bản như tách văn bản trên nhiều dòng, trong khi hộp giới hạn là phương pháp chung trên tất cả các phần tử (?). – NickFitz

+0

Liên kết tới 'getBBox() 'đã chuyển sang http://wiki.svg.org/index.php/GetBBox – RobM

5

Về độ dài của văn bản, liên kết dường như cho biết BBox và getComputedTextLength() có thể trả về các giá trị hơi khác nhau, nhưng những giá trị này gần giống nhau.

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

+0

Cảm ơn bạn đã liên kết !! Tôi đã phải đi qua tất cả các kịch bản của bản thân mình, nhưng đây là một bản tóm tắt thực sự tốt ... Vấn đề của tôi là sử dụng getBBox() trên một yếu tố Tspan trên firefox ... Nó không thể là một vấn đề cụ thể hơn và gây phiền nhiễu .. cảm ơn một lần nữa! –

2

Làm thế nào về một cái gì đó như thế này cho khả năng tương thích:

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

này trả mức trung bình của bất kỳ kết quả hợp lệ trong ba phương pháp. Bạn có thể cải thiện nó để loại bỏ các ngoại lệ hoặc ủng hộ getComputedTextLength nếu phần tử là phần tử văn bản.

Cảnh báo: Như nhận xét cho biết, getBoundingClientRect rất khó. Loại bỏ nó khỏi các phương pháp hoặc chỉ sử dụng các yếu tố này ở những nơi mà getBoundingClientRect sẽ trả lại kết quả tốt, vì vậy không có vòng quay và có thể không có tỷ lệ (?)

+0

getBoundingClientRect hoạt động trong một hệ thống phối hợp có khả năng khác với hai hệ kia. –

0

Không chắc chắn lý do nào, nhưng không có phương pháp nào ở trên phù hợp với tôi. Tôi đã có một số thành công với phương pháp canvas, nhưng tôi đã phải áp dụng tất cả các loại yếu tố quy mô. Ngay cả với các yếu tố tỷ lệ tôi vẫn có kết quả không phù hợp giữa Safari, Chrome và Firefox.

Vì vậy, tôi đã cố gắng như sau:

  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;

Làm việc tuyệt vời và siêu chính xác, nhưng chỉ trong Firefox. Quy mô các yếu tố để giải cứu cho Chrome và Safari, nhưng không có niềm vui. Hóa ra rằng lỗi của Safari và Chrome không tuyến tính với chiều dài chuỗi hoặc kích thước phông chữ.

Vì vậy, hãy tiếp cận số hai. Tôi không quan tâm nhiều đến cách tiếp cận bạo lực, nhưng sau khi đấu tranh với điều này và tắt trong nhiều năm, tôi đã quyết định thử. Tôi quyết định tạo ra các giá trị không đổi cho mỗi ký tự có thể in riêng lẻ. Thông thường điều này sẽ khá tẻ nhạt, nhưng may mắn là Firefox sẽ trở nên siêu chính xác.Dưới đây là hai phần brute giải pháp lực của tôi:

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

Lưu ý: Đoạn trên đã để thực hiện trong Firefox để tạo ra một mảng chính xác về giá trị. Ngoài ra, bạn phải thay thế mục mảng 32 bằng giá trị độ rộng khoảng trống trong nhật ký bảng điều khiển.

Tôi chỉ cần sao chép Firefox trên văn bản màn hình và dán vào mã javascript của tôi. Bây giờ tôi có dãy độ dài ký tự có thể in được, tôi có thể thực hiện chức năng lấy độ rộng. Đây là mã:

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

Vâng, đó là nó. Sức mạnh vũ phu, nhưng nó là siêu chính xác trong cả ba trình duyệt, và mức độ thất vọng của tôi đã đi đến số không. Bạn không chắc chắn nó sẽ kéo dài bao lâu khi các trình duyệt phát triển, nhưng nó sẽ đủ dài để tôi phát triển một kỹ thuật số liệu phông chữ mạnh mẽ cho văn bản SVG của tôi.

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

làm việc cho tôi trong

Các vấn đề liên quan