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 * the DOM object 28 * @class 29 * @type {Object} 30 */ 31 cc.DOM = {}; 32 33 /** 34 * @function 35 * @private 36 * @param x 37 */ 38 cc.DOM.addMethods = function (x) { 39 for (var funcs in cc.DOM.methods) { 40 x[funcs] = cc.DOM.methods[funcs]; 41 } 42 }; 43 cc.DOM.methods = /** @lends cc.DOM# */{ 44 /** 45 * Replace the set position of ccNode 46 * @param {object|Number} x 47 * @param {Number} y 48 */ 49 setPosition:function (x, y) { 50 if (arguments.length == 2) { 51 this._position.x = x; 52 this._position.y = y; 53 //this._position = cc.p(newPosOrxValue,yValue); 54 } else { 55 this._position = x; 56 } 57 this.setNodeDirty(); 58 this.dom.translates(this._position.x, -this._position.y); 59 }, 60 /** 61 * replace set Position Y of ccNode 62 * @param {Number} y 63 */ 64 setPositionY:function (y) { 65 this._position.y = y; 66 this.setNodeDirty(); 67 this.dom.translates(this._position.x, -this._position.y); 68 }, 69 70 /** 71 * replace set Position X of ccNode 72 * @param {Number} x 73 */ 74 setPositionX:function (x) { 75 this._position.x = x; 76 this.setNodeDirty(); 77 this.dom.translates(this._position.x, -this._position.y); 78 }, 79 80 /** 81 * replace set Scale of ccNode 82 * @param {object|Number} scale 83 * @param {Number} scaleY 84 */ 85 setScale:function (scale, scaleY) { 86 //save dirty region when before change 87 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 88 89 this._scaleX = scale; 90 this._scaleY = scaleY || scale; 91 92 //save dirty region when after changed 93 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 94 this.setNodeDirty(); 95 this.dom.resize(this._scaleX, this._scaleY); 96 }, 97 98 /** 99 * replace set Scale X of ccNode 100 * @param {Number} x 101 */ 102 setScaleX:function (x) { 103 this._scaleX = x; 104 this.setNodeDirty(); 105 this.dom.resize(this._scaleX, this._scaleY); 106 }, 107 108 /** 109 * replace set Scale Y of ccNode 110 * @param {Number} y 111 */ 112 setScaleY:function (y) { 113 this._scaleY = y; 114 this.setNodeDirty(); 115 this.dom.resize(this._scaleX, this._scaleY); 116 }, 117 118 /** 119 * replace set anchorpoint of ccNode 120 * @param {object} point 121 */ 122 setAnchorPoint:function (point) { 123 this._anchorPoint = point; 124 this._anchorPointInPoints = cc.p(this._contentSize.width * this._anchorPoint.x, 125 this._contentSize.height * this._anchorPoint.y); 126 this.dom.style[cc.$.pfx + 'TransformOrigin'] = '' + this._anchorPointInPoints.x + 'px ' + -this._anchorPointInPoints.y + 'px'; 127 if (this.isIgnoreAnchorPointForPosition()) { 128 this.dom.style.marginLeft = 0; 129 this.dom.style.marginBottom = 0; 130 } 131 else { 132 this.dom.style.marginLeft = (this.isToggler) ? 0 : -this._anchorPointInPoints.x + 'px'; 133 this.dom.style.marginBottom = -this._anchorPointInPoints.y + 'px'; 134 } 135 this.setNodeDirty(); 136 }, 137 138 /** 139 * replace set ContentSize of ccNode 140 * @param {cc.Size} size 141 */ 142 setContentSize:function (size) { 143 if (!cc.sizeEqualToSize(size, this._contentSize)) { 144 this._contentSize = size; 145 this._anchorPointInPoints = cc.p(this._contentSize.width * this._anchorPoint.x, 146 this._contentSize.height * this._anchorPoint.y); 147 this.dom.width = size.width; 148 this.dom.height = size.height; 149 this.setAnchorPoint(this.getAnchorPoint()); 150 } 151 if (this.canvas) { 152 this.canvas.width = this._contentSize.width; 153 this.canvas.height = this._contentSize.height; 154 } 155 this.setNodeDirty(); 156 this.redraw(); 157 }, 158 159 /** 160 * replace set Rotation of ccNode 161 * @param {Number} newRotation 162 */ 163 setRotation:function (newRotation) { 164 if (this._rotation == newRotation) 165 return; 166 //save dirty region when before change 167 //this._addDirtyRegionToDirector(this.getBoundingBoxToWorld()); 168 169 this._rotationX = this._rotationY = newRotation; 170 this._rotationRadiansX = this._rotationX * (Math.PI / 180); 171 this._rotationRadiansY = this._rotationY * (Math.PI / 180); 172 173 this.setNodeDirty(); 174 this.dom.rotate(newRotation); 175 }, 176 177 /** 178 * replace set SkewX of ccNode 179 * @param {Number} x 180 */ 181 setSkewX:function (x) { 182 this._skewX = x; 183 this.setNodeDirty(); 184 this.dom.setSkew(this._skewX, this._skewY); 185 }, 186 187 /** 188 * replace set SkewY of ccNode 189 * @param {Number} y 190 */ 191 setSkewY:function (y) { 192 this._skewY = y; 193 this.setNodeDirty(); 194 this.dom.setSkew(this._skewX, this._skewY); 195 }, 196 197 /** 198 * replace set Visible of ccNode 199 * @param {Boolean} x 200 */ 201 setVisible:function (x) { 202 this._visible = x; 203 this.setNodeDirty(); 204 if (this.dom) 205 this.dom.style.display = (x) ? 'block' : 'none'; 206 }, 207 _setZOrder:function (z) { 208 this._zOrder = z 209 this.setNodeDirty(); 210 if (this.dom) 211 this.dom.zIndex = z; 212 }, 213 214 /** 215 * replace set Parent of ccNode 216 * @param {cc.Node} p 217 */ 218 setParent:function (p) { 219 this._parent = p; 220 221 if (p !== null) { 222 p.setAnchorPoint(p.getAnchorPoint()); 223 this.setNodeDirty(); 224 cc.DOM.parentDOM(this); 225 } 226 }, 227 228 /** 229 * replace resume Schedule and actions of ccNode 230 */ 231 resumeSchedulerAndActions:function () { 232 this.getScheduler().resumeTarget(this); 233 this.getActionManager().resumeTarget(this); 234 //if dom does not have parent, but node has no parent and its running 235 if (this.dom && !this.dom.parentNode) { 236 if (!this.getParent()) { 237 this.dom.appendTo(cc.container); 238 } 239 else { 240 cc.DOM.parentDOM(this); 241 } 242 } 243 if (this.dom) 244 this.dom.style.visibility = "visible"; 245 }, 246 247 /** 248 * replace pause Schedule and Actions of ccNode 249 */ 250 pauseSchedulerAndActions:function () { 251 this.getScheduler().pauseTarget(this); 252 this.getActionManager().pauseTarget(this); 253 if (this.dom) { 254 this.dom.style.visibility = 'hidden'; 255 } 256 }, 257 258 /** 259 * replace clean up of ccNode 260 */ 261 cleanup:function () { 262 // actions 263 this.stopAllActions(); 264 this.unscheduleAllCallbacks(); 265 266 // timers 267 this._arrayMakeObjectsPerformSelector(this._children, cc.Node.StateCallbackType.cleanup); 268 if (this.dom) { 269 this.dom.remove(); 270 } 271 }, 272 /** 273 * replace remove from parent and clean up of ccNode 274 */ 275 removeFromParentAndCleanup:function () { 276 this.dom.remove(); 277 }, 278 setOpacity:function (o) { 279 this._opacity = o; 280 this.dom.style.opacity = o / 255; 281 }, 282 /** 283 * refresh/updates the DOM element 284 */ 285 redraw:function () { 286 if (this.isSprite) { 287 var tmp = this._children; 288 this._children = []; 289 cc.Sprite.prototype.visit.call(this, this.ctx); 290 this._children = tmp; 291 } 292 else { 293 cc.Sprite.prototype.visit.call(this, this.ctx); 294 } 295 } 296 }; 297 298 cc.DOM._resetEGLViewDiv = function(){ 299 var eglViewDiv = cc.$("#EGLViewDiv"); 300 if(eglViewDiv){ 301 var eglViewer = cc.EGLView.getInstance(); 302 var designSize = eglViewer.getDesignResolutionSize(); 303 var viewPortRect = eglViewer.getViewPortRect(); 304 var screenSize = eglViewer.getFrameSize(); 305 var designSizeWidth = designSize.width, designSizeHeight = designSize.height; 306 if((designSize.width === 0) && (designSize.height === 0)){ 307 designSizeWidth = screenSize.width; 308 designSizeHeight = screenSize.height; 309 } 310 311 var viewPortWidth = viewPortRect.size.width, viewPortHeight = viewPortRect.size.height; 312 if((viewPortRect.size.width === 0) && (viewPortRect.size.height === 0)){ 313 viewPortWidth = screenSize.width; 314 viewPortHeight = screenSize.height; 315 } 316 317 eglViewDiv.style.position = 'absolute'; 318 //x.dom.style.display='block'; 319 eglViewDiv.style.width = designSizeWidth + "px"; 320 eglViewDiv.style.maxHeight = designSizeHeight + "px"; 321 eglViewDiv.style.margin = 0; 322 323 eglViewDiv.resize(eglViewer.getScaleX(), eglViewer.getScaleY()); 324 325 if (viewPortWidth < screenSize.width) { 326 eglViewDiv.style.left = ((viewPortWidth - designSizeWidth) / 2 327 + (screenSize.width - viewPortWidth ) / 2) + "px"; 328 } else { 329 eglViewDiv.style.left = (viewPortWidth - designSizeWidth) / 2 + "px"; 330 } 331 332 if (viewPortHeight < screenSize.height) { 333 eglViewDiv.style.bottom = ((screenSize.height - viewPortHeight ) / 2) + "px"; 334 } else { 335 eglViewDiv.style.bottom = "0px"; 336 } 337 } 338 }; 339 340 /** 341 * @function 342 * @private 343 * @param x 344 * @return {Boolean} 345 */ 346 cc.DOM.parentDOM = function (x) { 347 var p = x.getParent(); 348 //if has parent, parent need to have dom too 349 if (!p || !x.dom) 350 return false; 351 if (!p.dom) { 352 cc.DOM.placeHolder(p); 353 p.setParent = cc.DOM.methods.setParent; 354 } 355 //if parent have dom, attach self to parent 356 x.dom.appendTo(p.dom); 357 p.setAnchorPoint(p.getAnchorPoint()); 358 359 if (p.getParent()) { 360 cc.DOM.parentDOM(p); 361 } else { 362 //parent has no more parent, if its running, then add it to the container 363 if (p.isRunning()) { 364 //find EGLView div 365 var eglViewDiv = cc.$("#EGLViewDiv"); 366 if (eglViewDiv) { 367 p.dom.appendTo(eglViewDiv); 368 } else { 369 eglViewDiv = cc.$new("div"); 370 eglViewDiv.id = "EGLViewDiv"; 371 372 var eglViewer = cc.EGLView.getInstance(); 373 var designSize = eglViewer.getDesignResolutionSize(); 374 var viewPortRect = eglViewer.getViewPortRect(); 375 var screenSize = eglViewer.getFrameSize(); 376 var designSizeWidth = designSize.width, designSizeHeight = designSize.height; 377 if ((designSize.width === 0) && (designSize.height === 0)) { 378 designSizeWidth = screenSize.width; 379 designSizeHeight = screenSize.height; 380 } 381 382 var viewPortWidth = viewPortRect.size.width, viewPortHeight = viewPortRect.size.height; 383 if ((viewPortRect.size.width === 0) && (viewPortRect.size.height === 0)) { 384 viewPortWidth = screenSize.width; 385 viewPortHeight = screenSize.height; 386 } 387 388 eglViewDiv.style.position = 'absolute'; 389 //x.dom.style.display='block'; 390 eglViewDiv.style.width = designSizeWidth + "px"; 391 eglViewDiv.style.maxHeight = designSizeHeight + "px"; 392 eglViewDiv.style.margin = 0; 393 394 eglViewDiv.resize(eglViewer.getScaleX(), eglViewer.getScaleY()); 395 396 if (viewPortWidth < screenSize.width) { 397 eglViewDiv.style.left = ((viewPortWidth - designSizeWidth) / 2 398 + (screenSize.width - viewPortWidth ) / 2) + "px"; 399 } else { 400 eglViewDiv.style.left = (viewPortWidth - designSizeWidth) / 2 + "px"; 401 } 402 403 if (viewPortHeight < screenSize.height) { 404 eglViewDiv.style.bottom = ((screenSize.height - viewPortHeight ) / 2) + "px"; 405 } else { 406 eglViewDiv.style.bottom = "0px"; 407 } 408 409 p.dom.appendTo(eglViewDiv); 410 eglViewDiv.appendTo(cc.container); 411 } 412 } 413 } 414 return true; 415 }; 416 417 /** 418 * @function 419 * @private 420 * @param x 421 */ 422 cc.DOM.setTransform = function (x) { 423 if (x.ctx) { 424 /* x.ctx.save(); 425 x.ctx.setTransform(1,0,0,1,0,0); 426 x.ctx.clearRect(0,0,x.canvas.width, x.canvas.height); 427 x.ctx.restore();*/ 428 x.ctx.translate(x.getAnchorPointInPoints().x, x.getAnchorPointInPoints().y); 429 if (x.isSprite) { 430 var tmp = x._children; 431 x._children = []; 432 cc.Sprite.prototype.visit.call(x, x.ctx); 433 x._children = tmp; 434 } 435 else { 436 cc.Sprite.prototype.visit.call(x, x.ctx); 437 } 438 } 439 if (x.dom) { 440 x.dom.position.x = x.getPosition().x; 441 x.dom.position.y = -x.getPosition().y; 442 x.dom.rotation = x.getRotation(); 443 x.dom.scale = {x:x.getScaleX(), y:x.getScaleY()}; 444 x.dom.skew = {x:x.getSkewX(), y:x.getSkewY()}; 445 if (x.setAnchorPoint) 446 x.setAnchorPoint(x.getAnchorPoint()); 447 x.dom.transforms(); 448 } 449 450 }; 451 452 /** 453 * @function 454 * @private 455 * @param x 456 */ 457 cc.DOM.forSprite = function (x) { 458 x.dom = cc.$new('div'); 459 x.canvas = cc.$new('canvas'); 460 x.canvas.width = x.getContentSize().width; 461 x.canvas.height = x.getContentSize().height; 462 x.dom.style.position = 'absolute'; 463 x.dom.style.bottom = 0; 464 x.ctx = x.canvas.getContext('2d'); 465 x.dom.appendChild(x.canvas); 466 if (x.getParent()) { 467 cc.DOM.parentDOM(x); 468 } 469 x.isSprite = true; 470 }; 471 472 /** 473 * This creates divs for parent Nodes that are related to the current node 474 * @function 475 * @private 476 * @param x 477 */ 478 cc.DOM.placeHolder = function (x) { 479 //creating a placeholder dom to simulate other ccNode in the hierachy 480 x.dom = cc.$new('div'); 481 x.placeholder = true; 482 x.dom.style.position = 'absolute'; 483 x.dom.style.bottom = 0; 484 //x.dom.style.display='block'; 485 x.dom.style.width = (x.getContentSize().width || cc.Director.getInstance().getWinSize().width) + "px"; 486 x.dom.style.maxHeight = (x.getContentSize().height || cc.Director.getInstance().getWinSize().height) + "px"; 487 x.dom.style.margin = 0; 488 cc.DOM.setTransform(x); 489 x.dom.transforms(); 490 cc.DOM.addMethods(x); 491 //x.dom.style.border = 'red 1px dotted'; 492 }; 493 494 /** 495 * Converts cc.Sprite or cc.MenuItem to DOM elements <br/> 496 * It currently only supports cc.Sprite and cc.MenuItem 497 * @function 498 * @param {cc.Sprite|cc.MenuItem|Array} nodeObject 499 * * @example 500 * // example 501 * cc.DOM.convert(Sprite1, Sprite2, Menuitem); 502 * 503 * var myDOMElements = [Sprite1, Sprite2, MenuItem]; 504 * cc.DOM.convert(myDOMElements); 505 */ 506 cc.DOM.convert = function (nodeObject) { 507 //if passing by list, make it an array 508 if (arguments.length > 1) { 509 cc.DOM.convert(arguments); 510 return; 511 } else if (arguments.length == 1 && !arguments[0].length) { 512 cc.DOM.convert([arguments[0]]); 513 return; 514 } 515 var args = arguments[0]; 516 for (var i = 0; i < args.length; i++) { 517 //first check if its sprite 518 if (args[i] instanceof cc.Sprite) { 519 // create a canvas 520 if (!args[i].dom) 521 cc.DOM.forSprite(args[i]); 522 } else { 523 cc.log('DOM converter only supports sprite and menuitems yet'); 524 } 525 cc.DOM.addMethods(args[i]); 526 args[i].visit = function () { 527 }; 528 args[i].transform = function () { 529 }; 530 cc.DOM.setTransform(args[i]); 531 args[i].setVisible(args[i].isVisible()); 532 } 533 }; 534