/** * Hilo * Copyright 2015 alibaba.com * Licensed under the MIT License */ /** * *
* @class Text class provide basic text-display function, use DOMElement for complex text-display. * @augments View * @mixes CacheMixin * @borrows CacheMixin#cache as #cache * @borrows CacheMixin#updateCache as #updateCache * @borrows CacheMixin#setCacheDirty as #setCacheDirty * @param {Object} properties Properties parameters for the object. Includes all writable properties. * @module hilo/view/Text * @requires hilo/core/Class * @requires hilo/core/Hilo * @requires hilo/view/View * @requires hilo/view/CacheMixin * @property {String} text Text to display. * @property {String} color Color of the text. * @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 * @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. * @property {Boolean} outline Draw the outline of the text or fill the text. * @property {Number} lineSpacing The spacing between lines. Measured in px, default value is 0. * @property {Number} maxWidth The max length of the text, default value is 200. * @property {String} font Text's CSS font style, readonly! Use setFont function to set text font. * @property {Number} textWidth Width of the text, readonly! Works only on canvas mode. * @property {Number} textHeight Height of the text, readonly! Works only on canvas mode. */ var Text = Class.create(/** @lends Text.prototype */{ Extends: View, Mixes:CacheMixin, constructor: function(properties){ properties = properties || {}; this.id = this.id || properties.id || Hilo.getUid('Text'); Text.superclass.constructor.call(this, properties); // if(!properties.width) this.width = 200; //default width if(!properties.font) this.font = '12px arial'; //default font style this._fontHeight = Text.measureFontHeight(this.font); }, text: '', color: '#000', textAlign: null, textVAlign: null, outline: false, lineSpacing: 0, maxWidth: 200, font: null, //ready-only textWidth: 0, //read-only textHeight: 0, //read-only /** * Set text CSS font style. * @param {String} font Text CSS font style to set. * @returns {Text} the Text object, chained call supported. */ setFont: function(font){ var me = this; if(me.font !== font){ me.font = font; me._fontHeight = Text.measureFontHeight(font); } return me; }, /** * Overwrite render function. * @private */ render: function(renderer, delta){ var me = this; if(renderer.renderType === 'canvas'){ if(this.drawable){ renderer.draw(me); } else{ me._draw(renderer.context); } } else if(renderer.renderType === 'dom'){ var drawable = me.drawable; var domElement = drawable.domElement; var style = domElement.style; style.font = me.font; style.textAlign = me.textAlign; style.color = me.color; style.width = me.width + 'px'; style.height = me.height + 'px'; style.lineHeight = (me._fontHeight + me.lineSpacing) + 'px'; domElement.innerHTML = me.text; renderer.draw(this); } else{ //TODO:自动更新cache TODO:auto update cache me.cache(); renderer.draw(me); } }, /** * Draw text under the assigned render context. * @private */ _draw: function(context){ var me = this, text = me.text.toString(); if(!text) return; //set drawing style context.font = me.font; context.textAlign = me.textAlign; context.textBaseline = 'top'; //find and draw all explicit lines var lines = text.split(/\r\n|\r|\n|/); var width = 0, height = 0; var lineHeight = me._fontHeight + me.lineSpacing; var i, line, w, len, wlen; var drawLines = []; for(i = 0, len = lines.length; i < len; i++){ line = lines[i]; w = context.measureText(line).width; //check if the line need to split if(w <= me.maxWidth){ drawLines.push({text:line, y:height}); // me._drawTextLine(context, line, height); if(width < w) width = w; height += lineHeight; continue; } var str = '', oldWidth = 0, newWidth, j, word; for(j = 0, wlen = line.length; j < wlen; j++){ word = line[j]; newWidth = context.measureText(str + word).width; if(newWidth > me.maxWidth){ drawLines.push({text:str, y:height}); // me._drawTextLine(context, str, height); if(width < oldWidth) width = oldWidth; height += lineHeight; str = word; }else{ oldWidth = newWidth; str += word; } if(j == wlen - 1){ drawLines.push({text:str, y:height}); // me._drawTextLine(context, str, height); if(str !== word && width < newWidth) width = newWidth; height += lineHeight; } } } me.textWidth = width; me.textHeight = height; if(!me.width) me.width = width; if(!me.height) me.height = height; //vertical alignment var startY = 0; switch(me.textVAlign){ case 'middle': startY = me.height - me.textHeight >> 1; break; case 'bottom': startY = me.height - me.textHeight; break; } //draw background var bg = me.background; if(bg){ context.fillStyle = bg; context.fillRect(0, 0, me.width, me.height); } if(me.outline) context.strokeStyle = me.color; else context.fillStyle = me.color; //draw text lines for(i = 0; i < drawLines.length; i++){ line = drawLines[i]; me._drawTextLine(context, line.text, startY + line.y); } }, /** * Draw a line of text under the assigned render context. * @private */ _drawTextLine: function(context, text, y){ var me = this, x = 0, width = me.width; switch(me.textAlign){ case 'center': x = width >> 1; break; case 'right': case 'end': x = width; break; } if(me.outline) context.strokeText(text, x, y); else context.fillText(text, x, y); }, Statics: /** @lends Text */{ /** * Measure the line height of the assigned text font style. * @param {String} font Font style to measure. * @return {Number} Return line height of the assigned font style. */ measureFontHeight: function(font){ var docElement = document.documentElement, fontHeight; var elem = Hilo.createElement('div', {style:{font:font, position:'absolute'}, innerHTML:'M'}); docElement.appendChild(elem); fontHeight = elem.offsetHeight; docElement.removeChild(elem); return fontHeight; } } });