1 /** 2 * @namespace JawsJS core functions. 3 * 4 * Jaws, a HTML5 canvas/javascript 2D game development framework 5 * 6 * Homepage: http://jawsjs.com/ 7 * Source: http://github.com/ippa/jaws/ 8 * Documentation: http://jawsjs.com/docs/ 9 * 10 * Works with: Chrome 6.0+, Firefox 3.6+, 4+, IE 9+ 11 * License: LGPL - http://www.gnu.org/licenses/lgpl.html 12 * 13 * Jaws uses the "module pattern". 14 * Adds 1 global, <b>jaws</b>, so plays nice with all other JS libs. 15 * 16 * Formating guide: 17 * jaws.oneFunction() 18 * jaws.one_variable = 1 19 * new jaws.OneConstructor 20 * 21 * @property {int} mouse_x Mouse X position with respect to the canvas-element 22 * @property {int} mouse_y Mouse Y position with respect to the canvas-element 23 * @property {canvas} canvas The detected/created canvas-element used for the game 24 * @property {context} context The detected/created canvas 2D-context, used for all draw-operations 25 * @property {int} width Width of the canvas-element 26 * @property {int} height Height of the canvas-element 27 */ 28 var jaws = (function(jaws) { 29 30 var title; 31 var log_tag; 32 33 /* 34 * Placeholders for constructors in extras-dir. We define the constructors here to be able to give ppl better error-msgs. 35 * When the correct from extras-dir is included, these will be overwritten. 36 */ 37 jaws.Parallax = function() { jaws.log.error("To use jaws.Parallax() you need to include src/extras/parallax.js") } 38 jaws.SpriteList = function() { jaws.log.error("To use SpriteList() you need to include src/extras/sprite_list.js") } 39 jaws.TileMap = function() { jaws.log.error("To use TileMap() you need to include src/extras/tile_map.js") } 40 jaws.PixelMap = function() { jaws.log.error("To use PixelMap() you need to include src/extras/pixel_map.js") } 41 jaws.QuadTree = function() { jaws.log.error("To use QuadTree() you need to include src/extras/quadtree.js") } 42 jaws.Audio = function() { jaws.log.error("To use jaws.Audio() you need to include src/extras/audio.js") } 43 44 /** 45 * Returns or sets contents of title's innerHTML 46 * @private 47 * @param {type} value The new value to set the innerHTML of title 48 * @returns {string} The innerHTML of title 49 */ 50 jaws.title = function(value) { 51 52 if (!jaws.isString(value)) { 53 jaws.log.error("jaws.title: Passed in value is not a String."); 54 return; 55 } 56 57 if (value) { 58 return (title.innerHTML = value); 59 } 60 return title.innerHTML; 61 }; 62 63 /** 64 * Unpacks Jaws core-constructors into the global namespace. 65 * If a global property is already taken, a warning will be written to jaws log. 66 */ 67 jaws.unpack = function() { 68 var make_global = ["Sprite", "SpriteList", "Animation", "Viewport", "SpriteSheet", "Parallax", "TileMap", "pressed", "QuadTree"]; 69 70 make_global.forEach(function(item) { 71 if (window[item]) { 72 jaws.log.warn("jaws.unpack: " + item + " already exists in global namespace."); 73 } 74 else { 75 window[item] = jaws[item]; 76 } 77 }); 78 }; 79 80 /** 81 * Writes messages to either log_tag (if set) or console.log (if available) 82 * @param {string} msg The string to write 83 * @param {boolean} append If messages should be appended or not 84 */ 85 jaws.log = function(msg, append) { 86 if (!jaws.isString(msg)) { 87 msg = JSON.stringify(msg); 88 } 89 90 if (jaws.log.on) { 91 if (log_tag && jaws.log.use_log_element) { 92 if (append) { 93 log_tag.innerHTML += msg + "<br />"; 94 } 95 else { 96 log_tag.innerHTML = msg; 97 } 98 } 99 if (console.log && jaws.log.use_console) { 100 console.log("JawsJS: ", msg); 101 } 102 } 103 }; 104 105 /** 106 * If logging should take place or not 107 * @type {boolean} 108 */ 109 jaws.log.on = true; 110 111 /** 112 * If console.log should be used during log writing 113 * @type {boolean} 114 */ 115 jaws.log.use_console = false; 116 117 /** 118 * If log_tag should be used during log writing 119 * @type {boolean} 120 */ 121 jaws.log.use_log_element = true; 122 123 /** 124 * Write messages to console.warn (if it exists) or append current log 125 * @param {string|object} msg String or object to record 126 * @see jaws.log 127 */ 128 jaws.log.warn = function(msg) { 129 if (console.warn && jaws.log.use_console && jaws.log.on) { 130 console.warn(msg); 131 } else { 132 jaws.log("[WARNING]: " + JSON.stringify(msg), true); 133 } 134 }; 135 136 /** 137 * Write messages to console.error (if it exists) or append current log 138 * @param {string|object} msg String or object to record 139 * @see jaws.log 140 */ 141 jaws.log.error = function(msg) { 142 if (console.error && jaws.log.use_console && jaws.log.on) { 143 console.error(msg); 144 } else { 145 jaws.log("[ERROR]: " + JSON.stringify(msg), true); 146 } 147 }; 148 149 /** 150 * Write messages to console.info (if it exists) or append current log 151 * @param {string|object} msg String or object to record 152 * @see jaws.log 153 */ 154 jaws.log.info = function(msg) { 155 if (console.info && jaws.log.use_console && jaws.log.on) { 156 console.info(msg); 157 } else { 158 jaws.log("[INFO]: " + JSON.stringify(msg), true); 159 } 160 }; 161 162 /** 163 * Write messages to console.debug (if it exists) or append current log 164 * @param {string|object} msg String or object to record 165 * @see jaws.log 166 */ 167 jaws.log.debug = function(msg) { 168 if (console.debug && jaws.log.use_console && jaws.log.on) { 169 console.debug(msg); 170 } else { 171 jaws.log("[DEBUG]: " + JSON.stringify(msg), true); 172 } 173 }; 174 175 /** 176 * Clears the contents of log_tag element (if set) and console.log (if set) 177 */ 178 jaws.log.clear = function() { 179 if (log_tag) { 180 log_tag.innerHTML = ""; 181 } 182 if (console.clear) { 183 console.clear(); 184 } 185 }; 186 187 /** 188 * Initalizes jaws{canvas, context, dom, width, height} 189 * @private 190 * @param {object} options Object-literal of constructor properties 191 * @see jaws.url_parameters() 192 */ 193 jaws.init = function(options) { 194 195 /* Find <title> tag */ 196 title = document.getElementsByTagName('title')[0]; 197 jaws.url_parameters = jaws.getUrlParameters(); 198 199 jaws.canvas = document.getElementsByTagName('canvas')[0]; 200 if (!jaws.canvas) { 201 jaws.dom = document.getElementById("canvas"); 202 } 203 204 // Ordinary <canvas>, get context 205 if (jaws.canvas) { 206 jaws.context = jaws.canvas.getContext('2d'); 207 } 208 else if (jaws.dom) { 209 jaws.dom.style.position = "relative"; 210 } 211 else { 212 jaws.canvas = document.createElement("canvas"); 213 jaws.canvas.width = options.width; 214 jaws.canvas.height = options.height; 215 jaws.context = jaws.canvas.getContext('2d'); 216 document.body.appendChild(jaws.canvas); 217 } 218 219 /* 220 * If debug=1 parameter is present in the URL, let's either find <div id="jaws-log"> or create the tag. 221 * jaws.log(message) will use this div for debug/info output to the gamer or developer 222 * 223 */ 224 log_tag = document.getElementById('jaws-log'); 225 if (jaws.url_parameters["debug"]) { 226 if (!log_tag) { 227 log_tag = document.createElement("div"); 228 log_tag.id = "jaws-log"; 229 log_tag.style.cssText = "overflow: auto; color: #aaaaaa; width: 300px; height: 150px; margin: 40px auto 0px auto; padding: 5px; border: #444444 1px solid; clear: both; font: 10px verdana; text-align: left;"; 230 document.body.appendChild(log_tag); 231 } 232 } 233 234 235 if(jaws.url_parameters["bust_cache"]) { 236 jaws.log.info("Busting cache when loading assets") 237 jaws.assets.bust_cache = true; 238 } 239 240 /* Let's scale sprites retro-style by default */ 241 if (jaws.context) 242 jaws.useCrispScaling(); 243 244 jaws.width = jaws.canvas ? jaws.canvas.width : jaws.dom.offsetWidth; 245 jaws.height = jaws.canvas ? jaws.canvas.height : jaws.dom.offsetHeight; 246 247 jaws.mouse_x = 0; 248 jaws.mouse_y = 0; 249 window.addEventListener("mousemove", saveMousePosition); 250 }; 251 252 /** 253 * Use 'retro' crisp scaling when drawing sprites through the canvas API, this is the default 254 */ 255 jaws.useCrispScaling = function() { 256 jaws.context.imageSmoothingEnabled = false; 257 jaws.context.webkitImageSmoothingEnabled = false; 258 jaws.context.mozImageSmoothingEnabled = false; 259 }; 260 261 /** 262 * Use smooth antialiased scaling when drawing sprites through the canvas API 263 */ 264 jaws.useSmoothScaling = function() { 265 jaws.context.imageSmoothingEnabled = true; 266 jaws.context.webkitImageSmoothingEnabled = true; 267 jaws.context.mozImageSmoothingEnabled = true; 268 }; 269 270 /** 271 * Keeps updated mouse coordinates in jaws.mouse_x and jaws.mouse_y 272 * This is called each time event "mousemove" triggers. 273 * @private 274 * @param {EventObject} e The EventObject populated by the calling event 275 */ 276 function saveMousePosition(e) { 277 jaws.mouse_x = (e.pageX || e.clientX); 278 jaws.mouse_y = (e.pageY || e.clientY); 279 280 var game_area = jaws.canvas ? jaws.canvas : jaws.dom; 281 jaws.mouse_x -= game_area.offsetLeft; 282 jaws.mouse_y -= game_area.offsetTop; 283 } 284 285 /** 286 * 1) Calls jaws.init(), detects or creats a canvas, and sets up the 2D context (jaws.canvas and jaws.context). 287 * 2) Pre-loads all defined assets with jaws.assets.loadAll(). 288 * 3) Creates an instance of game_state and calls setup() on that instance. 289 * 4) Loops calls to update() and draw() with given FPS until game ends or another game state is activated. 290 * @param {function} game_state The game state function to be started 291 * @param {object} options Object-literal of game loop properties 292 * @param {object} game_state_setup_options Object-literal of game state properties and values 293 * @see jaws.init() 294 * @see jaws.setupInput() 295 * @see jaws.assets.loadAll() 296 * @see jaws.switchGameState() 297 * @example 298 * 299 * jaws.start(MyGame) // Start game state Game() with default options 300 * jaws.start(MyGame, {fps: 30}) // Start game state Game() with options, in this case jaws will run your game with 30 frames per second. 301 * jaws.start(window) // Use global functions setup(), update() and draw() if available. Not the recommended way but useful for testing and mini-games. 302 * 303 */ 304 jaws.start = function(game_state, options, game_state_setup_options) { 305 if (!options) options = {}; 306 307 var fps = options.fps || 60; 308 if (options.loading_screen === undefined) options.loading_screen = true; 309 if (!options.width) options.width = 500; 310 if (!options.height) options.height = 300; 311 312 /* Takes care of finding/creating canvas-element and debug-div */ 313 jaws.init(options); 314 315 if (!jaws.isFunction(game_state) && !jaws.isObject(game_state)) { 316 jaws.log.error("jaws.start: Passed in GameState is niether function or object"); 317 return; 318 } 319 if (!jaws.isObject(game_state_setup_options) && game_state_setup_options !== undefined) { 320 jaws.log.error("jaws.start: The setup options for the game state is not an object."); 321 return; 322 } 323 324 if (options.loading_screen) { 325 jaws.assets.displayProgress(0); 326 } 327 328 jaws.log.info("setupInput()", true); 329 jaws.setupInput(); 330 331 /* Callback for when one single asset has been loaded */ 332 function assetProgress(src, percent_done) { 333 jaws.log.info(percent_done + "%: " + src, true); 334 if (options.loading_screen) { 335 jaws.assets.displayProgress(percent_done); 336 } 337 } 338 339 /* Callback for when an asset can't be loaded*/ 340 function assetError(src, percent_done) { 341 jaws.log.info(percent_done + "%: Error loading asset " + src, true); 342 } 343 344 /* Callback for when all assets are loaded */ 345 function assetsLoaded() { 346 jaws.log.info("all assets loaded", true); 347 jaws.switchGameState(game_state || window, {fps: fps}, game_state_setup_options); 348 } 349 350 jaws.log.info("assets.loadAll()", true); 351 if (jaws.assets.length() > 0) { 352 jaws.assets.loadAll({onprogress: assetProgress, onerror: assetError, onload: assetsLoaded}); 353 } 354 else { 355 assetsLoaded(); 356 } 357 }; 358 359 /** 360 * Switchs to a new active game state and saves previous game state in jaws.previous_game_state 361 * @param {function} game_state The game state function to start 362 * @param {object} options The object-literal properties to pass to the new game loop 363 * @param {object} game_state_setup_options The object-literal properties to pass to starting game state 364 * @example 365 * 366 * function MenuState() { 367 * this.setup = function() { ... } 368 * this.draw = function() { ... } 369 * this.update = function() { 370 * if(pressed("enter")) jaws.switchGameState(GameState); // Start game when Enter is pressed 371 * } 372 * } 373 * 374 * function GameState() { 375 * this.setup = function() { ... } 376 * this.update = function() { ... } 377 * this.draw = function() { ... } 378 * } 379 * 380 * jaws.start(MenuState) 381 * 382 */ 383 jaws.switchGameState = function(game_state, options, game_state_setup_options) { 384 if(options === undefined) options = {}; 385 386 if(jaws.isFunction(game_state)) { 387 game_state = new game_state; 388 } 389 if(!jaws.isObject(game_state)) { 390 jaws.log.error("jaws.switchGameState: Passed in GameState should be a Function or an Object."); 391 return; 392 } 393 394 var fps = (options && options.fps) || (jaws.game_loop && jaws.game_loop.fps) || 60; 395 var setup = options.setup 396 397 jaws.game_loop && jaws.game_loop.stop(); 398 jaws.clearKeyCallbacks(); 399 400 jaws.previous_game_state = jaws.game_state; 401 jaws.game_state = game_state; 402 jaws.game_loop = new jaws.GameLoop(game_state, {fps: fps, setup: setup}, game_state_setup_options); 403 jaws.game_loop.start(); 404 }; 405 406 /** 407 * Creates a new HTMLCanvasElement from a HTMLImageElement 408 * @param {HTMLImageElement} image The HTMLImageElement to convert to a HTMLCanvasElement 409 * @returns {HTMLCanvasElement} A HTMLCanvasElement with drawn HTMLImageElement content 410 */ 411 jaws.imageToCanvas = function(image) { 412 if (jaws.isCanvas(image)) return image; 413 414 if (!jaws.isImage(image)) { 415 jaws.log.error("jaws.imageToCanvas: Passed in object is not an Image."); 416 return; 417 } 418 419 var canvas = document.createElement("canvas"); 420 canvas.src = image.src; 421 canvas.width = image.width; 422 canvas.height = image.height; 423 424 var context = canvas.getContext("2d"); 425 context.drawImage(image, 0, 0, image.width, image.height); 426 return canvas; 427 }; 428 429 /** 430 * Returns object as an array 431 * @param {object} obj An array or object 432 * @returns {array} Either an array or the object as an array 433 * @example 434 * 435 * jaws.forceArray(1) // --> [1] 436 * jaws.forceArray([1,2]) // --> [1,2] 437 */ 438 jaws.forceArray = function(obj) { 439 return Array.isArray(obj) ? obj : [obj]; 440 }; 441 442 /** 443 * Clears screen (the canvas-element) through context.clearRect() 444 */ 445 jaws.clear = function() { 446 jaws.context.clearRect(0, 0, jaws.width, jaws.height); 447 }; 448 449 /** Fills the screen with given fill_style */ 450 jaws.fill = function(fill_style) { 451 jaws.context.fillStyle = fill_style; 452 jaws.context.fillRect(0, 0, jaws.width, jaws.height); 453 }; 454 455 456 /** 457 * calls draw() on everything you throw on it. Give it arrays, argumentlists, arrays of arrays. 458 * 459 */ 460 jaws.draw = function() { 461 var list = arguments; 462 if(list.length == 1 && jaws.isArray(list[0])) list = list[0]; 463 for(var i=0; i < list.length; i++) { 464 if(jaws.isArray(list[i])) jaws.draw(list[i]); 465 else if(list[i].draw) list[i].draw(); 466 } 467 } 468 469 /** 470 * calls update() on everything you throw on it. Give it arrays, argumentlists, arrays of arrays. 471 * 472 */ 473 jaws.update = function() { 474 var list = arguments; 475 if(list.length == 1 && jaws.isArray(list[0])) list = list[0]; 476 for(var i=0; i < list.length; i++) { 477 if(jaws.isArray(list[i])) jaws.update(list[i]); 478 else if(list[i].update) list[i].update(); 479 } 480 } 481 482 /** 483 * Tests if object is an image or not 484 * @param {object} obj An Image or image-like object 485 * @returns {boolean} If object's prototype is "HTMLImageElement" 486 */ 487 jaws.isImage = function(obj) { 488 return Object.prototype.toString.call(obj) === "[object HTMLImageElement]"; 489 }; 490 491 /** 492 * Tests if object is a Canvas object 493 * @param {type} obj A canvas or canvas-like object 494 * @returns {boolean} If object's prototype is "HTMLCanvasElement" 495 */ 496 jaws.isCanvas = function(obj) { 497 return Object.prototype.toString.call(obj) === "[object HTMLCanvasElement]"; 498 }; 499 500 /** 501 * Tests if an object is either a canvas or an image object 502 * @param {object} obj A canvas or canva-like object 503 * @returns {boolean} If object isImage or isCanvas 504 */ 505 jaws.isDrawable = function(obj) { 506 return jaws.isImage(obj) || jaws.isCanvas(obj); 507 }; 508 509 /** 510 * Tests if an object is a string or not 511 * @param {object} obj A string or string-like object 512 * @returns {boolean} The result of typeof and constructor testing 513 */ 514 jaws.isString = function(obj) { 515 return typeof obj === "string" || (typeof obj === "object" && obj.constructor === String); 516 }; 517 518 /** 519 * Tests if an object is a number or not 520 * @param {number} n A number or number-like value 521 * @returns {boolean} If n passed isNaN() and isFinite() 522 */ 523 jaws.isNumber = function(n) { 524 return !isNaN(parseFloat(n)) && isFinite(n); 525 }; 526 527 /** 528 * Tests if an object is an Array or not 529 * @param {object} obj An array or array-like object 530 * @returns {boolean} If object's constructor is "Array" 531 */ 532 jaws.isArray = function(obj) { 533 if (!obj) 534 return false; 535 return !(obj.constructor.toString().indexOf("Array") === -1); 536 }; 537 538 /** 539 * Tests if an object is an Object or not 540 * @param {object} value An object or object-like enitity 541 * @returns {boolean} If object is not null and typeof 'object' 542 */ 543 jaws.isObject = function(value) { 544 return value !== null && typeof value === 'object'; 545 }; 546 547 /** 548 * Tests if an object is a function or not 549 * @param {object} obj A function or function-like object 550 * @returns {boolean} If the prototype of the object is "Function" 551 */ 552 jaws.isFunction = function(obj) { 553 return (Object.prototype.toString.call(obj) === "[object Function]"); 554 }; 555 556 /** 557 * Tests if an object is a regular expression or not 558 * @param {object} obj A /regexp/-object 559 * @returns {boolean} If the object is an instance of RegExp 560 */ 561 jaws.isRegExp = function(obj) { 562 return (obj instanceof RegExp); 563 }; 564 565 566 /** 567 * Tests if an object is within drawing canvas (jaws.width and jaws.height) 568 * @param {object} item An object with both x and y properties 569 * @returns {boolean} If the item's x and y are less than 0 or more than jaws.width or jaws.height 570 */ 571 jaws.isOutsideCanvas = function(item) { 572 if (item.x && item.y) { 573 return (item.x < 0 || item.y < 0 || item.x > jaws.width || item.y > jaws.height); 574 } 575 }; 576 577 /** 578 * Sets x and y properties to 0 (if less than), or jaws.width or jaws.height (if greater than) 579 * @param {object} item An object with x and y properties 580 */ 581 jaws.forceInsideCanvas = function(item) { 582 if (item.x && item.y) { 583 if (item.x < 0) { 584 item.x = 0; 585 } 586 if (item.x > jaws.width) { 587 item.x = jaws.width; 588 } 589 if (item.y < 0) { 590 item.y = 0; 591 } 592 if (item.y > jaws.height) { 593 item.y = jaws.height; 594 } 595 } 596 }; 597 598 /** 599 * Parses current window.location for URL parameters and values 600 * @returns {array} Hash of url-parameters and their values 601 * @example 602 * // Given the current URL is <b>http://test.com/?debug=1&foo=bar</b> 603 * jaws.getUrlParameters() // --> {debug: 1, foo: bar} 604 */ 605 jaws.getUrlParameters = function() { 606 var vars = [], hash; 607 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&'); 608 for (var i = 0; i < hashes.length; i++) { 609 hash = hashes[i].split('='); 610 vars.push(hash[0]); 611 vars[hash[0]] = hash[1]; 612 } 613 return vars; 614 }; 615 616 /** 617 * Compares an object's default properties against those sent to its constructor 618 * @param {object} object The object to compare and assign new values 619 * @param {object} options Object-literal of constructor properties and new values 620 * @param {object} defaults Object-literal of properties and their default values 621 */ 622 jaws.parseOptions = function(object, options, defaults) { 623 object["options"] = options; 624 625 for (var option in options) { 626 if (defaults[option] === undefined) { 627 jaws.log.warn("jaws.parseOptions: Unsupported property " + option + "for " + object.constructor); 628 } 629 } 630 for (var option in defaults) { 631 if( jaws.isFunction(defaults[option]) ) defaults[option] = defaults[option](); 632 object[option] = (options[option] !== undefined) ? options[option] : jaws.clone(defaults[option]); 633 } 634 }; 635 636 /** 637 * Returns a shallow copy of an array or object 638 * @param {array|object} value The array or object to clone 639 * @returns {array|object} A copy of an array of object 640 */ 641 jaws.clone = function(value) { 642 if (jaws.isArray(value)) 643 return value.slice(0); 644 if (jaws.isObject(value)) 645 return JSON.parse(JSON.stringify(value)); 646 return value; 647 }; 648 649 /* 650 * Converts image to canvas 2D context. Then you can draw on it :). 651 */ 652 jaws.imageToCanvasContext = function(image) { 653 var canvas = document.createElement("canvas") 654 canvas.width = image.width 655 canvas.height = image.height 656 657 var context = canvas.getContext("2d") 658 if(jaws.context) { 659 context.imageSmoothingEnabled = jaws.context.mozImageSmoothingEnabled; 660 context.webkitImageSmoothingEnabled = jaws.context.mozImageSmoothingEnabled; 661 context.mozImageSmoothingEnabled = jaws.context.mozImageSmoothingEnabled; 662 } 663 664 context.drawImage(image, 0, 0, canvas.width, canvas.height) 665 return context 666 } 667 668 /** 669 * scale 'image' by factor 'factor'. 670 * Scaling is done using nearest-neighbor ( retro-blocky-style ). 671 * Returns a canvas. 672 */ 673 jaws.retroScaleImage = function(image, factor) { 674 var canvas = jaws.isImage(image) ? jaws.imageToCanvas(image) : image 675 var context = canvas.getContext("2d") 676 var data = context.getImageData(0,0,canvas.width,canvas.height).data 677 678 // Create new canvas to return 679 var canvas2 = document.createElement("canvas") 680 canvas2.width = image.width * factor 681 canvas2.height = image.height * factor 682 var context2 = canvas2.getContext("2d") 683 var to_data = context2.createImageData(canvas2.width, canvas2.height) 684 685 var w2 = to_data.width 686 var h2 = to_data.height 687 for (var y=0; y < h2; y += 1) { 688 var y2 = Math.floor(y / factor) 689 var y_as_x = y * to_data.width 690 var y2_as_x = y2 * image.width 691 692 for (var x=0; x < w2; x += 1) { 693 var x2 = Math.floor(x / factor) 694 var y_dst = (y_as_x + x) * 4 695 var y_src = (y2_as_x + x2) * 4 696 697 to_data.data[y_dst] = data[y_src]; 698 to_data.data[y_dst+1] = data[y_src+1]; 699 to_data.data[y_dst+2] = data[y_src+2]; 700 to_data.data[y_dst+3] = data[y_src+3]; 701 } 702 } 703 704 context2.putImageData(to_data, 0, 0) 705 706 return canvas2 707 } 708 709 return jaws; 710 })(jaws || {}); 711 712 // Support CommonJS require() 713 if(typeof module !== "undefined" && ('exports' in module)) { module.exports = jaws } 714