1 /* 2 SpiderGL Computer Graphics Library 3 Copyright (c) 2010, Marco Di Benedetto - Visual Computing Lab, ISTI - CNR 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions are met: 8 * Redistributions of source code must retain the above copyright 9 notice, this list of conditions and the following disclaimer. 10 * Redistributions in binary form must reproduce the above copyright 11 notice, this list of conditions and the following disclaimer in the 12 documentation and/or other materials provided with the distribution. 13 * Neither the name of SpiderGL nor the 14 names of its contributors may be used to endorse or promote products 15 derived from this software without specific prior written permission. 16 17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 DISCLAIMED. IN NO EVENT SHALL PAUL BRUNT BE LIABLE FOR ANY 21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 /** 30 * @fileOverview UI 31 */ 32 33 /** 34 * The SpiderGL.UserInterface namespace. 35 * 36 * @namespace The SpiderGL.UserInterface namespace. 37 */ 38 SpiderGL.UserInterface = { }; 39 40 /** 41 * Creates a SpiderGL.UserInterface.CanvasHandler. 42 * 43 * SpiderGL.UserInterface.CanvasHandler is an event handler used to implement an easy controller for WebGL canvas. 44 * It should not be directly used. Use {@link SpiderGL.UserInterface.handleCanvas} or {@link SpiderGL.UserInterface.handleCanvasOnLoad} to install it to a listener object. 45 * 46 * @class The SpiderGL.UserInterface.CanvasHandler is an event handler used to implement an easy controller for WebGL canvas. It should not be directly used. 47 * 48 * @augments SpiderGL.Core.ObjectBase 49 * 50 * @param {WebGLRenderingcontext} gl The WebGLRenderingcontext to pass to the handler. 51 * @param {object} handler The event handler to which events will be dispatched. 52 * @param {object} [options] Optional parameters 53 * @param {bool} [options.standardGLUnpack=SpiderGL.UserInterface.CanvasHandler.DEFAULT_STANDARD_GL_UNPACK] If true, sets the default OpenGL unpack behaviour. 54 * @param {number} [options.animateRate=SpiderGL.UserInterface.CanvasHandler.DEFAULT_ANIMATE_RATE] Additional options. 55 * 56 * @see SpiderGL.UserInterface.handleCanvas 57 * @see SpiderGL.UserInterface.handleCanvasOnLoad 58 */ 59 SpiderGL.UserInterface.CanvasHandler = function (gl, handler, options) { 60 SpiderGL.Core.ObjectBase.call(this); 61 62 options = options || { }; 63 64 var that = this; 65 var canvas = gl.canvas; 66 67 this._gl = gl; 68 this._canvas = canvas; 69 this._handler = handler; 70 71 this._ignoreKeyRepeat = SpiderGL.Utility.getDefaultValue(options.ignoreKeyRepeat, SpiderGL.UserInterface.CanvasHandler.DEFAULT_IGNORE_KEY_REPEAT); 72 this._keysDown = { }; 73 74 this._mouseButtonsDown = [false, false, false]; 75 76 this._dragging = [false, false, false]; 77 this._dragStartPos = [[0, 0], [0, 0], [0, 0]]; 78 this._dragEndPos = [[0, 0], [0, 0], [0, 0]]; 79 this._dragDeltaPos = [[0, 0], [0, 0], [0, 0]]; 80 81 this._cursorPos = [0, 0]; 82 this._cursorPrevPos = [0, 0]; 83 this._cursorDeltaPos = [0, 0]; 84 85 this._drawEventPending = false; 86 this._drawEventHandler = function () { that._onDraw(); }; 87 this._postDrawEventFunction = function () { that._postDrawEvent(); }; 88 89 this._animateTime = Date.now(); 90 this._animatePrevTime = this._animateTime; 91 this._animateDeltaTime = 0; 92 this._animateRate = 0; 93 this._animateID = null; 94 this._animateEventHandler = function () { that._onAnimate(); }; 95 this._animateMS = -1; 96 this._animateWithTimeout = false; 97 this._fastAnimate = false; 98 99 this._fpsUpdateMS = 1000; 100 this._fpsTime = Date.now(); 101 this._fpsCount = 0; 102 this._fps = 0; 103 104 /** @private */ 105 var handleMessage = function (evt) { 106 if (evt.source != window) return; 107 if (evt.data == SpiderGL.UserInterface.CanvasHandler._FAST_ANIMATE_MESSAGE_NAME) { 108 evt.stopPropagation(); 109 that._onAnimate(); 110 } 111 else if (evt.data == SpiderGL.UserInterface.CanvasHandler._FAST_DRAW_MESSAGE_NAME) { 112 evt.stopPropagation(); 113 that._onDraw(); 114 } 115 }; 116 window.addEventListener("message", handleMessage, true); 117 118 canvas.tabIndex = 0; 119 120 canvas.addEventListener("unload", function (e) { that._onTerminate (e); }, false); 121 canvas.addEventListener("keydown", function (e) { that._onKeyDown (e); }, false); 122 canvas.addEventListener("keyup", function (e) { that._onKeyUp (e); }, false); 123 canvas.addEventListener("keypress", function (e) { that._onKeyPress (e); }, false); 124 canvas.addEventListener("mousedown", function (e) { that._onMouseButtonDown (e); }, false); 125 canvas.addEventListener("mouseup", function (e) { that._onMouseButtonUp (e); }, false); 126 canvas.addEventListener("mousemove", function (e) { that._onMouseMove (e); }, false); 127 canvas.addEventListener("mouseout", function (e) { that._onMouseOut (e); }, false); 128 canvas.addEventListener("click", function (e) { that._onClick (e); }, false); 129 canvas.addEventListener("dblclick", function (e) { that._onDoubleClick (e); }, false); 130 canvas.addEventListener("resize", function (e) { that._onResize (e); }, false); 131 canvas.addEventListener("DOMMouseScroll", function (e) { that._onMouseWheel (e); }, false); 132 canvas.addEventListener("mousewheel", function (e) { that._onMouseWheel (e); }, false); 133 canvas.addEventListener("blur", function (e) { that._onBlur (e); }, false); 134 135 window.addEventListener("mouseup", function (e) { that._onWindowMouseButtonUp (e); }, false); 136 window.addEventListener("mousemove", function (e) { that._onWindowMouseMove (e); }, false); 137 138 canvas.addEventListener("touchstart", SpiderGL.UserInterface.CanvasHandler._touchHandler, true); 139 canvas.addEventListener("touchend", SpiderGL.UserInterface.CanvasHandler._touchHandler, true); 140 canvas.addEventListener("touchmove", SpiderGL.UserInterface.CanvasHandler._touchHandler, true); 141 canvas.addEventListener("touchcancel", SpiderGL.UserInterface.CanvasHandler._touchHandler, true); 142 143 var standardGLUnpack = SpiderGL.Utility.getDefaultValue(options.standardGLUnpack, SpiderGL.UserInterface.CanvasHandler.DEFAULT_STANDARD_GL_UNPACK); 144 if (standardGLUnpack) { 145 SpiderGL.WebGL.Context.setStandardGLUnpack(gl); 146 } 147 148 this.animateRate = SpiderGL.Utility.getDefaultValue(options.animateRate, SpiderGL.UserInterface.CanvasHandler.DEFAULT_ANIMATE_RATE); 149 } 150 151 SpiderGL.UserInterface.CanvasHandler._FAST_DRAW_MESSAGE_NAME = "spidergl-fast-draw-message"; 152 SpiderGL.UserInterface.CanvasHandler._FAST_ANIMATE_MESSAGE_NAME = "spidergl-fast-animate-message"; 153 154 /** 155 * Default value for animate rate. 156 * 157 * @type number 158 * 159 * @default 0 160 */ 161 SpiderGL.UserInterface.CanvasHandler.DEFAULT_ANIMATE_RATE = 0; 162 163 /** 164 * Default value for ignoring key repeats. 165 * 166 * @type bool 167 * 168 * @default true 169 */ 170 SpiderGL.UserInterface.CanvasHandler.DEFAULT_IGNORE_KEY_REPEAT = true; 171 172 /** 173 * Default value for applying standard OpenGL pixel unpack parameters. 174 * 175 * @type bool 176 * 177 * @default true 178 */ 179 SpiderGL.UserInterface.CanvasHandler.DEFAULT_STANDARD_GL_UNPACK = true; 180 181 /** 182 * Default name of the property to install in the handler object for accessing the canvas handler. 183 * 184 * @type string 185 * 186 * @default "ui" 187 */ 188 SpiderGL.UserInterface.CanvasHandler.DEFAULT_PROPERTY_NAME = "ui"; 189 190 SpiderGL.UserInterface.CanvasHandler._touchHandler = function (event) { 191 var touches = event.changedTouches, 192 193 first = touches[0], 194 type = ""; 195 196 switch(event.type) 197 { 198 case "touchstart": type = "mousedown"; break; 199 case "touchmove": type = "mousemove"; break; 200 case "touchend": type = "mouseup"; break; 201 default: return; 202 } 203 204 //initMouseEvent(type, canBubble, cancelable, view, clickCount, 205 // screenX, screenY, clientX, clientY, ctrlKey, 206 // altKey, shiftKey, metaKey, button, relatedTarget); 207 208 var simulatedEvent = document.createEvent("MouseEvent"); 209 simulatedEvent.initMouseEvent( 210 type, true, true, window, 1, 211 first.screenX, first.screenY, 212 first.clientX, first.clientY, false, 213 false, false, false, 0/*left*/, null 214 ); 215 216 first.target.dispatchEvent(simulatedEvent); 217 event.preventDefault(); 218 }; 219 220 SpiderGL.UserInterface.CanvasHandler.prototype = { 221 _firstNotify : function () { 222 this._onInitialize(); 223 if (this._animateRate > 0) { 224 this._onAnimate(); 225 } 226 this.postDrawEvent(); 227 }, 228 229 _dispatch : function () { 230 var evt = arguments[0]; 231 var handler = this._handler; 232 var method = handler[evt]; 233 if (!method) return; 234 var args = Array.prototype.slice.call(arguments, 1); 235 var r = method.apply(handler, args); 236 //if (r === false) return; 237 //this._postDrawEvent(); 238 }, 239 240 _postDrawEvent : function () { 241 if (this._drawEventPending) return; 242 this._drawEventPending = true; 243 //setTimeout(this._drawEventHandler, 0); 244 window.postMessage(SpiderGL.UserInterface.CanvasHandler._FAST_DRAW_MESSAGE_NAME, "*"); 245 }, 246 247 _getMouseClientPos : function(e) { 248 var r = this._canvas.getBoundingClientRect(); 249 var w = this._canvas.width; 250 var h = this._canvas.height; 251 var x = e.clientX - r.left; 252 var y = h - 1 - (e.clientY - r.top); 253 var outside = ((x < 0) || (x >= w) || (y < 0) || (y >= h)); 254 return [x, y, outside]; 255 }, 256 257 /* 258 _getTouchClientPos : function(e) { 259 return this._getMouseClientPos(e); 260 }, 261 */ 262 263 _onInitialize : function () { 264 this._dispatch("onInitialize"); 265 }, 266 267 _onTerminate : function () { 268 this._dispatch("onTerminate"); 269 }, 270 271 _onBlur : function (e) { 272 var gl = this._gl; 273 var ks = this._keysDown; 274 for (var c in ks) { 275 if (ks[c]) { 276 ks[c] = false; 277 this._dispatch("onKeyUp", c, null); 278 } 279 } 280 }, 281 282 _onKeyDown : function (e) { 283 var c = e.keyCode || e.charCode; 284 var s = String.fromCharCode(c); 285 if (s.length > 0) { 286 c = s.toUpperCase(); 287 } 288 var wasDown = this._keysDown[c]; 289 this._keysDown[c] = true; 290 if (!wasDown || !this._ignoreKeyRepeat) { 291 this._dispatch("onKeyDown", c, e); 292 } 293 }, 294 295 _onKeyUp : function (e) { 296 var c = e.keyCode || e.charCode; 297 var s = String.fromCharCode(c); 298 if (s.length > 0) { 299 c = s.toUpperCase(); 300 } 301 this._keysDown[c] = false; 302 this._dispatch("onKeyUp", c, e); 303 }, 304 305 _onKeyPress : function (e) { 306 var c = e.keyCode || e.charCode; 307 var s = String.fromCharCode(c); 308 if (s.length > 0) { 309 c = s; 310 } 311 this._dispatch("onKeyPress", c, e); 312 }, 313 314 /* 315 _onTouchStart : function (e) { 316 e = e.changedTouches[0]; 317 this._canvas.focus(); 318 var xy = this._getTouchClientPos(e); 319 this._dispatch("onTouchStart", xy[0], xy[1], e); 320 e.stopPropagation(); 321 }, 322 323 _onTouchEnd : function (e) { 324 e = e.changedTouches[0]; 325 this._canvas.focus(); 326 var xy = this._getTouchClientPos(e); 327 this._dispatch("onTouchEnd", xy[0], xy[1], e); 328 e.stopPropagation(); 329 }, 330 331 _onTouchMove : function (e) { 332 e = e.changedTouches[0]; 333 this._canvas.focus(); 334 var xy = this._getTouchClientPos(e); 335 this._dispatch("onTouchMove", xy[0], xy[1], e); 336 e.stopPropagation(); 337 }, 338 */ 339 340 _onMouseButtonDown : function (e) { 341 this._canvas.focus(); 342 343 var xy = this._getMouseClientPos(e); 344 this._cursorPos = xy; 345 346 var btn = e.button; 347 this._mouseButtonsDown[btn] = true; 348 this._dragStartPos[btn] = [xy[0], xy[1]]; 349 this._dispatch("onMouseButtonDown", btn, xy[0], xy[1], e); 350 351 e.preventDefault(); 352 e.stopPropagation(); 353 }, 354 355 _onMouseButtonUp : function (e) { 356 var xy = this._getMouseClientPos(e); 357 this._cursorPos = xy; 358 359 var btn = e.button; 360 this._mouseButtonsDown[btn] = false; 361 this._dispatch("onMouseButtonUp", btn, xy[0], xy[1], e); 362 363 if (this._dragging[btn]) { 364 this._dragging[btn] = false; 365 var sPos = this._dragStartPos[btn]; 366 var ePos = [xy[0], xy[1]]; 367 this._dragEndPos[btn] = ePos; 368 this._dragDeltaPos[btn] = [ePos[0] - sPos[0], ePos[1] - sPos[1]]; 369 this._dispatch("onDragEnd", btn, ePos[0], ePos[1]); 370 } 371 372 e.stopPropagation(); 373 }, 374 375 _onWindowMouseButtonUp : function (e) { 376 var xy = this._getMouseClientPos(e); 377 this._cursorPos = xy; 378 379 var btn = e.button; 380 if (!xy[2] || !this._mouseButtonsDown[btn]) return; 381 382 this._mouseButtonsDown[btn] = false; 383 this._dispatch("onMouseButtonUp", btn, xy[0], xy[1], e); 384 385 if (this._dragging[btn]) { 386 this._dragging[btn] = false; 387 var sPos = this._dragStartPos[btn]; 388 var ePos = [xy[0], xy[1]]; 389 this._dragEndPos[btn] = ePos; 390 this._dragDeltaPos[btn] = [ePos[0] - sPos[0], ePos[1] - sPos[1]]; 391 this._dispatch("onDragStart", btn, ePos[0], ePos[1]); 392 } 393 394 e.stopPropagation(); 395 }, 396 397 _onMouseMove : function (e) { 398 this._cursorPrevPos = this._cursorPos; 399 400 var xy = this._getMouseClientPos(e); 401 this._cursorPos = xy; 402 403 this._cursorDeltaPos = [this._cursorPos[0] - this._cursorPrevPos[0], this._cursorPos[1] - this._cursorPrevPos[1]]; 404 this._dispatch("onMouseMove", xy[0], xy[1], e); 405 406 for (var i=0; i<3; ++i) { 407 if (!this._mouseButtonsDown[i]) continue; 408 var sPos = this._dragStartPos[i]; 409 var ePos = [xy[0], xy[1]]; 410 this._dragEndPos[i] = ePos; 411 this._dragDeltaPos[i] = [ePos[0] - sPos[0], ePos[1] - sPos[1]]; 412 if (!this._dragging[i]) { 413 this._dragging[i] = true; 414 this._dispatch("onDragStart", i, sPos[0], sPos[1]); 415 } 416 this._dispatch("onDrag", i, ePos[0], ePos[1]); 417 } 418 419 e.stopPropagation(); 420 }, 421 422 _onWindowMouseMove : function (e) { 423 var gl = this._gl; 424 var xy = this._getMouseClientPos(e); 425 426 if (!xy[2]) return; 427 428 for (var i=0; i<3; ++i) { 429 if (!this._dragging[i]) continue; 430 var sPos = this._dragStartPos[i]; 431 var ePos = [xy[0], xy[1]]; 432 this._dragEndPos[i] = ePos; 433 this._dragDeltaPos[i] = [ePos[0] - sPos[0], ePos[1] - sPos[1]]; 434 this._dispatch("onDrag", i, ePos[0], ePos[1]); 435 } 436 437 e.stopPropagation(); 438 }, 439 440 _onMouseWheel : function (e) { 441 var xy = this._getMouseClientPos(e); 442 var delta = 0; 443 if (!e) { 444 e = window.event; 445 } 446 if (e.wheelDelta) { 447 delta = e.wheelDelta / 120; 448 if (window.opera) { 449 delta = -delta; 450 } 451 } 452 else if (e.detail) { 453 delta = -e.detail / 3; 454 } 455 if (delta) { 456 this._dispatch("onMouseWheel", delta, xy[0], xy[1], e); 457 } 458 459 if (e.preventDefault) { 460 e.preventDefault(); 461 } 462 463 e.stopPropagation(); 464 }, 465 466 _onMouseOut: function(e) { 467 }, 468 469 _onClick : function (e) { 470 var xy = this._getMouseClientPos(e); 471 this._dispatch("onClick", e.button, xy[0], xy[1], e); 472 }, 473 474 _onDoubleClick : function (e) { 475 var xy = this._getMouseClientPos(e); 476 this._dispatch("onDoubleClick", e.button, xy[0], xy[1], e); 477 }, 478 479 _onResize : function (e) { 480 this._dispatch("onResize", this._canvas.width, this._canvas.height, e); 481 }, 482 483 _onAnimate : function () { 484 this._animatePrevTime = this._animateTime; 485 this._animateTime = Date.now(); 486 this._animateDeltaTime = this._animateTime - this._animatePrevTime; 487 this._dispatch("onAnimate", this._animateDeltaTime / 1000); 488 if (this._animateMS >= 0) { 489 if (this._animateWithTimeout) { 490 setTimeout(this._animateEventHandler, this._animateMS); 491 } 492 } 493 else if (this._fastAnimate) { 494 window.postMessage(SpiderGL.UserInterface.CanvasHandler._FAST_ANIMATE_MESSAGE_NAME, "*"); 495 } 496 }, 497 498 _onDraw : function () { 499 this._drawEventPending = false; 500 501 this._fpsCount++; 502 503 var now = Date.now(); 504 var fpsDT = now - this._fpsTime; 505 if (fpsDT >= this._fpsUpdateMS) { 506 this._fps = SpiderGL.Math.floor(this._fpsCount * 1000 / fpsDT); 507 this._fpsTime = now; 508 this._fpsCount = 0; 509 } 510 511 this._dispatch("onDraw"); 512 }, 513 514 /** 515 * Gets the canvas hijacked WebGLRenderingContext. 516 * 517 * @type WebGLRenderingContext 518 * 519 * @readonly 520 */ 521 get gl() { 522 return this._gl; 523 }, 524 525 /** 526 * Gets the associated canvas. 527 * 528 * @type HTMLCanvasElement 529 * 530 * @readonly 531 */ 532 get canvas() { 533 return this._canvas; 534 }, 535 536 /** 537 * Gets the width of the associated canvas. 538 * 539 * @type number 540 * 541 * @readonly 542 */ 543 get width() { 544 return this._canvas.width; 545 }, 546 547 /** 548 * Gets the height of the associated canvas. 549 * 550 * @type number 551 * 552 * @readonly 553 */ 554 get height() { 555 return this._canvas.height; 556 }, 557 558 /** 559 * Gets a function that, once called, sends a draw event, which once handled will call the onDraw method of the registered handler. 560 * 561 * @type function 562 * 563 * @readonly 564 */ 565 get postDrawEvent() { 566 return this._postDrawEventFunction; 567 }, 568 569 /** 570 * Gets the time, in seconds, of the current onAnimate event. 571 * 572 * @type number 573 * 574 * @readonly 575 */ 576 get animateTime() { 577 return this._animateTime; 578 }, 579 580 /** 581 * Gets the time, in seconds, of the last onAnimate event. 582 * 583 * @type number 584 * 585 * @readonly 586 */ 587 get animatePrevTime() { 588 return this._animatePrevTime; 589 }, 590 591 /** 592 * Gets the elapsed time, in milliseconds, between the last and the current onAnimate event. 593 * 594 * @type number 595 * 596 * @readonly 597 */ 598 get animateDeltaTime() { 599 return this._animateDeltaTime; 600 }, 601 602 /** 603 * Gets/Sets the frequency (calls per second) used to emit the onAnimate event. 604 * If zero, the onAnimate event will be disabled. If greater than zero, specifies how many times emit the event per second. 605 * If less than zero, the event will be emitted as fast as possible. 606 * 607 * @type number 608 * 609 * @default SpiderGL.UserInterface.CanvasHandler.DEFAULT_ANIMATE_RATE 610 */ 611 get animateRate() { 612 return this._animateRate; 613 }, 614 615 set animateRate(r) { 616 r = SpiderGL.Utility.getDefaultValue(r, SpiderGL.UserInterface.CanvasHandler.DEFAULT_ANIMATE_RATE); 617 if (this._animateRate === r) return; 618 619 this._fastAnimate = false; 620 this._animateMS = -1; 621 622 this._animateTime = Date.now(); 623 this._animatePrevTime = this._animateTime; 624 this._animateDeltaTime = 0; 625 626 if (this._animateID) { 627 clearInterval(this._animateID); 628 this._animateID = null; 629 } 630 631 this._animateRate = r; 632 633 if (r > 0) { 634 this._animateMS = SpiderGL.Math.floor(1000 / r); 635 if (this._animateWithTimeout) { 636 setTimeout(this._animateEventHandler, this._animateMS); 637 } 638 else { 639 this._animateID = setInterval(this._animateEventHandler, this._animateMS); 640 } 641 } 642 else if (r < 0) { 643 this._fastAnimate = true; 644 window.postMessage(SpiderGL.UserInterface.CanvasHandler._FAST_ANIMATE_MESSAGE_NAME, "*"); 645 } 646 }, 647 648 /** 649 * Gets the number of draw events occurred in the last second. 650 * 651 * @type number 652 * 653 * @readonly 654 */ 655 get framesPerSecond() { 656 return this._fps; 657 }, 658 659 /** 660 * Gets/Sets if the key repeat must be ignored. 661 * 662 * @type bool 663 * 664 * @default SpiderGL.UserInterface.CanvasHandler.DEFAULT_IGNORE_KEY_REPEAT 665 */ 666 get ignoreKeyRepeat() { 667 return this._ignoreKeyRepeat; 668 }, 669 670 set ignoreKeyRepeat(on) { 671 this._ignoreKeyRepeat = SpiderGL.Utility.getDefaultValue(on, SpiderGL.UserInterface.CanvasHandler.DEFAULT_IGNORE_KEY_REPEAT); 672 }, 673 674 /** 675 * Tests if a key is pressed. 676 * 677 * @param {string|number} key The key to test. 678 * 679 * @returns {bool} True if the key is pressed, false otherwise. 680 */ 681 isKeyDown : function (key) { 682 if (key.toUpperCase) { 683 key = key.toUpperCase(); 684 } 685 return this._keysDown[key]; 686 }, 687 688 /** 689 * Tests if a mouse button is pressed. 690 * 691 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 692 * 693 * @returns {bool} True if the mouse button is pressed, false otherwise. 694 */ 695 isMouseButtonDown : function (btn) { 696 return this._mouseButtonsDown[btn]; 697 }, 698 699 /** 700 * Tests if a dragging (mouse move + mouse button down) operation is active. 701 * 702 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 703 * 704 * @returns {bool} True if the dragging operation is active with the specified mouse button, false otherwise. 705 */ 706 isDragging : function (btn) { 707 return this._dragging[btn]; 708 }, 709 710 /** 711 * Gets the cursor x position when dragging has started. 712 * 713 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 714 * 715 * @returns {number} The cursor x position, relative to the canvas lower left corner, when the dragging has started. 716 */ 717 dragStartX : function (btn) { 718 return this._dragStartPos[btn][0]; 719 }, 720 721 /** 722 * Gets the cursor y position when dragging has started. 723 * 724 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 725 * 726 * @returns {number} The cursor y position, relative to the canvas lower left corner, when the dragging has started. 727 */ 728 dragStartY : function (btn) { 729 return this._dragStartPos[btn][1]; 730 }, 731 732 /** 733 * Gets the cursor x position when dragging has finished. 734 * 735 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 736 * 737 * @returns {number} The cursor x position, relative to the canvas lower left corner, when the dragging has finished. 738 */ 739 dragEndX : function (btn) { 740 return this._dragEndPos[btn][0]; 741 }, 742 743 /** 744 * Gets the cursor y position when dragging has finished. 745 * 746 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 747 * 748 * @returns {number} The cursor y position, relative to the canvas lower left corner, when the dragging has finished. 749 */ 750 dragEndY : function (btn) { 751 return this._dragEndPos[btn][1]; 752 }, 753 754 /** 755 * If dragging is ongoing, gets the difference between the current cursor x position and the cursor x position at dragging start. 756 * 757 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 758 * 759 * @returns {number} The difference between the current cursor x position and the cursor x position at dragging start. 760 */ 761 dragDeltaX : function (btn) { 762 return this._dragDeltaPos[btn][0]; 763 }, 764 765 /** 766 * If dragging is ongoing, gets the difference between the current cursor y position and the cursor x position at dragging start. 767 * 768 * @param {number} btn The button to test (0 = left, 1 = right, 2 = middle). 769 * 770 * @returns {number} The difference between the current cursor y position and the cursor y position at dragging start. 771 */ 772 dragDeltaY : function (btn) { 773 return this._dragDeltaPos[btn][1]; 774 }, 775 776 /** 777 * Gets the cursor x position, relative to the canvas lower left corner. 778 * 779 * @type number 780 */ 781 get cursorX() { 782 return this._cursorPos[0]; 783 }, 784 785 /** 786 * Gets the cursor y position, relative to the canvas lower left corner. 787 * 788 * @type number 789 */ 790 get cursorY() { 791 return this._cursorPos[1]; 792 }, 793 794 /** 795 * Gets the previous cursor x position, relative to the canvas lower left corner. 796 * 797 * @type number 798 */ 799 get cursorPrevX() { 800 return this._cursorPrevPos[0]; 801 }, 802 803 /** 804 * Gets the previous cursor y position, relative to the canvas lower left corner. 805 * 806 * @type number 807 */ 808 get cursorPrevY() { 809 return this._cursorPrevPos[1]; 810 }, 811 812 /** 813 * Gets the difference between the current and the previous cursor x position, relative to the canvas lower left corner. 814 * 815 * @type number 816 */ 817 get cursorDeltaX() { 818 return this._cursorDeltaPos[0]; 819 }, 820 821 /** 822 * Gets the difference between the current and the previous cursor y position, relative to the canvas lower left corner. 823 * 824 * @type number 825 */ 826 get cursorDeltaY() { 827 return this._cursorDeltaPos[1]; 828 }, 829 830 /** 831 * Calls immediately the onDraw event handler. 832 */ 833 draw : function () { 834 this._onDraw(); 835 } 836 }; 837 838 SpiderGL.Type.extend(SpiderGL.UserInterface.CanvasHandler, SpiderGL.Core.ObjectBase); 839 840 /** 841 * Sets up a WebGL context and canvas event handling. 842 * The WebGLRenderingContext is created and hijacked using {@link SpiderGL.WebGL.Context.getHijacked}. 843 * A {@link SpiderGL.UserInterface.CanvasHandler} is created to handle the canvas events and dispatch them to the provided handler. 844 * The canvas handler will be installed in the handler object as a named property. 845 * 846 * @param {HTMLCanvasElement|string} canvas The canvas used for rendering and from which event will be received. 847 * @param {object} handler The event handler. 848 * @param {function()} [handler.onInitialize] onInitialize event handler. 849 * @param {function()} [handler.onTerminate] onTerminate event handler. 850 * @param {function(keyCode, event)} [handler.onKeyUp] onKeyUp event handler. 851 * @param {function(keyCode, event)} [handler.onKeyDown] onKeyDown event handler. 852 * @param {function(keyCode, event)} [handler.onKeyPress] onKeyPress event handler. 853 * @param {function(button, cursorX, cursorY, event)} [handler.onMouseButtonDown] onMouseButtonDown event handler. 854 * @param {function(button, cursorX, cursorY, event)} [handler.onMouseButtonUp] onMouseButtonUp event handler. 855 * @param {function(cursorX, cursorY, event)} [handler.onMouseMove] onMouseMove event handler. 856 * @param {function(wheelDelta, cursorX, cursorY, event)} [handler.onMouseWheel] onMouseWheel event handler. 857 * @param {function(button, cursorX, cursorY, event)} [handler.onClick] onClick event handler. 858 * @param {function(button, cursorX, cursorY, event)} [handler.onDoubleClick] onDoubleClick event handler. 859 * @param {function(button, cursorX, cursorY)} [handler.onDragStart] onDragStart event handler. 860 * @param {function(button, cursorX, cursorY)} [handler.onDragEnd] onDragEnd event handler. 861 * @param {function(button, cursorX, cursorY)} [handler.onDrag] onDrag event handler. 862 * @param {function(canvasWidth, canvasHeight)} [handler.onResize] onResize event handler. 863 * @param {function(deltaTimeSecs)} [handler.onAnimate] onAnimate event handler. 864 * @param {function()} [handler.onDraw] onDraw event handler. 865 * @param {object} options Optional parameters (see {@link SpiderGL.UserInterface.CanvasHandler}). 866 * @param {string} [options.uiName=SpiderGL.UserInterface.CanvasHandler.DEFAULT_PROPERTY_NAME] The name of the property to install in the handler object for accessing the canvas handler. 867 * 868 * @see SpiderGL.UserInterface.handleCanvasOnLoad 869 * @see SpiderGL.UserInterface.CanvasHandler 870 */ 871 SpiderGL.UserInterface.handleCanvas = function (canvas, handler, options) { 872 if (!canvas || !handler) return false; 873 874 options = options || { }; 875 876 var gl = SpiderGL.WebGL.Context.getHijacked(canvas, options); 877 if (!gl) return false; 878 879 var ui = new SpiderGL.UserInterface.CanvasHandler(gl, handler, options); 880 if (!ui) return false; 881 882 var uiName = SpiderGL.Utility.getDefaultValue(options.uiName, SpiderGL.UserInterface.CanvasHandler.DEFAULT_PROPERTY_NAME); 883 handler[uiName] = ui; 884 ui._firstNotify(); 885 886 return true; 887 } 888 889 /** 890 * Sets up a WebGL context and canvas event handling after window loading. 891 * When the window fires the onload event, {@link SpiderGL.UserInterface.handleCanvas} is called. 892 * 893 * @param {HTMLCanvasElement|string} canvas The canvas used for rendering and from which event will be received. 894 * @param {object} handler The event handler (see {@link SpiderGL.UserInterface.handleCanvas}). 895 * @param {object} options Optional parameters (see {@link SpiderGL.UserInterface.handleCanvas}). 896 * 897 * @see SpiderGL.UserInterface.handleCanvas 898 */ 899 SpiderGL.UserInterface.handleCanvasOnLoad = function (canvas, handler, options) { 900 if (!canvas || !handler) return false; 901 902 options = options || { }; 903 var onLoad = SpiderGL.Utility.getDefaultValue(options.onLoad, null); 904 905 function doHandle() { 906 SpiderGL.UserInterface.handleCanvas(canvas, handler, options); 907 if (onLoad) { onLoad(); } 908 } 909 910 window.addEventListener("load", doHandle, false); 911 return true; 912 } 913 914