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