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