1 
  2 /**
  3  * @class Text类提供简单的文字显示功能。复杂的文本功能可以使用DOMElement。
  4  * @augments View
  5  * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。
  6  * @module hilo/view/Text
  7  * @requires hilo/core/Class
  8  * @requires hilo/core/Hilo
  9  * @requires hilo/view/View
 10  * @property {String} text 指定要显示的文本内容。
 11  * @property {String} color 指定使用的字体颜色。
 12  * @property {String} textAlign 指定文本的对齐方式。可以是以下任意一个值:'start', 'end', 'left', 'right', and 'center'。
 13  * @property {Boolean} outline 指定文本是绘制边框还是填充。
 14  * @property {Number} lineSpacing 指定文本的行距。单位为像素。默认值为0。
 15  * @property {Number} textWidth 指示文本内容的宽度,只读属性。仅在canvas模式下有效。
 16  * @property {Number} textHeight 指示文本内容的高度,只读属性。仅在canvas模式下有效。
 17  * @property {String} font 指定使用的字体样式。
 18  */
 19 var Text = Class.create(/** @lends Text.prototype */{
 20     Extends: View,
 21     constructor: function Text(properties){
 22         properties = properties || {};
 23         this.id = this.id || properties.id || Hilo.getUid('Text');
 24         Text.superclass.constructor.call(this, properties);
 25 
 26         if(!this.width) this.width = 200; //default width
 27         if(!this.font) this.font = '12px arial'; //default font style
 28     },
 29 
 30     text: null,
 31     color: null,
 32     textAlign: null,
 33     outline: false,
 34     lineSpacing: 0,
 35     textWidth: 0, //read-only
 36     textHeight: 0, //read-only
 37     font: {
 38         get: function(){
 39             return this._font || null;
 40         },
 41         set: function(value){
 42             if(this._font === value) return;
 43             this._font = value;
 44             this._fontHeight = Text.measureFontHeight(value);
 45         }
 46     },
 47 
 48     /**
 49      * 覆盖渲染方法。
 50      */
 51     render: function(renderer, delta){
 52         var me = this, canvas = renderer.canvas;
 53 
 54         if(canvas.getContext){
 55             me._draw(renderer.context);
 56         }else{
 57             var drawable = me.drawable;
 58             var domElement = drawable.domElement;
 59             var style = domElement.style;
 60 
 61             style.font = me.font;
 62             style.textAlign = me.textAlign;
 63             style.color = me.color;
 64             style.width = me.width + 'px';
 65             style.height = me.height + 'px';
 66             style.lineHeight = (me._fontHeight + me.lineSpacing) + 'px';
 67 
 68             domElement.innerHTML = me.text;
 69             renderer.draw(this);
 70         }
 71     },
 72 
 73     /**
 74      * 在指定的渲染上下文上绘制文本。
 75      * @private
 76      */
 77     _draw: function(context){
 78         var me = this, text = me.text.toString();
 79         if(!text) return;
 80 
 81         //set drawing style
 82         context.font = me.font;
 83         context.textAlign = me.textAlign;
 84         context.textBaseline = 'top';
 85         if(me.outline) context.strokeStyle = me.color;
 86         else context.fillStyle = me.color;
 87 
 88         //find and draw all explicit lines
 89         var lines = text.split(/\r\n|\r|\n|<br(?:[ \/])*>/);
 90         var width = 0, height = 0;
 91         var lineHeight = me._fontHeight + me.lineSpacing;
 92         var i, line, w;
 93 
 94         for(i = 0, len = lines.length; i < len; i++){
 95             line = lines[i];
 96             w = context.measureText(line).width;
 97 
 98             //check if the line need to split
 99             if(w <= me.width){
100                 me._drawTextLine(context, line, height);
101                 if(width < w) width = w;
102                 height += lineHeight;
103                 continue;
104             }
105 
106             var str = '', oldWidth = 0, newWidth, j, word;
107 
108             for(j = 0, wlen = line.length; j < wlen; j++){
109                 word = line[j];
110                 newWidth = context.measureText(str + word).width;
111 
112                 if(newWidth > me.width){
113                     me._drawTextLine(context, str, height);
114                     if(width < oldWidth) width = oldWidth;
115                     height += lineHeight;
116                     str = word;
117                 }else{
118                     oldWidth = newWidth;
119                     str += word;
120                 }
121 
122                 if(j == wlen - 1){
123                     me._drawTextLine(context, str, height);
124                     if(str !== word && width < newWidth) width = newWidth;
125                     height += lineHeight;
126                 }
127             }
128         }
129 
130         me.textWidth = width;
131         me.textHeight = height;
132         if(!me.height) me.height = height;
133     },
134 
135     /**
136      * 在指定的渲染上下文上绘制一行文本。
137      * @private
138      */
139     _drawTextLine: function(context, text, y){
140         var me = this, x = 0, width = me.width;
141 
142         switch(me.textAlign){
143             case 'center':
144                 x = width * 0.5 >> 0;
145                 break;
146             case 'right':
147             case 'end':
148                 x = width;
149                 break;
150         };
151 
152         if(me.outline) context.strokeText(text, x, y);
153         else context.fillText(text, x, y);
154     },
155 
156     Statics: /** @lends Text */{
157         /**
158          * 测算指定字体样式的行高。
159          * @param {String} font 指定要测算的字体样式。
160          * @return {Number} 返回指定字体的行高。
161          */
162         measureFontHeight: function(font){
163             var docElement = document.documentElement, fontHeight;
164             var elem = Hilo.createElement('div', {style:{font:font, position:'absolute'}, innerHTML:'M'});
165 
166             docElement.appendChild(elem);
167             fontHeight = elem.offsetHeight;
168             docElement.removeChild(elem);
169             return fontHeight;
170         }
171     }
172 
173 });