1 /** 2 * Hilo 3 * Copyright 2015 alibaba.com 4 * Licensed under the MIT License 5 */ 6 7 /** 8 * <iframe src='../../../examples/Text.html?noHeader' width = '320' height = '240' scrolling='no'></iframe> 9 * <br/> 10 * @class Text类提供简单的文字显示功能。复杂的文本功能可以使用DOMElement。 11 * @augments View 12 * @mixes CacheMixin 13 * @borrows CacheMixin#cache as #cache 14 * @borrows CacheMixin#updateCache as #updateCache 15 * @borrows CacheMixin#setCacheDirty as #setCacheDirty 16 * @param {Object} properties 创建对象的属性参数。可包含此类所有可写属性。 17 * @module hilo/view/Text 18 * @requires hilo/core/Class 19 * @requires hilo/core/Hilo 20 * @requires hilo/view/View 21 * @requires hilo/view/CacheMixin 22 * @property {String} text 指定要显示的文本内容。 23 * @property {String} color 指定使用的字体颜色。 24 * @property {String} textAlign 指定文本的对齐方式。可以是以下任意一个值:'start', 'end', 'left', 'right', and 'center'。注意:必须设置文本的 width 属性才能生效。 25 * @property {String} textVAlign 指定文本的垂直对齐方式。可以是以下任意一个值:'top', 'middle', 'bottom'。注意:必须设置文本的 height 属性才能生效。 26 * @property {Boolean} outline 指定文本是绘制边框还是填充。 27 * @property {Number} lineSpacing 指定文本的行距。单位为像素。默认值为0。 28 * @property {Number} maxWidth 指定文本的最大宽度。默认值为200。 29 * @property {String} font 文本的字体CSS样式。只读属性。设置字体样式请用setFont方法。 30 * @property {Number} textWidth 指示文本内容的宽度,只读属性。仅在canvas模式下有效。 31 * @property {Number} textHeight 指示文本内容的高度,只读属性。仅在canvas模式下有效。 32 */ 33 var Text = Class.create(/** @lends Text.prototype */{ 34 Extends: View, 35 Mixes:CacheMixin, 36 constructor: function(properties){ 37 properties = properties || {}; 38 this.id = this.id || properties.id || Hilo.getUid('Text'); 39 Text.superclass.constructor.call(this, properties); 40 41 // if(!properties.width) this.width = 200; //default width 42 if(!properties.font) this.font = '12px arial'; //default font style 43 this._fontHeight = Text.measureFontHeight(this.font); 44 }, 45 46 text: '', 47 color: '#000', 48 textAlign: null, 49 textVAlign: null, 50 outline: false, 51 lineSpacing: 0, 52 maxWidth: 200, 53 font: null, //ready-only 54 textWidth: 0, //read-only 55 textHeight: 0, //read-only 56 57 /** 58 * 设置文本的字体CSS样式。 59 * @param {String} font 要设置的字体CSS样式。 60 * @returns {Text} Text对象本身。链式调用支持。 61 */ 62 setFont: function(font){ 63 var me = this; 64 if(me.font !== font){ 65 me.font = font; 66 me._fontHeight = Text.measureFontHeight(font); 67 } 68 69 return me; 70 }, 71 72 /** 73 * 覆盖渲染方法。 74 * @private 75 */ 76 render: function(renderer, delta){ 77 var me = this; 78 79 if(renderer.renderType === 'canvas'){ 80 if(this.drawable){ 81 renderer.draw(me); 82 } 83 else{ 84 me._draw(renderer.context); 85 } 86 } 87 else if(renderer.renderType === 'dom'){ 88 var drawable = me.drawable; 89 var domElement = drawable.domElement; 90 var style = domElement.style; 91 92 style.font = me.font; 93 style.textAlign = me.textAlign; 94 style.color = me.color; 95 style.width = me.width + 'px'; 96 style.height = me.height + 'px'; 97 style.lineHeight = (me._fontHeight + me.lineSpacing) + 'px'; 98 99 domElement.innerHTML = me.text; 100 renderer.draw(this); 101 } 102 else{ 103 //TODO:自动更新cache TODO:auto update cache 104 me.cache(); 105 renderer.draw(me); 106 } 107 }, 108 109 /** 110 * 在指定的渲染上下文上绘制文本。 111 * @private 112 */ 113 _draw: function(context){ 114 var me = this, text = me.text.toString(); 115 if(!text) return; 116 117 //set drawing style 118 context.font = me.font; 119 context.textAlign = me.textAlign; 120 context.textBaseline = 'top'; 121 122 //find and draw all explicit lines 123 var lines = text.split(/\r\n|\r|\n|<br(?:[ \/])*>/); 124 var width = 0, height = 0; 125 var lineHeight = me._fontHeight + me.lineSpacing; 126 var i, line, w, len, wlen; 127 var drawLines = []; 128 129 for(i = 0, len = lines.length; i < len; i++){ 130 line = lines[i]; 131 w = context.measureText(line).width; 132 133 //check if the line need to split 134 if(w <= me.maxWidth){ 135 drawLines.push({text:line, y:height}); 136 // me._drawTextLine(context, line, height); 137 if(width < w) width = w; 138 height += lineHeight; 139 continue; 140 } 141 142 var str = '', oldWidth = 0, newWidth, j, word; 143 144 for(j = 0, wlen = line.length; j < wlen; j++){ 145 word = line[j]; 146 newWidth = context.measureText(str + word).width; 147 148 if(newWidth > me.maxWidth){ 149 drawLines.push({text:str, y:height}); 150 // me._drawTextLine(context, str, height); 151 if(width < oldWidth) width = oldWidth; 152 height += lineHeight; 153 str = word; 154 }else{ 155 oldWidth = newWidth; 156 str += word; 157 } 158 159 if(j == wlen - 1){ 160 drawLines.push({text:str, y:height}); 161 // me._drawTextLine(context, str, height); 162 if(str !== word && width < newWidth) width = newWidth; 163 height += lineHeight; 164 } 165 } 166 } 167 168 me.textWidth = width; 169 me.textHeight = height; 170 if(!me.width) me.width = width; 171 if(!me.height) me.height = height; 172 173 //vertical alignment 174 var startY = 0; 175 switch(me.textVAlign){ 176 case 'middle': 177 startY = me.height - me.textHeight >> 1; 178 break; 179 case 'bottom': 180 startY = me.height - me.textHeight; 181 break; 182 } 183 184 //draw background 185 var bg = me.background; 186 if(bg){ 187 context.fillStyle = bg; 188 context.fillRect(0, 0, me.width, me.height); 189 } 190 191 if(me.outline) context.strokeStyle = me.color; 192 else context.fillStyle = me.color; 193 194 //draw text lines 195 for(i = 0; i < drawLines.length; i++){ 196 line = drawLines[i]; 197 me._drawTextLine(context, line.text, startY + line.y); 198 } 199 }, 200 201 /** 202 * 在指定的渲染上下文上绘制一行文本。 203 * @private 204 */ 205 _drawTextLine: function(context, text, y){ 206 var me = this, x = 0, width = me.width; 207 208 switch(me.textAlign){ 209 case 'center': 210 x = width >> 1; 211 break; 212 case 'right': 213 case 'end': 214 x = width; 215 break; 216 } 217 218 if(me.outline) context.strokeText(text, x, y); 219 else context.fillText(text, x, y); 220 }, 221 222 Statics: /** @lends Text */{ 223 /** 224 * 测算指定字体样式的行高。 225 * @param {String} font 指定要测算的字体样式。 226 * @return {Number} 返回指定字体的行高。 227 */ 228 measureFontHeight: function(font){ 229 var docElement = document.documentElement, fontHeight; 230 var elem = Hilo.createElement('div', {style:{font:font, position:'absolute'}, innerHTML:'M'}); 231 232 docElement.appendChild(elem); 233 fontHeight = elem.offsetHeight; 234 docElement.removeChild(elem); 235 return fontHeight; 236 } 237 } 238 239 }); 240