1 goog.provide('lime.Label'); 2 goog.provide('lime.Renderer.CANVAS.LABEL'); 3 goog.provide('lime.Renderer.DOM.LABEL'); 4 5 6 goog.require('lime.Renderer.CANVAS.SPRITE'); 7 goog.require('lime.Renderer.DOM.SPRITE'); 8 goog.require('lime.Sprite'); 9 10 /** 11 * Display object for text 12 * @param {string} txt Text contents of the label. 13 * @constructor 14 * @extends lime.Sprite 15 */ 16 lime.Label = function(txt) { 17 lime.Sprite.call(this); 18 19 this.setText(txt); 20 21 this.setFontFamily(lime.Label.defaultFont); 22 this.setFontSize(14); 23 this.setFontColor('#000'); 24 this.setAlign('center'); 25 this.setFontWeight('400'); 26 27 this.setPadding(0); 28 29 this.setLineHeight(1.15); 30 31 this.setFill(255, 255, 255, 0); 32 33 }; 34 goog.inherits(lime.Label, lime.Sprite); 35 36 /** 37 * Common name for label objects 38 * @type {string} 39 */ 40 lime.Label.prototype.id = 'label'; 41 42 /** 43 * Default Font name for labels 44 * @type {string} 45 */ 46 lime.Label.defaultFont = 'Arial'; 47 48 /** @inheritDoc */ 49 lime.Label.prototype.supportedRenderers = [ 50 lime.Renderer.DOM.SPRITE.makeSubRenderer(lime.Renderer.DOM.LABEL), 51 lime.Renderer.CANVAS.SPRITE.makeSubRenderer(lime.Renderer.CANVAS.LABEL) 52 ]; 53 54 (function() { 55 56 var mContext; 57 58 /** 59 * Measure text contents of the label 60 * @return {goog.math.Size} size of the text. 61 */ 62 lime.Label.prototype.measureText = function() { 63 if (!goog.isDef(mContext)) { 64 var cvs = document.createElement('canvas'); 65 mContext = cvs.getContext('2d'); 66 } 67 68 var lh = this.getLineHeight(); 69 mContext.font = this.getFontSize() + 'px ' + this.getFontFamily(); 70 var metrics = mContext.measureText(this.text_); 71 var w = goog.userAgent.WEBKIT ? metrics.width : metrics.width + 1; 72 var stroke = this.stroke_?this.stroke_.width_:0; 73 return new goog.math.Size( 74 this.padding_[1] + this.padding_[3] + w + stroke*2, 75 this.padding_[0] + this.padding_[2] + lh * this.getFontSize() + stroke*2 76 ); 77 } 78 })(); 79 80 /** @inheritDoc */ 81 lime.Label.prototype.getSize = function() { 82 var size = lime.Node.prototype.getSize.call(this); 83 if (!size || (!size.width && !size.height)) { 84 return this.measureText(); 85 } 86 return size; 87 }; 88 89 /** 90 * Returns label text as stirng 91 * @return {string} Text contents. 92 */ 93 lime.Label.prototype.getText = function() { 94 return this.text_; 95 }; 96 97 /** 98 * Set label text 99 * @param {string} txt New text contents. 100 * @return {lime.Label} object itself. 101 */ 102 lime.Label.prototype.setText = function(txt) { 103 this.text_ = txt + ''; 104 this.setDirty(lime.Dirty.CONTENT); 105 delete this.words_; 106 return this; 107 }; 108 109 /** 110 * Returns font used to draw the label 111 * @return {string} Font name string. 112 */ 113 lime.Label.prototype.getFontFamily = function() { 114 return this.fontFamily_; 115 }; 116 117 /** 118 * Set font weight 119 * @param {string} value New font weight value. 120 * @return {lime.Label} object itself. 121 */ 122 lime.Label.prototype.setFontWeight = function(value) { 123 this.fontWeight_ = value; 124 this.setDirty(lime.Dirty.FONT); 125 return this; 126 }; 127 128 /** 129 * Returns font used to draw the label 130 * @return {string} Font name string. 131 */ 132 lime.Label.prototype.getFontWeight = function() { 133 return this.fontWeight_; 134 }; 135 136 /** 137 * Set font name 138 * @param {string} value New font family string. 139 * @return {lime.Label} object itself. 140 */ 141 lime.Label.prototype.setFontFamily = function(value) { 142 this.fontFamily_ = value; 143 this.setDirty(lime.Dirty.FONT); 144 return this; 145 }; 146 147 /** 148 * Returns font size in pixels 149 * @return {number} Font size in px. 150 */ 151 lime.Label.prototype.getFontSize = function() { 152 return this.fontSize_; 153 }; 154 155 /** 156 * Set the font size in pixels 157 * @param {number} value New font size in px. 158 * @return {lime.Label} object itself. 159 */ 160 lime.Label.prototype.setFontSize = function(value) { 161 this.fontSize_ = value; 162 this.setDirty(lime.Dirty.FONT); 163 return this; 164 }; 165 166 /** 167 * Returns font color as string 168 * @return {string} Font color. 169 */ 170 lime.Label.prototype.getFontColor = function() { 171 return this.fontColor_; 172 }; 173 174 /** 175 * Sets the font color. Accepts #hex, rgb(), rgba() or plain color name. 176 * @param {string} value New color. 177 * @return {lime.Label} object itself. 178 */ 179 lime.Label.prototype.setFontColor = function(value) { 180 this.fontColor_ = value; 181 this.setDirty(lime.Dirty.FONT); 182 return this; 183 }; 184 185 /** 186 * Return padding box around the text contents 187 * @return {goog.math.Box} padding box. 188 */ 189 lime.Label.prototype.getPadding = function() { 190 return this.padding_; 191 }; 192 193 /** 194 * Set new padding box around text contents. 195 * @param {number} top Top padding. 196 * @param {number=} opt_right Right padding. 197 * @param {number=} opt_bottom Bottom padding. 198 * @param {number=} opt_left Left padding. 199 * @return {lime.Label} object itself. 200 */ 201 lime.Label.prototype.setPadding = function(top, opt_right, 202 opt_bottom, opt_left) { 203 204 var val = [top, top, top, top]; 205 if (goog.isDef(opt_right)) { 206 val[1] = val[3] = opt_right; 207 } 208 if (goog.isDef(opt_bottom)) { 209 val[2] = opt_bottom; 210 } 211 if (goog.isDef(opt_left)) { 212 val[3] = opt_left; 213 } 214 this.padding_ = val; 215 216 this.setDirty(lime.Dirty.FONT); 217 return this; 218 }; 219 220 /** 221 * Sets the line height used in multiline strings. Can be in pixels 222 * or factor from font size. 223 * @param {number} value Line height. 224 * @param {boolean=} opt_absolute If height is in pixels. 225 */ 226 lime.Label.prototype.setLineHeight = function(value, opt_absolute) { 227 this.lineHeightAbsolute_ = opt_absolute || false; 228 this.lineHeight_ = value; 229 }; 230 231 /** 232 * Return line height as a factor from font size 233 * @return {number} Line height. 234 */ 235 lime.Label.prototype.getLineHeight = function() { 236 return this.lineHeightAbsolute_ ? 237 this.lineHeight_ / this.getFontSize() : this.lineHeight_; 238 }; 239 240 /** 241 * Returns alignment value 242 * @return {string} Alignement. 243 */ 244 lime.Label.prototype.getAlign = function() { 245 return this.align_; 246 }; 247 248 /** 249 * Sets label alignment. Accepts normal strings as left,center,right 250 * @param {string} value New alignment value. 251 * @return {lime.Label} object itself. 252 */ 253 lime.Label.prototype.setAlign = function(value) { 254 this.align_ = value; 255 this.setDirty(lime.Dirty.FONT); 256 return this; 257 }; 258 259 /** 260 * Break text into array of line breakable words 261 * @return {Array.<string>} array of words. 262 */ 263 lime.Label.prototype.calcWordsArray = function() { 264 var words = []; 265 var len = this.text_.length; 266 var regexp = goog.userAgent.GECKO ? /[\s\.]+/g : /[\s-\.]+/g; 267 var breaks = this.text_.match(regexp); 268 var st = 0; 269 if (breaks) 270 for (var i = 0; i < breaks.length; i++) { 271 var b = breaks[i]; 272 var ibreak = this.text_.indexOf(b, st); 273 var wlen = ibreak + b.length; 274 words.push(this.text_.substring(st, wlen)); 275 st = wlen; 276 } 277 if (st != len) { 278 words.push(this.text_.substring(st, len)); 279 } 280 return words; 281 }; 282 283 /** 284 * Wrap text on words array to lines based on current 285 * font size and given maximum width. 286 * @param {Object} context Canvas2DContext used to measure. 287 * @param {number} width Maximum line width. 288 * @return {Array.<string>} Lines of text. 289 */ 290 lime.Label.prototype.wrapText = function(context, width) { 291 var lines = [], line = '', words = this.words_, metrics; 292 for (var i = 0; i < words.length; i++) { 293 if (line == '') { 294 line = words[i]; 295 } 296 else { 297 metrics = context.measureText(goog.string.trim(line + words[i])); 298 if (metrics.width > width) { 299 lines.push(goog.string.trim(line)); 300 line = words[i]; 301 } 302 else { 303 line += words[i]; 304 } 305 } 306 } 307 lines.push(line); 308 return lines; 309 }; 310 311 /** @inheritDoc */ 312 lime.Label.prototype.update = function(){ 313 314 if(this.getDirty() & lime.Dirty.CONTENT) 315 delete this.lastDrawnWidth_; 316 317 lime.Node.prototype.update.apply(this,arguments); 318 } 319 320 321 /** 322 * @inheritDoc 323 * @this {lime.Label} 324 */ 325 lime.Renderer.DOM.LABEL.draw = function(el) { 326 lime.Renderer.DOM.SPRITE.draw.call(this, el); 327 328 var style = el.style; 329 if (this.dirty_ & lime.Dirty.CONTENT) { 330 goog.dom.setTextContent(el, this.text_); 331 } 332 if (this.dirty_ & lime.Dirty.FONT) { 333 style['lineHeight'] = this.getLineHeight(); 334 style['padding'] = goog.array.map(this.padding_,function(p){return p*this.getRelativeQuality()},this).join('px ') + 'px'; 335 style['color'] = this.getFontColor(); 336 style['fontFamily'] = this.getFontFamily(); 337 style['fontSize'] = this.getFontSize()*this.getRelativeQuality() + 'px'; 338 style['fontWeight'] = this.getFontWeight(); 339 style['textAlign'] = this.getAlign(); 340 } 341 }; 342 343 /** 344 * @inheritDoc 345 * @this {lime.Label} 346 */ 347 lime.Renderer.CANVAS.LABEL.draw = function(context) { 348 349 lime.Renderer.CANVAS.SPRITE.draw.call(this, context); 350 351 var frame = this.getFrame(), 352 width = -frame.left - this.padding_[3] + frame.right - this.padding_[1], 353 dowrap = 0; 354 355 if (!this.words_) { 356 this.words_ = this.calcWordsArray(); 357 dowrap = 1; 358 } 359 360 var stroke = this.stroke_?this.stroke_.width_:0; 361 362 context.save(); 363 var align = this.getAlign(); 364 if (align == 'left') { 365 context.translate(frame.left + this.padding_[3]+stroke, 366 frame.top + this.padding_[0]+stroke); 367 } 368 else if (align == 'right') { 369 context.translate(frame.right - this.padding_[1]-stroke, 370 frame.top + this.padding_[0]+stroke); 371 } 372 else if (align == 'center') { 373 context.translate( 374 (frame.left + this.padding_[3] + 375 frame.right - this.padding_[1]) * .5, 376 frame.top + this.padding_[0]+stroke); 377 } 378 379 var lh = this.getLineHeight(); 380 381 context.fillStyle = this.getFontColor(); 382 context.font = this.getFontWeight() + ' ' + this.getFontSize() + 383 'px/' + lh + ' ' + this.getFontFamily(); 384 context.textAlign = align; 385 context.textBaseline = 'top'; 386 387 if(dowrap || width!=this.lastDrawnWidth_){ 388 this.lines_ = this.wrapText(context, width); 389 this.lastDrawnWidth_ = width; 390 } 391 392 393 if (this.lines_) { 394 var lhpx = lh * this.getFontSize(); 395 lhpx = goog.userAgent.WEBKIT ? Math.floor(lhpx) : Math.round(lhpx); 396 for (var i = 0; i < this.lines_.length; i++) { 397 context.fillText(this.lines_[i], 0, lhpx * i); 398 } 399 } 400 401 402 context.restore(); 403 }; 404 405 /** 406 * Helper function to install new font file so you can use 407 * the font name as font-family. 408 * @param {string} name Font name. 409 * @param {string} fileurl Path to font file. 410 * @param {string=} opt_format Font format. 411 */ 412 lime.Label.installFont = function(name, fileurl, opt_format) { 413 var format = opt_format || 'truetype'; 414 goog.style.installStyles('@font-face{font-family: "' + name + 415 '";src: url(' + fileurl + ') format("' + format + '");})'); 416 }; 417