एसवीजी को टेक्स्ट एलिमेंट की चौड़ाई मिलती है


105

मैं एसवीजी फ़ाइल के लिए कुछ ईसीएमएस्क्रिप्ट / जावास्क्रिप्ट पर काम कर रहा हूं widthऔर heightएक textतत्व प्राप्त करने की आवश्यकता है ताकि मैं एक आयत का आकार बदल सकूं जो इसे घेरे हुए है। एचटीएमएल में मैं तत्व पर विशेषताओं offsetWidthऔर offsetHeightविशेषताओं का उपयोग करने में सक्षम होगा , लेकिन ऐसा प्रतीत होता है कि वे गुण अनुपलब्ध हैं।

यहां एक टुकड़ा है जिसे मुझे काम करने की आवश्यकता है। जब भी मैं पाठ को बदलूं, मुझे आयत की चौड़ाई बदलने की आवश्यकता है, लेकिन मुझे नहीं पता कि तत्व widthका वास्तविक (पिक्सेल में) कैसे प्राप्त किया जाए text

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

कोई विचार?

जवाबों:


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

और फिर उसके अनुसार रेक्ट की विशेषताओं को सेट करें।

लिंक: getBBox()एसवीजी v1.1 मानक में।


4
धन्यवाद। मुझे एक और फ़ंक्शन भी मिला, जो चौड़ाई के साथ मदद कर सकता था। textElement.getComputedTextLength ()। मैं आज रात दोनों को आज़माऊंगा और देखूंगा कि कौन मेरे लिए बेहतर काम करता है।
स्टीफन सोरेनसेन

5
मैं इन पिछले सप्ताह के साथ खेल रहा था; getComputedTextLength () विधि ने getBBox () के रूप में एक ही परिणाम लौटाया। चीजों की चौड़ाई मैंने उस पर कोशिश की, इसलिए मैं बस बाउंडिंग बॉक्स के साथ गया, क्योंकि मुझे चौड़ाई और ऊंचाई दोनों की आवश्यकता थी। मुझे यकीन नहीं है कि कोई भी परिस्थिति है जब पाठ की लंबाई चौड़ाई से भिन्न होगी: मुझे लगता है कि शायद यह विधि पाठ लेआउट के साथ मदद करने के लिए प्रदान की जाती है जैसे कि कई लाइनों पर पाठ को विभाजित करना, जबकि बाउंडिंग बॉक्स एक सामान्य विधि उपलब्ध है सभी (?) तत्वों पर।
NickFitz

2
समस्या यह है कि, यदि पाठ एक पथ का अनुसरण करता है, तो चौड़ाई पाठ की वास्तविक चौड़ाई नहीं है (उदाहरण के लिए यदि पाठ एक वृत्त पथ का अनुसरण करता है तो bbox वह है जो वृत्त को घेरता है, और उस isn की चौड़ाई प्राप्त करता है। 'सर्कल के चारों ओर जाने से पहले पाठ की चौड़ाई t)। एक और बात यह है कि bbox. उपलब्धता 2 के एक कारक से अधिक है, इसलिए यदि तत्व निरीक्षक 200 की चौड़ाई दिखाता है, तो bbox.width 400 है। मुझे यकीन नहीं है कि क्यों।
त्रिकुट्र

ड्रा होने से पहले आप लंबाई कैसे बढ़ा सकते हैं?
निकोस

7

पाठ की लंबाई के बारे में लिंक BBox को इंगित करता है और getComputedTextLength () थोड़ा अलग मान दे सकता है, लेकिन वे जो एक दूसरे के काफी करीब हैं।

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


उस लिंक के लिए आपको धन्यवाद!! मुझे अपने आप से सभी परिदृश्यों से गुजरना पड़ा, लेकिन यह वास्तव में अच्छा सारांश है ... मेरी समस्या फ़ायरबॉक्स पर एक Tspan तत्व पर getBBox () का उपयोग कर रही थी ... यह अधिक विशिष्ट और कष्टप्रद मुद्दा नहीं हो सकता है। । एक बार फिर धन्यवाद!
एंड्रेस एलिसंडो

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

मेरे लिए काम किया


आपका समाधान पाठ तत्व की वास्तविक लंबाई देता है जो सही उत्तर है। कुछ उत्तर getBBox () का उपयोग करते हैं जो पाठ को घुमाए नहीं जाने पर सही हो सकते हैं।
नेटसी

2

संगतता के लिए कुछ इस तरह के बारे में:

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

यह तीन तरीकों के किसी भी वैध परिणाम का औसत लौटाता है। आप आउटलेयर कास्ट करने के लिए इसे सुधार सकते हैं या getComputedTextLengthयदि तत्व एक टेक्स्ट एलिमेंट है तो इसका पक्ष ले सकते हैं ।

चेतावनी: जैसा कि टिप्पणी कहती है, getBoundingClientRectमुश्किल है। या तो तरीकों से इसे हटा दें या केवल उन तत्वों पर इसका उपयोग करें जहां getBoundingClientRectअच्छे परिणाम आएंगे, इसलिए कोई रोटेशन और शायद कोई स्केलिंग (?) नहीं है।


1
getBoundingClientRect अन्य दो के लिए एक संभावित भिन्न समन्वय प्रणाली में काम करता है।
रॉबर्ट लोंगसन

2

निश्चित रूप से क्यों नहीं, लेकिन उपरोक्त तरीकों में से कोई भी मेरे लिए काम नहीं करता है। मुझे कैनवास विधि के साथ कुछ सफलता मिली, लेकिन मुझे सभी प्रकार के स्केल कारकों को लागू करना पड़ा। यहां तक ​​कि पैमाने कारकों के साथ मैं अभी भी सफारी, क्रोम, और फ़ायरफ़ॉक्स के बीच असंगत परिणाम था।

तो, मैंने निम्नलिखित कोशिश की:

            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;

कमाल और सुपर सटीक काम किया, लेकिन केवल फ़ायरफ़ॉक्स में। क्रोम और सफारी के बचाव के लिए स्केल कारक, लेकिन कोई खुशी नहीं। यह पता लगाता है कि सफ़ारी और क्रोम त्रुटियाँ स्ट्रिंग लंबाई या फ़ॉन्ट आकार के साथ रैखिक नहीं हैं।

तो, नंबर दो पर पहुंचें। मैं ब्रूट फोर्स एप्रोच की बहुत परवाह नहीं करता, लेकिन वर्षों तक इससे जूझने के बाद मैंने इसे आजमाने का फैसला किया। मैंने प्रत्येक व्यक्तिगत मुद्रण योग्य चरित्र के लिए निरंतर मान उत्पन्न करने का निर्णय लिया। आम तौर पर यह एक प्रकार का थकाऊ होगा, लेकिन सौभाग्य से फ़ायरफ़ॉक्स सुपर सटीक होता है। यहाँ मेरे दो भाग जानवर बल समाधान है:

<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);
            var space_string_width = div.clientWidth;
            document.body.removeChild(div);
            var no_space_string = "!!";
            div.innerHTML = no_space_string;
            document.body.appendChild(div);
            var no_space_string_width = div.clientWidth;
            console.log("space width: " + (space_string_width - no_space_string_width));
            document.body.removeChild(div);


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

नोट: उपरोक्त स्निपेट को मूल्यों की एक सटीक सरणी उत्पन्न करने के लिए फ़ायरफ़ॉक्स में निष्पादित किया जाना है। इसके अलावा, आपको कंसोल लॉग में स्पेस आइटम की जगह एरो आइटम 32 को बदलना होगा।

मैं बस स्क्रीन टेक्स्ट पर फ़ायरफ़ॉक्स को कॉपी करता हूं, और इसे अपने जावास्क्रिप्ट कोड में पेस्ट करता हूं। अब जब मेरे पास मुद्रण योग्य चरित्र की लंबाई है, तो मैं एक चौड़ाई प्राप्त फ़ंक्शन लागू कर सकता हूं। यहाँ कोड है:

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

खैर, यह बात है। जानवर बल, लेकिन यह तीनों ब्राउज़रों में सुपर सटीक है, और मेरी हताशा का स्तर शून्य हो गया है। यह निश्चित नहीं है कि यह ब्राउज़र कितनी देर तक चलेगा, लेकिन यह मेरे एसवीजी टेक्स्ट के लिए एक मजबूत फॉन्ट मेट्रिक्स तकनीक विकसित करने के लिए काफी लंबा होना चाहिए।


अब तक का सबसे अच्छा समाधान! साझा करने के लिए धन्यवाद!
just_user

यह कर्निंग प्रबंधन नहीं करती है
पैट

यह सच है, लेकिन मेरे द्वारा उपयोग किए जाने वाले फोंट के लिए कोई फर्क नहीं पड़ता। जब मुझे थोड़ा समय मिलेगा तो मैं अगले साल इसका फिर से अवलोकन करने जा रहा हूं। मेरे पास अपने मामलों के लिए टेक्स्ट मेट्रिक्स को अधिक सटीक बनाने के बारे में कुछ विचार हैं जो एक क्रूर बल दृष्टिकोण का उपयोग नहीं करते हैं।
एजेंट-पी

महान। स्थानीय स्क्रिप्ट में मक्खी पर उन्हें संरेखित करने के बजाय मुझे एसवीजी चार्ट लेबल को सांख्यिकीय रूप से संरेखित करने की अनुमति देता है। रूबी से रूबी में चार्ट की सेवा करते समय जीवन बहुत सरल हो जाता है। धन्यवाद!
लेक्स लिंडसे

0

SVG युक्ति में इस जानकारी को लौटाने की एक विशिष्ट विधि है: getComputedTextLength()

var width = textElement.getComputedTextLength(); // returns a pixel number
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.