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 class provide basic text-display function, use DOMElement for complex text-display. 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 Properties parameters for the object. Includes all writable 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 Text to display. 23 * @property {String} color Color of the text. 24 * @property {String} textAlign Horizontal alignment way of the text. May be one of the following value:'start', 'end', 'left', 'right', and 'center'. Note:Need to specify the width property of the text to take effect 25 * @property {String} textVAlign Vertical alignment way of the text. May be one of the following value:'top', 'middle', 'bottom'. Note:Need to specify the height property of the text to take effect. 26 * @property {Boolean} outline Draw the outline of the text or fill the text. 27 * @property {Number} lineSpacing The spacing between lines. Measured in px, default value is 0. 28 * @property {Number} maxWidth The max length of the text, default value is 200. 29 * @property {String} font Text's CSS font style, readonly! Use setFont function to set text font. 30 * @property {Number} textWidth Width of the text, readonly! Works only on canvas mode. 31 * @property {Number} textHeight Height of the text, readonly! Works only on canvas mode. 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 * Set text CSS font style. 59 * @param {String} font Text CSS font style to set. 60 * @returns {Text} the Text object, chained call supported. 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 * Overwrite render function. 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 * Draw text under the assigned render context. 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 * Draw a line of text under the assigned render context. 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 * Measure the line height of the assigned text font style. 225 * @param {String} font Font style to measure. 226 * @return {Number} Return line height of the assigned font style. 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