1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 28 * cc.LabelTTF is a subclass of cc.TextureNode that knows how to render text labels<br/> 29 * All features from cc.TextureNode are valid in cc.LabelTTF<br/> 30 * cc.LabelTTF objects are slow for js-binding on mobile devices.<br/> 31 * Consider using cc.LabelAtlas or cc.LabelBMFont instead.<br/> 32 * @class 33 * @extends cc.Sprite 34 */ 35 cc.LabelTTF = cc.Sprite.extend(/** @lends cc.LabelTTF# */{ 36 _dimensions:cc.SizeZero(), 37 _hAlignment:cc.TEXT_ALIGNMENT_CENTER, 38 _vAlignment:cc.VERTICAL_TEXT_ALIGNMENT_TOP, 39 _fontName:"Arial", 40 _fontSize:0.0, 41 _string:"", 42 _fontStyleStr:null, 43 _colorStyleStr:null, 44 /** 45 * Constructor 46 */ 47 ctor:function () { 48 this._super(); 49 50 this._opacityModifyRGB = false; 51 this._fontStyleStr = ""; 52 this._colorStyleStr = ""; 53 this._opacity = 255; 54 this._color = cc.white(); 55 this._setColorStyleStr(); 56 }, 57 58 init:function (callsuper) { 59 if (callsuper) { 60 return this._super(); 61 } 62 return this.initWithString([" ", this._fontName, this._fontSize]); 63 }, 64 /** 65 * Prints out a description of this class 66 * @return {String} 67 */ 68 description:function () { 69 return "<cc.LabelTTF | FontName =" + this._fontName + " FontSize = " + this._fontSize.toFixed(1) + ">"; 70 }, 71 72 setColor:function (color3) { 73 if ((this._color.r == color3.r) && (this._color.g == color3.g) && (this._color.b == color3.b)) { 74 return; 75 } 76 77 this._color = this._colorUnmodified = new cc.Color3B(color3.r, color3.g, color3.b); 78 this._setColorStyleStr(); 79 this.setNodeDirty(); 80 }, 81 82 setOpacity:function (opacity) { 83 if (this._opacity === opacity) { 84 return; 85 } 86 87 this._opacity = opacity; 88 this._setColorStyleStr(); 89 this.setNodeDirty(); 90 }, 91 92 _setColorStyleStr:function () { 93 this._colorStyleStr = "rgba(" + this._color.r + "," + this._color.g + "," + this._color.b + ", " + this._opacity / 255 + ")"; 94 }, 95 96 /** 97 * changes the string to render 98 * @warning Changing the string is as expensive as creating a new cc.LabelTTF. To obtain better performance use cc.LabelAtlas 99 * @param {String} string text for the label 100 */ 101 setString:function (string) { 102 if (this._string != string) { 103 this._string = string + ""; 104 105 // Force update 106 if (this._string.length > 0) { 107 this._updateTTF(); 108 } 109 } 110 }, 111 112 /** 113 * returns the text of the label 114 * @return {String} 115 */ 116 getString:function () { 117 return this._string; 118 }, 119 120 /** 121 * return Horizontal Alignment of cc.LabelTTF 122 * @return {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} 123 */ 124 getHorizontalAlignment:function () { 125 return this._hAlignment; 126 }, 127 128 /** 129 * set Horizontal Alignment of cc.LabelTTF 130 * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} Horizontal Alignment 131 */ 132 setHorizontalAlignment:function (alignment) { 133 if (alignment != this._hAlignment) { 134 this._hAlignment = alignment; 135 136 // Force update 137 if (this._string.length > 0) { 138 this._updateTTF(); 139 } 140 } 141 }, 142 143 /** 144 * return Vertical Alignment of cc.LabelTTF 145 * @return {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} 146 */ 147 getVerticalAlignment:function () { 148 return this._vAlignment; 149 }, 150 151 /** 152 * set Vertical Alignment of cc.LabelTTF 153 * @param {cc.VERTICAL_TEXT_ALIGNMENT_TOP|cc.VERTICAL_TEXT_ALIGNMENT_CENTER|cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM} verticalAlignment 154 */ 155 setVerticalAlignment:function (verticalAlignment) { 156 if (verticalAlignment != this._vAlignment) { 157 this._vAlignment = verticalAlignment; 158 159 // Force update 160 if (this._string.length > 0) { 161 this._updateTTF(); 162 } 163 } 164 }, 165 166 /** 167 * return Dimensions of cc.LabelTTF 168 * @return {cc.Size} 169 */ 170 getDimensions:function () { 171 return this._dimensions; 172 }, 173 174 /** 175 * set Dimensions of cc.LabelTTF 176 * @param {cc.Size} dim 177 */ 178 setDimensions:function (dim) { 179 if (dim.width != this._dimensions.width || dim.height != this._dimensions.height) { 180 this._dimensions = dim; 181 182 // Force udpate 183 if (this._string.length > 0) { 184 this._updateTTF(); 185 } 186 } 187 }, 188 189 /** 190 * return font size of cc.LabelTTF 191 * @return {Number} 192 */ 193 getFontSize:function () { 194 return this._fontSize; 195 }, 196 197 /** 198 * set font size of cc.LabelTTF 199 * @param {Number} fontSize 200 */ 201 setFontSize:function (fontSize) { 202 if (this._fontSize != fontSize) { 203 this._fontSize = fontSize; 204 205 // Force update 206 if (this._string.length > 0) { 207 this._updateTTF(); 208 } 209 } 210 }, 211 212 /** 213 * return font name of cc.LabelTTF 214 * @return {String} 215 */ 216 getFontName:function () { 217 return this._fontName; 218 }, 219 220 /** 221 * set font name of cc.LabelTTF 222 * @param {String} fontName 223 */ 224 setFontName:function (fontName) { 225 if (this._fontName != fontName) { 226 this._fontName = new String(fontName); 227 // Force update 228 if (this._string.length > 0) { 229 this._updateTTF(); 230 } 231 } 232 }, 233 234 /** 235 * initializes the cc.LabelTTF with a font name, alignment, dimension and font size 236 * @param {String} initialize string 237 * @param {String} fontName 238 * @param {Number} fontSize 239 * @param {cc.Size} dimensions 240 * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment 241 * @return {Boolean} return false on error 242 */ 243 initWithString:function (arg) { 244 var strInfo = new String(arg[0]), fontName, fontSize, dimensions, hAlignment, vAlignment; 245 cc.Assert(strInfo != null, "cc.LabelTTF.initWithString() label is null"); 246 if (arg.length == 6) { 247 fontName = arg[1]; 248 fontSize = arg[2]; 249 dimensions = arg[3]; 250 hAlignment = arg[4]; 251 vAlignment = arg[5]; 252 } else if (arg.length == 5) { 253 fontName = arg[1]; 254 fontSize = arg[2]; 255 dimensions = arg[3]; 256 hAlignment = arg[4]; 257 vAlignment = cc.VERTICAL_TEXT_ALIGNMENT_TOP; 258 } else { 259 fontName = arg[1]; 260 fontSize = arg[2]; 261 dimensions = cc.size(0, arg[2]); 262 hAlignment = cc.TEXT_ALIGNMENT_LEFT; 263 vAlignment = cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM; 264 } 265 266 if (this.init(true)) { 267 this._dimensions = cc.size(dimensions.width, dimensions.height); 268 this._fontName = fontName; 269 this._hAlignment = hAlignment; 270 this._vAlignment = vAlignment; 271 this._fontSize = fontSize * cc.CONTENT_SCALE_FACTOR(); 272 this.setString(strInfo); 273 this._fontStyleStr = this._fontSize + "px '" + this._fontName + "'"; 274 this._updateTTF(); 275 return true; 276 } 277 return false; 278 }, 279 /** 280 * renders the label 281 * @param {CanvasContext|Null} ctx 282 */ 283 draw:function (ctx) { 284 if (cc.renderContextType == cc.CANVAS) { 285 var context = ctx || cc.renderContext; 286 if (this._flipX) 287 context.scale(-1, 1); 288 289 if (this._flipY) 290 context.scale(1, -1); 291 292 //this is fillText for canvas 293 context.fillStyle = this._colorStyleStr; 294 295 if (context.font != this._fontStyleStr) 296 context.font = this._fontStyleStr; 297 298 if (((this._contentSize.width > this._dimensions.width) || this._string.indexOf("\n") > -1) && this._dimensions.width !== 0) { 299 context.textBaseline = cc.LabelTTF._textBaseline[this._vAlignment]; 300 context.textAlign = cc.LabelTTF._textAlign[this._hAlignment]; 301 this._wrapText(context, this._string, 302 -this._dimensions.width * this._anchorPoint.x, 303 this._dimensions.height * this._anchorPoint.y, 304 this._dimensions.width, 305 this._dimensions.height, 306 this._fontSize * 1.2); 307 } else if (this._dimensions.width == 0) { 308 context.textBaseline = "bottom"; 309 context.textAlign = "left"; 310 if(!this._string.indexOf){ 311 var z = 0; 312 } 313 314 if (this._string.indexOf("\n") > -1) 315 this._multiLineText(context); 316 else 317 context.fillText(this._string, -this._contentSize.width * this._anchorPoint.x, this._contentSize.height * this._anchorPoint.y); 318 } else { 319 context.textBaseline = cc.LabelTTF._textBaseline[this._vAlignment]; 320 context.textAlign = cc.LabelTTF._textAlign[this._hAlignment]; 321 var xOffset = 0, yOffset = 0; 322 if (this._hAlignment == cc.TEXT_ALIGNMENT_RIGHT) 323 xOffset = this._dimensions.width; 324 if (this._hAlignment == cc.TEXT_ALIGNMENT_CENTER) 325 xOffset = this._dimensions.width / 2; 326 327 if (this._vAlignment == cc.VERTICAL_TEXT_ALIGNMENT_TOP) 328 yOffset = -this._dimensions.height; 329 if (this._vAlignment == cc.VERTICAL_TEXT_ALIGNMENT_CENTER) 330 yOffset = -this._dimensions.height / 2; 331 332 context.fillText(this._string, -this._dimensions.width * this._anchorPoint.x + xOffset, 333 this._dimensions.height * this._anchorPoint.y + yOffset); 334 } 335 336 cc.INCREMENT_GL_DRAWS(1); 337 } 338 }, 339 340 _multiLineText:function(context){ 341 var rowHeight = this._fontSize * 1.2; 342 var tmpWords = this._string.split("\n"); 343 var lineHeight = tmpWords.length; 344 var splitStrWidthArr = []; 345 var maxLineWidth = 0; 346 for(var i = 0; i< lineHeight; i++){ 347 splitStrWidthArr[i] = context.measureText(tmpWords[i]).width; 348 if(splitStrWidthArr[i] > maxLineWidth) 349 maxLineWidth = splitStrWidthArr[i]; 350 } 351 352 var centerPoint = cc.p(maxLineWidth / 2,(lineHeight * rowHeight) / 2); 353 for (i = 0; i < lineHeight; i++) { 354 var xOffset = -splitStrWidthArr[i]/2; 355 if (this._hAlignment == cc.TEXT_ALIGNMENT_RIGHT) 356 xOffset = centerPoint.x - maxLineWidth; 357 if (this._hAlignment == cc.TEXT_ALIGNMENT_CENTER) 358 xOffset = maxLineWidth - splitStrWidthArr[i]; 359 context.fillText(tmpWords[i], xOffset, i * rowHeight - centerPoint.y + rowHeight/2); 360 } 361 }, 362 363 _wrapText:function (context, text, x, y, maxWidth, maxHeight, lineHeight) { 364 var num = this._lineCount() - 1; 365 var xOffset = 0, yOffset = 0; 366 if (this._hAlignment === cc.TEXT_ALIGNMENT_RIGHT) 367 xOffset = maxWidth; 368 if (this._hAlignment === cc.TEXT_ALIGNMENT_CENTER) 369 xOffset = maxWidth / 2; 370 371 if (this._vAlignment === cc.VERTICAL_TEXT_ALIGNMENT_TOP) 372 yOffset = -maxHeight; 373 if (this._vAlignment === cc.VERTICAL_TEXT_ALIGNMENT_BOTTOM) 374 yOffset = -lineHeight * num; 375 if (this._vAlignment === cc.VERTICAL_TEXT_ALIGNMENT_CENTER) 376 yOffset = -maxHeight / 2 - (lineHeight * num / 2); 377 378 var tmpWords = text.split("\n"); 379 for (var j = 0; j < tmpWords.length; j++) { 380 var jOffset = j * lineHeight; 381 var words = tmpWords[j].split(" "); 382 var line = ""; 383 384 for (var n = 0; n < words.length; n++) { 385 var testLine = line + words[n] + " "; 386 var testWidth = context.measureText(testLine).width - context.measureText(" ").width; 387 if (testWidth >= maxWidth) { 388 context.fillText(line, x + xOffset, y + yOffset + jOffset); 389 y += lineHeight; 390 line = words[n] + " "; 391 } else { 392 line = testLine; 393 } 394 if (n == words.length - 1) { 395 context.fillText(line, x + xOffset, y + yOffset + jOffset); 396 } 397 } 398 } 399 }, 400 401 _lineCount:function () { 402 if (this._dimensions.width == 0) { 403 return 1; 404 } 405 var context = cc.renderContext; 406 var words = this._string.split(" "); 407 var line = "", num = 0; 408 cc.renderContext.save(); 409 for (var n = 0; n < words.length; n++) { 410 var tmpLine = line + words[n] + " "; 411 var tmpWidth = context.measureText(tmpLine).width - context.measureText(" ").width; 412 if (tmpWidth >= this._dimensions.width) { 413 num++; 414 line = words[n] + " "; 415 } 416 else { 417 line = tmpLine; 418 } 419 if (n == words.length - 1) { 420 num++; 421 } 422 } 423 cc.renderContext.restore(); 424 return num; 425 }, 426 427 _updateTTF:function () { 428 var oldFontStr = cc.renderContext.font; 429 this._fontStyleStr = this._fontSize + "px '" + this._fontName + "'"; 430 cc.renderContext.font = this._fontStyleStr; 431 var dim = cc.renderContext.measureText(this._string); 432 this.setContentSize(cc.size(dim.width, this._fontSize)); 433 cc.renderContext.font = oldFontStr; 434 this.setNodeDirty(); 435 } 436 }); 437 438 cc.LabelTTF._textAlign = ["left", "center", "right"]; 439 440 cc.LabelTTF._textBaseline = ["top", "middle", "bottom"]; 441 442 /** 443 * creates a cc.LabelTTF from a fontname, alignment, dimension and font size 444 * @param {String} label 445 * @param {String} fontName 446 * @param {Number} fontSize 447 * @param {cc.Size} dimensions 448 * @param {cc.TEXT_ALIGNMENT_LEFT|cc.TEXT_ALIGNMENT_CENTER|cc.TEXT_ALIGNMENT_RIGHT} alignment 449 * @return {cc.LabelTTF|Null} 450 * @example 451 * // Example 452 * var myLabel = cc.LabelTTF.create('label text', 'Times New Roman', 32, cc.size(32,16), cc.TEXT_ALIGNMENT_LEFT); 453 */ 454 cc.LabelTTF.create = function (/* Multi arguments */) { 455 var ret = new cc.LabelTTF(); 456 if (ret.initWithString(arguments)) { 457 return ret; 458 } 459 return null; 460 }; 461 462 cc.LabelTTF.node = function () { 463 return cc.LabelTTF.create(); 464 }; 465