Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / src / util / TextMetrics.js
1 /*!
2  * Ext JS Library 3.3.1
3  * Copyright(c) 2006-2010 Sencha Inc.
4  * licensing@sencha.com
5  * http://www.sencha.com/license
6  */
7 /**
8  * @class Ext.util.TextMetrics
9  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
10  * wide, in pixels, a given block of text will be. Note that when measuring text, it should be plain text and
11  * should not contain any HTML, otherwise it may not be measured correctly.
12  * @singleton
13  */
14 Ext.util.TextMetrics = function(){
15     var shared;
16     return {
17         /**
18          * Measures the size of the specified text
19          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
20          * that can affect the size of the rendered text
21          * @param {String} text The text to measure
22          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
23          * in order to accurately measure the text height
24          * @return {Object} An object containing the text's size {width: (width), height: (height)}
25          */
26         measure : function(el, text, fixedWidth){
27             if(!shared){
28                 shared = Ext.util.TextMetrics.Instance(el, fixedWidth);
29             }
30             shared.bind(el);
31             shared.setFixedWidth(fixedWidth || 'auto');
32             return shared.getSize(text);
33         },
34
35         /**
36          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
37          * the overhead of multiple calls to initialize the style properties on each measurement.
38          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
39          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
40          * in order to accurately measure the text height
41          * @return {Ext.util.TextMetrics.Instance} instance The new instance
42          */
43         createInstance : function(el, fixedWidth){
44             return Ext.util.TextMetrics.Instance(el, fixedWidth);
45         }
46     };
47 }();
48
49 Ext.util.TextMetrics.Instance = function(bindTo, fixedWidth){
50     var ml = new Ext.Element(document.createElement('div'));
51     document.body.appendChild(ml.dom);
52     ml.position('absolute');
53     ml.setLeftTop(-1000, -1000);
54     ml.hide();
55
56     if(fixedWidth){
57         ml.setWidth(fixedWidth);
58     }
59
60     var instance = {
61         /**
62          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
63          * Returns the size of the specified text based on the internal element's style and width properties
64          * @param {String} text The text to measure
65          * @return {Object} An object containing the text's size {width: (width), height: (height)}
66          */
67         getSize : function(text){
68             ml.update(text);
69             var s = ml.getSize();
70             ml.update('');
71             return s;
72         },
73
74         /**
75          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
76          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
77          * that can affect the size of the rendered text
78          * @param {String/HTMLElement} el The element, dom node or id
79          */
80         bind : function(el){
81             ml.setStyle(
82                 Ext.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height', 'text-transform', 'letter-spacing')
83             );
84         },
85
86         /**
87          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
88          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
89          * to set a fixed width in order to accurately measure the text height.
90          * @param {Number} width The width to set on the element
91          */
92         setFixedWidth : function(width){
93             ml.setWidth(width);
94         },
95
96         /**
97          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
98          * Returns the measured width of the specified text
99          * @param {String} text The text to measure
100          * @return {Number} width The width in pixels
101          */
102         getWidth : function(text){
103             ml.dom.style.width = 'auto';
104             return this.getSize(text).width;
105         },
106
107         /**
108          * <p><b>Only available on the instance returned from {@link #createInstance}, <u>not</u> on the singleton.</b></p>
109          * Returns the measured height of the specified text.  For multiline text, be sure to call
110          * {@link #setFixedWidth} if necessary.
111          * @param {String} text The text to measure
112          * @return {Number} height The height in pixels
113          */
114         getHeight : function(text){
115             return this.getSize(text).height;
116         }
117     };
118
119     instance.bind(bindTo);
120
121     return instance;
122 };
123
124 Ext.Element.addMethods({
125     /**
126      * Returns the width in pixels of the passed text, or the width of the text in this Element.
127      * @param {String} text The text to measure. Defaults to the innerHTML of the element.
128      * @param {Number} min (Optional) The minumum value to return.
129      * @param {Number} max (Optional) The maximum value to return.
130      * @return {Number} The text width in pixels.
131      * @member Ext.Element getTextWidth
132      */
133     getTextWidth : function(text, min, max){
134         return (Ext.util.TextMetrics.measure(this.dom, Ext.value(text, this.dom.innerHTML, true)).width).constrain(min || 0, max || 1000000);
135     }
136 });