2010-06-29 28 views
28

Tôi đang tạo một hộp văn bản SVG bằng cách sử dụng thư viện Raphael và điền nó bằng một chuỗi động được trích xuất từ ​​một tài liệu XML.Làm cách nào để xác định độ rộng hộp văn bản SVG hoặc ngắt dòng sau ký tự 'x'?

Đôi khi, chuỗi này dài hơn canvas Tôi đang đặt hộp văn bản, vì vậy tôi cần giới hạn chiều rộng của hộp sẽ tự ngắt dòng (tôi không thể tìm thấy bằng chứng nào về việc này có thể) HOẶC đảm bảo rằng ngắt dòng '\ n' được chèn sau một số ký tự nhất định.

Vì vậy, (1) đây có phải là lựa chọn tốt nhất không? Và (2) làm thế nào tôi sẽ làm điều này?

Trả lời

46

Không có thuộc tính cho gói văn bản, nhưng có một mẹo đơn giản mà bạn có thể sử dụng. Thêm một từ tại một thời điểm vào đối tượng văn bản và khi nó quá rộng, hãy thêm nguồn cấp dữ liệu dòng. Bạn có thể sử dụng hàm getBBox() để xác định chiều rộng. Về cơ bản, bạn mô phỏng một máy đánh chữ cũ thời. Đây là một mẫu của một số mã sẽ làm điều này cho bạn. Bạn có thể dễ dàng biến điều này thành một hàm đơn giản có văn bản và chiều rộng.

var r = Raphael(500, 500); 
var t = r.text(100, 100).attr('text-anchor', 'start'); 
var maxWidth = 100; 

var content = "Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate. "; 
var words = content.split(" "); 

var tempText = ""; 
for (var i=0; i<words.length; i++) { 
    t.attr("text", tempText + " " + words[i]); 
    if (t.getBBox().width > maxWidth) { 
    tempText += "\n" + words[i]; 
    } else { 
    tempText += " " + words[i]; 
    } 
} 

t.attr("text", tempText.substring(1)); 
+0

Thnx mate bạn đã lưu trong ngày! – chchrist

+0

Tôi đã viết một thư viện về cơ bản chỉ có điều này, có tên là raphael-paragraph. Xem câu trả lời của tôi dưới đây. –

3

Giải pháp đánh dấu là chậm đối với một lượng lớn văn bản (firefox 11). Tôi nghĩ rằng đó là bởi vì văn bản được trả lại nhiều lần để nhận được BBOX. chức năng sau đây hiệu quả hơn đối với số lượng văn bản lớn nhưng có lẽ ít chính xác hơn (mã từ raphaelmarkup project):

/** 
* @param t a raphael text shape 
* @param width - pixels to wrapp text width 
* modify t text adding new lines characters for wrapping it to given width. 
*/ 
rm._textWrapp = function(t, width) { 
    var content = t.attr("text"); 
    var abc="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    t.attr({'text-anchor': 'start', "text": abc}); 
    var letterWidth=t.getBBox().width/abc.length; 
    t.attr({"text": content}); 
    var words = content.split(" "), x=0, s=[]; 
    for (var i = 0; i < words.length; i++) { 
     var l = words[i].length; 
     if(x+l>width) { 
      s.push("\n") 
      x=0; 
     } 
     else { 
      x+=l*letterWidth; 
     } 
     s.push(words[i]+" "); 
    } 
    t.attr({"text": s.join("")}); 
}; 
+0

Đẹp, nhưng 'if (x + l> chiều rộng) {' trông giống như một sai lầm - nó xử lý chiều rộng chữ trung bình của từ cuối cùng trong mỗi bài kiểm tra là 1px. Hoạt động tốt hơn nhiều nếu bạn mất mệnh đề 'else' và đặt' x + = l * letterWidth; 'vào đầu mỗi vòng lặp' for'. Ngoài ra ''text-anchor': 'start',' là không cần thiết - không cần ép buộc căn trái.** chỉnh sửa ** chỉ thấy rằng câu trả lời của Evan đưa những điều này vào tài khoản và là để đáp ứng với mã này, không phải của Mark. – user568458

9

cảm ơn câu trả lời. Tuy nhiên, tôi thấy rằng tôi cần một vài điều chỉnh để làm việc cho tôi:

function textWrap(t, width) { 
    var content = t.attr("text"); 
    var abc = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 
    t.attr({ 
     'text-anchor' : 'start', 
     "text" : abc 
    }); 
    var letterWidth = t.getBBox().width/abc.length; 
    t.attr({ 
     "text" : content 
    }); 

    var words = content.split(" "); 
    var x = 0, s = []; 
    for (var i = 0; i < words.length; i++) { 

     var l = words[i].length; 
     if (x + (l * letterWidth) > width) { 
      s.push("\n"); 
      x = 0; 
     } 
     x += l * letterWidth; 
     s.push(words[i] + " "); 
    } 
    t.attr({ 
     "text" : s.join("") 
    }); 
} 

Những thay đổi là:

  • sự so sánh cần thiết để sử dụng (l * letterwidth) ... không chỉ l
  • nếu/khác thay đổi để chỉ một nếu - để ngắt dòng sẽ luôn đặt x 0
  • và luôn thêm mới l * letterwidth cho x giá trị

hy vọng điều này sẽ giúp.

+1

Cảm ơn vì điều này - mặc dù tôi không chắc chắn tại sao bạn cần mã này ở trên cùng: ''text-anchor': 'start''. Tôi đã xóa nó và nó có vẻ hoạt động ổn định và giữ nguyên định dạng ban đầu của tôi. – rwalter

+1

+1 Đây là một cải tiến về mã của Cancerbero và tùy chọn tốt nhất trên trang nếu hiệu suất là một yếu tố. Một cải tiến có thể là: letterwidth là hằng số cho mỗi phông chữ và cỡ chữ, vì vậy nếu bạn đang chạy số lượng lớn văn bản này, bạn có thể tăng hiệu suất khiêm tốn bằng cách lưu trữ thư trong một biến có phạm vi thích hợp, thay vì tính lại nó chuyển đổi văn bản cho mỗi phần tử. Tôi khuyên bạn nên lưu trữ nó trong một đối tượng, được khóa bởi họ phông chữ và cỡ chữ. – user568458

0

Vâng, tôi giải quyết nó tinh chỉnh nó một chút

var words = server.split(" "); 
var length = words.length; 
var temp_text = ""; 

for(var i = 0; i < length; i++) { 
    temp_text = temp_text + ' ' + words[i]; 
    t.attr("text", temp_text); 

    if(t.getBBox().width > width) { 
     temp_text = temp_text.replace(/(*)(\w+)$/, "\n$2"); 
    } 
} 

t.attr("text", temp_text.trim()); 
0

Tôi biết đó là một chút muộn bây giờ, nhưng bạn có thể quan tâm trong dự án Raphael-paragraph của tôi mà thực hiện điều này tự động.

Đoạn Raphael cho phép bạn tạo văn bản đa dòng được bao bọc tự động với các giới hạn chiều rộng và chiều cao tối đa, chiều cao dòng và cấu hình kiểu văn bản. Nó có thể gạch nối từ dài và cắt ngắn chúng nếu chúng vượt quá giới hạn dọc. Nó vẫn khá beta-ish và đòi hỏi rất nhiều tối ưu hóa, nhưng nó sẽ làm việc cho các mục đích của bạn.

Ví dụ sử dụng và tài liệu được cung cấp trên trang GitHub.

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