- M … mute / unmute sound
- enter … restart
- escape … menu
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Bomb.js b/bomberman/frontend/src/main/webapp/js/Bomb.js
deleted file mode 100644
index c820b0dd6e..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Bomb.js
+++ /dev/null
@@ -1,71 +0,0 @@
-Bomb = Entity.extend({
- /**
- * Entity position on map grid
- */
- position: {},
-
- /**
- * How far the fire reaches when bomb explodes
- */
- strength: 1,
-
- /**
- * Bitmap dimensions
- */
- size: {
- w: 28,
- h: 28
- },
-
- /**
- * Bitmap animation
- */
- bmp: null,
-
- /**
- * Timer in frames
- */
- timer: 0,
-
- /**
- * Max timer value in seconds
- */
- timerMax: 2,
-
- exploded: false,
-
- fires: [],
-
- explodeListener: null,
-
- init: function(id, position, strength) {
- this.id = id;
- this.strength = strength;
-
- var spriteSheet = new createjs.SpriteSheet({
- images: [gGameEngine.bombImg],
- frames: {
- width: this.size.w,
- height: this.size.h,
- regX: 5,
- regY: 5
- },
- animations: {
- idle: [0, 4, "idle", 0.2]
- }
- });
- this.bmp = new createjs.Sprite(spriteSheet);
- this.bmp.gotoAndPlay('idle');
-
- this.position = position;
- this.bmp.x = position.x;
- this.bmp.y = position.y;
-
- this.fires = [];
- gGameEngine.stage.addChild(this.bmp);
- },
-
- remove: function() {
- gGameEngine.stage.removeChild(this.bmp);
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Bonus.js b/bomberman/frontend/src/main/webapp/js/Bonus.js
deleted file mode 100644
index 4a4c6a1e45..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Bonus.js
+++ /dev/null
@@ -1,24 +0,0 @@
-Bonus = Entity.extend({
- types: ['speed', 'bomb', 'fire'],
-
- type: '',
- position: {},
- bmp: null,
-
- init: function(position, typePosition) {
- this.type = this.types[typePosition];
-
- this.position = position;
-
- this.bmp = new createjs.Bitmap(gGameEngine.bonusesImg);
- var pixels = Utils.convertToBitmapPosition(position);
- this.bmp.x = pixels.x;
- this.bmp.y = pixels.y;
- this.bmp.sourceRect = new createjs.Rectangle(typePosition * 32, 0, 32, 32);
- gGameEngine.stage.addChild(this.bmp);
- },
-
- remove: function() {
- gGameEngine.stage.removeChild(this.bmp);
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Entity.js b/bomberman/frontend/src/main/webapp/js/Entity.js
deleted file mode 100644
index 43f53e4faf..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Entity.js
+++ /dev/null
@@ -1,12 +0,0 @@
-Entity = Class.extend({
- id: null,
-
- init: function() {
- },
-
- update: function() {
- },
-
- remove: function () {
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Fire.js b/bomberman/frontend/src/main/webapp/js/Fire.js
deleted file mode 100644
index 495192fda5..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Fire.js
+++ /dev/null
@@ -1,50 +0,0 @@
-Fire = Entity.extend({
- /**
- * Entity position on map grid
- */
- position: {},
-
- /**
- * Bitmap dimensions
- */
- size: {
- w: 38,
- h: 38
- },
-
- /**
- * Bitmap animation
- */
- bmp: null,
-
- init: function(id, position) {
- this.id = id;
- var spriteSheet = new createjs.SpriteSheet({
- images: [gGameEngine.fireImg],
- frames: { width: this.size.w, height: this.size.h, regX: 0, regY: 0 },
- animations: {
- idle: [0, 5, null, 0.4],
- }
- });
- this.bmp = new createjs.Sprite(spriteSheet);
- this.bmp.gotoAndPlay('idle');
- var that = this;
- this.bmp.addEventListener('animationend', function() {
- that.remove();
- });
-
- this.position = position;
-
- this.bmp.x = position.x + 2;
- this.bmp.y = position.y - 5;
-
- gGameEngine.stage.addChild(this.bmp);
- },
-
- update: function() {
- },
-
- remove: function() {
- gGameEngine.stage.removeChild(this.bmp);
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/GameEngine.js b/bomberman/frontend/src/main/webapp/js/GameEngine.js
deleted file mode 100644
index 163c3c213a..0000000000
--- a/bomberman/frontend/src/main/webapp/js/GameEngine.js
+++ /dev/null
@@ -1,204 +0,0 @@
-GameEngine = Class.extend({
- tileSize: 32,
- tilesX: 17,
- tilesY: 13,
- size: {},
- fps: 60,
- playersCount: 2,
- bonusesPercent: 16,
-
- stage: null,
- menu: null,
- players: [],
- tiles: [],
- bombs: [],
- bonuses: [],
- fires: [],
-
- playerBoyImg: null,
- playerGirlImg: null,
- playerGirl2Img: null,
- tilesImgs: {},
- bombImg: null,
- fireImg: null,
- bonusesImg: null,
-
- playing: false,
- mute: false,
- soundtrackLoaded: false,
- soundtrackPlaying: false,
- soundtrack: null,
-
- serverProxy: null,
-
- init: function() {
- this.size = {
- w: this.tileSize * this.tilesX,
- h: this.tileSize * this.tilesY
- };
- },
-
- load: function() {
- // Init canvas
- this.stage = new createjs.Stage("canvas");
- this.stage.enableMouseOver();
-
- // Load assets
- var queue = new createjs.LoadQueue();
- var that = this;
- queue.addEventListener("complete", function() {
- that.playerBoyImg = queue.getResult("playerBoy");
- that.playerGirlImg = queue.getResult("playerGirl");
- that.playerGirl2Img = queue.getResult("playerGirl2");
- that.tilesImgs.grass = queue.getResult("tile_grass");
- that.tilesImgs.wall = queue.getResult("tile_wall");
- that.tilesImgs.wood = queue.getResult("tile_wood");
- that.bombImg = queue.getResult("bomb");
- that.fireImg = queue.getResult("fire");
- that.bonusesImg = queue.getResult("bonuses");
- that.setup();
- });
- queue.loadManifest([
- {id: "playerBoy", src: "img/george.png"},
- {id: "playerGirl", src: "img/betty.png"},
- {id: "playerGirl2", src: "img/betty2.png"},
- {id: "tile_grass", src: "img/tile_grass.png"},
- {id: "tile_wall", src: "img/tile_wall.png"},
- {id: "tile_wood", src: "img/tile_wood.png"},
- {id: "bomb", src: "img/bomb.png"},
- {id: "fire", src: "img/fire.png"},
- {id: "bonuses", src: "img/bonuses.png"}
- ]);
-
- createjs.Sound.addEventListener("fileload", this.onSoundLoaded);
- createjs.Sound.alternateExtensions = ["mp3"];
- createjs.Sound.registerSound("sound/bomb.ogg", "bomb");
- // createjs.Sound.registerSound("sound/game.ogg", "game");
-
- this.menu = new Menu();
- },
-
- setup: function() {
- if (!gInputEngine.bindings.length) {
- gInputEngine.setup();
- }
-
- this.bombs = [];
- this.tiles = [];
- this.bonuses = [];
-
- this.serverProxy = new ServerProxy();
-
- // Toggle sound
- gInputEngine.subscribe('mute', this.toggleSound);
-
- // Start loop
- if (!createjs.Ticker.hasEventListener('tick')) {
- createjs.Ticker.addEventListener('tick', gGameEngine.update);
- createjs.Ticker.setFPS(this.fps);
- }
-
- if (gGameEngine.playersCount > 0) {
- if (this.soundtrackLoaded) {
- this.playSoundtrack();
- }
- }
-
- if (!this.playing) {
- this.menu.show();
- }
- },
-
- onSoundLoaded: function(sound) {
- if (sound.id == 'game') {
- gGameEngine.soundtrackLoaded = true;
- if (gGameEngine.playersCount > 0) {
- gGameEngine.playSoundtrack();
- }
- }
- },
-
- playSoundtrack: function() {
- if (!gGameEngine.soundtrackPlaying) {
- gGameEngine.soundtrack = createjs.Sound.play("game", "none", 0, 0, -1);
- gGameEngine.soundtrack.setVolume(1);
- gGameEngine.soundtrackPlaying = true;
- }
- },
-
- update: function() {
- // Player
- for (var i = 0; i < gGameEngine.players.length; i++) {
- var player = gGameEngine.players[i];
- player.update();
- }
-
- // Bombs
- for (var i = 0; i < gGameEngine.bombs.length; i++) {
- var bomb = gGameEngine.bombs[i];
- bomb.update();
- }
-
- // Menu
- gGameEngine.menu.update();
-
- // Stage
- gGameEngine.stage.update();
- },
-
- // gameOver: function(status) {
- // if (gGameEngine.menu.visible) { return; }
- //
- // if (status == 'win') {
- // var winText = "You won!";
- // if (gGameEngine.playersCount > 1) {
- // var winner = gGameEngine.getWinner();
- // winText = winner == 0 ? "Player 1 won!" : "Player 2 won!";
- // }
- // this.menu.show([{text: winText, color: '#669900'}, {text: ' ;D', color: '#99CC00'}]);
- // } else {
- // this.menu.show([{text: 'Game Over', color: '#CC0000'}, {text: ' :(', color: '#FF4444'}]);
- // }
- // },
-
- restart: function() {
- // gInputEngine.removeAllListeners();
- gGameEngine.stage.removeAllChildren();
- gGameEngine.setup();
- this.serverProxy = new ServerProxy();
- },
-
- /**
- * Moves specified child to the front.
- */
- moveToFront: function(child) {
- var children = gGameEngine.stage.getNumChildren();
- gGameEngine.stage.setChildIndex(child, children - 1);
- },
-
- toggleSound: function() {
- if (gGameEngine.mute) {
- gGameEngine.mute = false;
- gGameEngine.soundtrack.resume();
- } else {
- gGameEngine.mute = true;
- gGameEngine.soundtrack.pause();
- }
- },
-
- gc: function(survivors) {
- [this.players, this.tiles, this.bombs, this.bonuses].forEach(function (it) {
- var i = it.length;
- while (i--) {
- if (!survivors.has(it[i].id)) {
- it[i].remove();
- it.splice(i, 1);
- }
- }
- });
-
- }
-
-});
-
-gGameEngine = new GameEngine();
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/InputEngine.js b/bomberman/frontend/src/main/webapp/js/InputEngine.js
deleted file mode 100644
index f9600c9052..0000000000
--- a/bomberman/frontend/src/main/webapp/js/InputEngine.js
+++ /dev/null
@@ -1,132 +0,0 @@
-InputEngine = Class.extend({
-
- // move notification fps
- fps: 60,
-
- /**
- * A dictionary mapping ASCII key codes to string values describing
- * the action we want to take when that key is pressed.
- */
- bindings: {},
-
- /**
- * A dictionary mapping actions that might be taken in our game
- * to a boolean value indicating whether that action is currently being performed.
- */
- actions: {},
-
- possessed: null,
-
- subscribers: [],
-
- init: function() { },
-
- setup: function() {
- this.bind(37, 'left');
- this.bind(38, 'up');
- this.bind(39, 'right');
- this.bind(40, 'down');
-
-
- this.bind(32, 'bomb');
-
- this.bind(13, 'restart');
- this.bind(27, 'escape');
- this.bind(77, 'mute');
-
- // move multiple presses with fps frequency
- this.keyboardController({
- 37 : this.onKeyDown,
- 38 : this.onKeyDown,
- 39 : this.onKeyDown,
- 40 : this.onKeyDown
- }, 1000 / this.fps);
-
- document.addEventListener('keydown', this.onKeyDown);
- document.addEventListener('keyup', this.onKeyUp);
- },
-
- onKeyUp: function(event) {
- var action = gInputEngine.bindings[event.keyCode];
- if (action) {
- gInputEngine.actions[action] = false;
- event.preventDefault();
- }
- return false;
- },
-
- onKeyDown: function(event) {
- var action = gInputEngine.bindings[event.keyCode];
- if (action) {
- gInputEngine.actions[action] = true;
- var subscribers = gInputEngine.subscribers[action];
- if (subscribers) {
- for (var i = 0; i < subscribers.length; i++ ) {
- subscribers[i]()
- }
- }
-
- event.preventDefault();
- }
- return false;
- },
-
- /**
- * The bind function takes an ASCII keycode and a string representing
- * the action to take when that key is pressed.
- */
- bind: function(key, action) {
- this.bindings[key] = action;
- },
-
- subscribe: function (action, callback) {
- this.subscribers[action] = this.subscribers[action] || [];
- this.subscribers[action].push(callback)
- },
-
- // Keyboard input with customisable repeat (set to 0 for no key repeat)
- keyboardController: function(keys, repeat) {
-
- // Lookup of key codes to timer ID, or null for no repeat
- var timers = {};
-
- // When key is pressed and we don't already think it's pressed, call the
- // key action callback and set a timer to generate another one after a delay
- document.onkeydown= function(event) {
- var key = (event || window.event).keyCode;
- if (!(key in keys))
- return true;
- if (!(key in timers)) {
- timers[key] = null;
- keys[key](event);
- if (repeat !== 0)
- var f = function () {
- keys[key](event);
- };
- timers[key]= setInterval(f, repeat);
- }
- return false;
- };
-
- // Cancel timeout and mark key as released on keyup
- document.onkeyup = function(event) {
- var key= (event || window.event).keyCode;
- if (key in timers) {
- if (timers[key] !== null)
- clearInterval(timers[key]);
- delete timers[key];
- }
- };
-
- // When window is unfocused we may not get key events. To prevent this
- // causing a key to 'get stuck down', cancel all held keys
- window.onblur = function() {
- for (key in timers)
- if (timers[key] !== null)
- clearInterval(timers[key]);
- timers= {};
- };
- }
-});
-
-gInputEngine = new InputEngine();
diff --git a/bomberman/frontend/src/main/webapp/js/Menu.js b/bomberman/frontend/src/main/webapp/js/Menu.js
deleted file mode 100644
index 4cdbdea3c1..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Menu.js
+++ /dev/null
@@ -1,106 +0,0 @@
-Menu = Class.extend({
- visible: true,
-
- views: [],
-
- init: function () {
- gGameEngine.playersCount = 0;
-
- this.showLoader();
- },
-
- show: function (text) {
- this.visible = true;
-
- this.draw(text);
- },
-
- hide: function () {
- this.visible = false;
-
- for (var i = 0; i < this.views.length; i++) {
- gGameEngine.stage.removeChild(this.views[i]);
- }
-
- this.views = [];
- },
-
- update: function () {
- if (this.visible) {
- for (var i = 0; i < this.views.length; i++) {
- gGameEngine.moveToFront(this.views[i]);
- }
- }
- },
-
- setHandCursor: function (btn) {
- btn.addEventListener('mouseover', function () {
- document.body.style.cursor = 'pointer';
- });
- btn.addEventListener('mouseout', function () {
- document.body.style.cursor = 'auto';
- });
- },
-
- start: function () {
- this.hide();
-
- gGameEngine.playing = true;
- gGameEngine.serverProxy.getSessionIdFromMatchMaker();
- gGameEngine.restart();
- },
-
- draw: function (text) {
- var that = this;
-
- // semi-transparent black background
- var bgGraphics = new createjs.Graphics().beginFill("rgba(0, 0, 0, 0.5)").drawRect(0, 0, gGameEngine.size.w, gGameEngine.size.h);
- var bg = new createjs.Shape(bgGraphics);
- gGameEngine.stage.addChild(bg);
- this.views.push(bg);
-
-
- // start button
- var startButtonX = gGameEngine.size.w / 2 - 55;
- var startButtonY = gGameEngine.size.h / 2 - 80;
- var startButtonSize = 110;
-
- var singleBgGraphics = new createjs.Graphics().beginFill("rgba(0, 0, 0, 0.5)").drawRect(startButtonX, startButtonY, startButtonSize, startButtonSize);
- var singleBg = new createjs.Shape(singleBgGraphics);
- gGameEngine.stage.addChild(singleBg);
- this.views.push(singleBg);
- this.setHandCursor(singleBg);
- singleBg.addEventListener('click', function () {
- that.start();
- });
-
- var playButton = new createjs.Text("Play", "32px Helvetica", "#ff4444");
- var singleTitleWidth = playButton.getMeasuredWidth();
- var modeTitlesY = startButtonY + startButtonSize - playButton.getMeasuredHeight() - 20;
-
- playButton.x = startButtonX + (startButtonSize - singleTitleWidth) / 2;
- playButton.y = modeTitlesY;
- gGameEngine.stage.addChild(playButton);
- this.views.push(playButton);
-
- var iconsY = startButtonY + 13;
- var singleIcon = new createjs.Bitmap("img/betty.png");
- singleIcon.sourceRect = new createjs.Rectangle(0, 0, 48, 48);
- singleIcon.x = startButtonX + (startButtonSize - 48) / 2;
- singleIcon.y = iconsY;
- gGameEngine.stage.addChild(singleIcon);
- this.views.push(singleIcon);
- },
-
- showLoader: function () {
- var bgGraphics = new createjs.Graphics().beginFill("#000000").drawRect(0, 0, gGameEngine.size.w, gGameEngine.size.h);
- var bg = new createjs.Shape(bgGraphics);
- gGameEngine.stage.addChild(bg);
-
- var loadingText = new createjs.Text("Loading...", "20px Helvetica", "#FFFFFF");
- loadingText.x = gGameEngine.size.w / 2 - loadingText.getMeasuredWidth() / 2;
- loadingText.y = gGameEngine.size.h / 2 - loadingText.getMeasuredHeight() / 2 - 150;
- gGameEngine.stage.addChild(loadingText);
- gGameEngine.stage.update();
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Message.js b/bomberman/frontend/src/main/webapp/js/Message.js
deleted file mode 100644
index 467e2ef8a5..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Message.js
+++ /dev/null
@@ -1,112 +0,0 @@
-Messages = Class.extend({
- handler: {},
-
- init: function () {
- this.handler['Pawn'] = this.handlePawn;
- this.handler['Bomb'] = this.handleBomb;
- this.handler['Wood'] = this.handleTile;
- this.handler['Wall'] = this.handleTile;
- this.handler['Fire'] = this.handleFire;
- },
-
- move: function (direction) {
- var template = {
- topic: "MOVE",
- data: {}
- };
-
- template.data.direction = direction.toUpperCase();
- return JSON.stringify(template);
- },
-
- plantBomb: function () {
- var template = {
- topic: "PLANT_BOMB",
- data: {}
- };
-
- return JSON.stringify(template);
- },
-
-
- handleReplica: function (msg) {
- //var gameObjects = JSON.parse(msg.data).objects
- var gameObjects = msg.data.objects;
- var survivors = new Set();
-
- for (var i = 0; i < gameObjects.length; i++) {
- var obj = gameObjects[i];
- if (gMessages.handler[obj.type] === undefined)
- continue;
-
- survivors.add(obj.id);
- gMessages.handler[obj.type](obj);
- }
- gGameEngine.gc(survivors);
- },
-
- handlePossess: function (msg) {
- gInputEngine.possessed = parseInt(msg.data);
- },
-
- handlePawn: function(obj) {
- var player = gGameEngine.players.find(function (el) {
- return el.id === obj.id;
- });
- var position = Utils.getEntityPosition(obj.position);
-
- if (player) {
- player.bmp.x = position.x;
- player.bmp.y = position.y;
- } else {
- console.log(new Date().getTime() + " handel new player " + obj.id);
- player = new Player(obj.id, position);
- gGameEngine.players.push(player);
- }
- },
-
- handleBomb: function(obj) {
- var bomb = gGameEngine.bombs.find(function (el) {
- return el.id === obj.id;
- });
- var position = Utils.getEntityPosition(obj.position);
-
- if (bomb) {
- bomb.bmp.x = position.x;
- bomb.bmp.y = position.y;
- } else {
- bomb = new Bomb(obj.id, position);
- gGameEngine.bombs.push(bomb);
- }
- },
-
- handleTile: function (obj) {
- var tile = gGameEngine.tiles.find(function (el) {
- return el.id === obj.id;
- });
-
- //var position = Utils.getEntityPosition(Utils.convertToBitmapPosition(obj.position));
- var position = Utils.getEntityPosition(obj.position);
- if (tile) {
- tile.material = obj.type;
- } else {
- tile = new Tile(obj.id, obj.type, position);
- gGameEngine.tiles.push(tile);
- }
- },
-
- handleFire: function (obj) {
- var fire = gGameEngine.fires.find(function (el) {
- return el.id === obj.id;
- });
-
- var position = Utils.getEntityPosition(obj.position);
- if (!fire) {
- fire = new Fire(obj.id, position);
- gGameEngine.fires.push(fire);
- }
- }
-
-});
-
-gMessages = new Messages();
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Player.js b/bomberman/frontend/src/main/webapp/js/Player.js
deleted file mode 100644
index 486a17a8ad..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Player.js
+++ /dev/null
@@ -1,117 +0,0 @@
-Player = Entity.extend({
- /**
- * Bitmap dimensions
- */
- size: {
- w: 48,
- h: 48
- },
-
- /**
- * Bitmap animation
- */
- bmp: null,
-
- alive: true,
-
- bombs: [],
-
- controls: {
- 'up': 'up',
- 'left': 'left',
- 'down': 'down',
- 'right': 'right',
- 'bomb': 'bomb'
- },
-
- /**
- * Bomb that player can escape from even when there is a collision
- */
- escapeBomb: null,
-
- deadTimer: 0,
-
-
-
- init: function(id, position) {
- this.id = id;
-
- var img = gGameEngine.playerGirlImg;
-
- var spriteSheet = new createjs.SpriteSheet({
- images: [img],
- frames: { width: this.size.w, height: this.size.h, regX: 10, regY: 12 },
- animations: {
- idle: [0, 0, 'idle'],
- down: [0, 3, 'down', 0.1],
- left: [4, 7, 'left', 0.1],
- up: [8, 11, 'up', 0.1],
- right: [12, 15, 'right', 0.1],
- dead: [16, 16, 'dead', 0.1]
- }
- });
- this.bmp = new createjs.Sprite(spriteSheet);
-
- this.bmp.x = position.x;
- this.bmp.y = position.y;
-
- gGameEngine.stage.addChild(this.bmp);
-
- this.bombs = [];
- },
-
-
- update: function() {
- if (!this.alive) {
- return;
- }
-
- if (gInputEngine.possessed !== this.id) {
- return;
- }
-
- if (gInputEngine.actions[this.controls.up]) {
- this.animate('up');
- } else if (gInputEngine.actions[this.controls.down]) {
- this.animate('down');
- } else if (gInputEngine.actions[this.controls.left]) {
- this.animate('left');
- } else if (gInputEngine.actions[this.controls.right]) {
- this.animate('right');
- } else {
- this.animate('idle');
- }
- },
-
- /**
- * Changes animation if requested animation is not already current.
- */
- animate: function(animation) {
- if (!this.bmp.currentAnimation || this.bmp.currentAnimation.indexOf(animation) === -1) {
- this.bmp.gotoAndPlay(animation);
- }
- },
-
- die: function() {
- this.alive = false;
-
- this.bmp.gotoAndPlay('dead');
- this.fade();
- },
-
- fade: function() {
- var timer = 0;
- var bmp = this.bmp;
- var fade = setInterval(function() {
- timer++;
-
- if (timer > 30) {
- bmp.alpha -= 0.05;
- }
- if (bmp.alpha <= 0) {
- clearInterval(fade);
- }
-
- }, 30);
- }
-});
diff --git a/bomberman/frontend/src/main/webapp/js/ServerProxy.js b/bomberman/frontend/src/main/webapp/js/ServerProxy.js
deleted file mode 100644
index 53bfc190d1..0000000000
--- a/bomberman/frontend/src/main/webapp/js/ServerProxy.js
+++ /dev/null
@@ -1,91 +0,0 @@
-ServerProxy = Class.extend({
- gameServerUrl: "localhost:8090",
- matchMakerUrl: "localhost:8080/matchmaker/join",
- gameId: "1234",
-
- socket: null,
-
- handler: {},
-
- init: function () {
- this.handler['REPLICA'] = gMessages.handleReplica;
- this.handler['POSSESS'] = gMessages.handlePossess;
-
- var self = this;
- gInputEngine.subscribe('up', function () {
- self.socket.send(gMessages.move('up'))
- });
- gInputEngine.subscribe('down', function () {
- self.socket.send(gMessages.move('down'))
- });
- gInputEngine.subscribe('left', function () {
- self.socket.send(gMessages.move('left'))
- });
- gInputEngine.subscribe('right', function () {
- self.socket.send(gMessages.move('right'))
- });
- gInputEngine.subscribe('bomb', function () {
- self.socket.send(gMessages.plantBomb())
- });
- },
-
- getSessionIdFromMatchMaker: function () {
- var that = this;
- var login = $("#loginInput").val();
- if(!login){
- alert("Please input login");
- console.log("Empty login, retry login");
- }
- $.ajax({
- contentType: 'application/x-www-form-urlencoded',
- data: {
- "name": login
- },
- dataType: 'text',
- success: function(data){
- that.gameId=data;
- console.log("Matchmaker returned gameId=" + data);
- that.connectToGameServer(that.gameId, login);
- },
- error: function(){
- alert("Matchmaker request failed, use default gameId=" + that.gameId);
- console.log("Matchmaker request failed, use default gameId=" + that.gameId);
- that.connectToGameServer(that.gameId, login);
- },
- //processData: false
- type: 'POST',
- url: that.matchMakerUrl
- });
- },
-
- connectToGameServer: function (gameId, login) {
- var self = this;
- this.socket = new WebSocket("ws://" + this.gameServerUrl + "/game/connect?gameId=" + gameId + "&name=" + login);
-
- this.socket.onopen = function () {
- console.log("Connection established.");
- };
-
- this.socket.onclose = function (event) {
- if (event.wasClean) {
- console.log('closed');
- } else {
- console.log('alert close');
- }
- console.log('Code: ' + event.code + ' cause: ' + event.reason);
- };
-
- this.socket.onmessage = function (event) {
- var msg = JSON.parse(event.data);
- if (self.handler[msg.topic] === undefined)
- return;
-
- self.handler[msg.topic](msg);
- };
-
- this.socket.onerror = function (error) {
- console.log("Error " + error.message);
- };
- }
-
-});
diff --git a/bomberman/frontend/src/main/webapp/js/Tile.js b/bomberman/frontend/src/main/webapp/js/Tile.js
deleted file mode 100644
index b0e0f2a6aa..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Tile.js
+++ /dev/null
@@ -1,48 +0,0 @@
-Tile = Entity.extend({
- /**
- * Entity position on map grid
- */
- position: {},
-
- /**
- * Bitmap dimensions
- */
- size: {
- w: 32,
- h: 32
- },
-
- /**
- * Bitmap animation
- */
- bmp: null,
-
- material: '',
-
- init: function(id, material, position) {
- this.id = id;
- this.material = material;
- this.position = position;
- var img;
- if (material == 'grass') {
- img = gGameEngine.tilesImgs.grass;
- } else if (material === 'Wall') {
- img = gGameEngine.tilesImgs.wall;
- } else if (material === 'Wood') {
- img = gGameEngine.tilesImgs.wood;
- }
- this.bmp = new createjs.Bitmap(img);
-
- this.bmp.x = position.x;
- this.bmp.y = position.y;
-
- gGameEngine.stage.addChild(this.bmp);
- },
-
- update: function() {
- },
-
- remove: function() {
- gGameEngine.stage.removeChild(this.bmp);
- }
-});
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/Utils.js b/bomberman/frontend/src/main/webapp/js/Utils.js
deleted file mode 100644
index 35446f8049..0000000000
--- a/bomberman/frontend/src/main/webapp/js/Utils.js
+++ /dev/null
@@ -1,48 +0,0 @@
-var Utils = {};
-
-/**
- * Returns true if positions are equal.
- */
-Utils.comparePositions = function(pos1, pos2) {
- return pos1.x == pos2.x && pos1.y == pos2.y;
-};
-
-
-/**
- * Convert bitmap pixels position to entity on grid position.
- */
-Utils.convertToEntityPosition = function(pixels) {
- var position = {};
- position.x = Math.round(pixels.x / gGameEngine.tileSize);
- position.y = Math.round(pixels.y /gGameEngine.tileSize);
- return position;
-};
-
-Utils.getEntityPosition = function (pixels) {
- var position = {};
- position.x = pixels.x;
- position.y = -pixels.y + 12 * 32;
- return position;
-}
-
-/**
- * Convert entity on grid position to bitmap pixels position.
- */
-Utils.convertToBitmapPosition = function(entity) {
- var position = {};
- position.x = entity.x * gGameEngine.tileSize;
- position.y = entity.y * gGameEngine.tileSize;
- return position;
-};
-
-/**
- * Removes an item from array.
- */
-Utils.removeFromArray = function(array, item) {
- for (var i = 0; i < array.length; i++) {
- if (item == array[i]) {
- array.splice(i, 1);
- }
- }
- return array;
-};
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/core.js b/bomberman/frontend/src/main/webapp/js/core.js
deleted file mode 100644
index 31f5105790..0000000000
--- a/bomberman/frontend/src/main/webapp/js/core.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/* Simple JavaScript Inheritance
- * By John Resig http://ejohn.org/
- * MIT Licensed.
- */
-// Inspired by base2 and Prototype
-(function(){
- var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
-
- // The base Class implementation (does nothing)
- this.Class = function(){};
-
- // Create a new Class that inherits from this class
- Class.extend = function(prop) {
- var _super = this.prototype;
-
- // Instantiate a base class (but only create the instance,
- // don't run the init constructor)
- initializing = true;
- var prototype = new this();
- initializing = false;
-
- // Copy the properties over onto the new prototype
- for (var name in prop) {
- // Check if we're overwriting an existing function
- prototype[name] = typeof prop[name] == "function" &&
- typeof _super[name] == "function" && fnTest.test(prop[name]) ?
- (function(name, fn){
- return function() {
- var tmp = this._super;
-
- // Add a new ._super() method that is the same method
- // but on the super-class
- this._super = _super[name];
-
- // The method only need to be bound temporarily, so we
- // remove it when we're done executing
- var ret = fn.apply(this, arguments);
- this._super = tmp;
-
- return ret;
- };
- })(name, prop[name]) :
- prop[name];
- }
-
- // The dummy class constructor
- function Class() {
- // All construction is actually done in the init method
- if ( !initializing && this.init )
- this.init.apply(this, arguments);
- }
-
- // Populate our constructed prototype object
- Class.prototype = prototype;
-
- // Enforce the constructor to be what we expect
- Class.prototype.constructor = Class;
-
- // And make this class extendable
- Class.extend = arguments.callee;
-
- return Class;
- };
-})();
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js b/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js
deleted file mode 100644
index 6f2e17b093..0000000000
--- a/bomberman/frontend/src/main/webapp/js/lib/easeljs-NEXT.combined.js
+++ /dev/null
@@ -1,13413 +0,0 @@
-/*!
-* EaselJS
-* Visit http://createjs.com/ for documentation, updates and examples.
-*
-* Copyright (c) 2010 gskinner.com, inc.
-*
-* Permission is hereby granted, free of charge, to any person
-* obtaining a copy of this software and associated documentation
-* files (the "Software"), to deal in the Software without
-* restriction, including without limitation the rights to use,
-* copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following
-* conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-* OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-//##############################################################################
-// extend.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Sets up the prototype chain and constructor property for a new class.
- *
- * This should be called right after creating the class constructor.
- *
- * function MySubClass() {}
- * createjs.extend(MySubClass, MySuperClass);
- * MySubClass.prototype.doSomething = function() { }
- *
- * var foo = new MySubClass();
- * console.log(foo instanceof MySuperClass); // true
- * console.log(foo.prototype.constructor === MySubClass); // true
- *
- * @method extend
- * @param {Function} subclass The subclass.
- * @param {Function} superclass The superclass to extend.
- * @return {Function} Returns the subclass's new prototype.
- */
-createjs.extend = function(subclass, superclass) {
- "use strict";
-
- function o() { this.constructor = subclass; }
- o.prototype = superclass.prototype;
- return (subclass.prototype = new o());
-};
-
-//##############################################################################
-// promote.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`.
- * It is recommended to use the super class's name as the prefix.
- * An alias to the super class's constructor is always added in the format `prefix_constructor`.
- * This allows the subclass to call super class methods without using `function.call`, providing better performance.
- *
- * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")`
- * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the
- * prototype of `MySubClass` as `MySuperClass_draw`.
- *
- * This should be called after the class's prototype is fully defined.
- *
- * function ClassA(name) {
- * this.name = name;
- * }
- * ClassA.prototype.greet = function() {
- * return "Hello "+this.name;
- * }
- *
- * function ClassB(name, punctuation) {
- * this.ClassA_constructor(name);
- * this.punctuation = punctuation;
- * }
- * createjs.extend(ClassB, ClassA);
- * ClassB.prototype.greet = function() {
- * return this.ClassA_greet()+this.punctuation;
- * }
- * createjs.promote(ClassB, "ClassA");
- *
- * var foo = new ClassB("World", "!?!");
- * console.log(foo.greet()); // Hello World!?!
- *
- * @method promote
- * @param {Function} subclass The class to promote super class methods on.
- * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass.
- * @return {Function} Returns the subclass.
- */
-createjs.promote = function(subclass, prefix) {
- "use strict";
-
- var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__;
- if (supP) {
- subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable
- for (var n in supP) {
- if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; }
- }
- }
- return subclass;
-};
-
-//##############################################################################
-// indexOf.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of
- * that value. Returns -1 if value is not found.
- *
- * var i = createjs.indexOf(myArray, myElementToFind);
- *
- * @method indexOf
- * @param {Array} array Array to search for searchElement
- * @param searchElement Element to find in array.
- * @return {Number} The first index of searchElement in array.
- */
-createjs.indexOf = function (array, searchElement){
- "use strict";
-
- for (var i = 0,l=array.length; i < l; i++) {
- if (searchElement === array[i]) {
- return i;
- }
- }
- return -1;
-};
-
-//##############################################################################
-// Event.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-// constructor:
- /**
- * Contains properties and methods shared by all events for use with
- * {{#crossLink "EventDispatcher"}}{{/crossLink}}.
- *
- * Note that Event objects are often reused, so you should never
- * rely on an event object's state outside of the call stack it was received in.
- * @class Event
- * @param {String} type The event type.
- * @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
- * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
- * @constructor
- **/
- function Event(type, bubbles, cancelable) {
-
-
- // public properties:
- /**
- * The type of event.
- * @property type
- * @type String
- **/
- this.type = type;
-
- /**
- * The object that generated an event.
- * @property target
- * @type Object
- * @default null
- * @readonly
- */
- this.target = null;
-
- /**
- * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will
- * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event
- * is generated from childObj, then a listener on parentObj would receive the event with
- * target=childObj (the original target) and currentTarget=parentObj (where the listener was added).
- * @property currentTarget
- * @type Object
- * @default null
- * @readonly
- */
- this.currentTarget = null;
-
- /**
- * For bubbling events, this indicates the current event phase:
- *
capture phase: starting from the top parent to the target
- *
at target phase: currently being dispatched from the target
- *
bubbling phase: from the target to the top parent
- *
- * @property eventPhase
- * @type Number
- * @default 0
- * @readonly
- */
- this.eventPhase = 0;
-
- /**
- * Indicates whether the event will bubble through the display list.
- * @property bubbles
- * @type Boolean
- * @default false
- * @readonly
- */
- this.bubbles = !!bubbles;
-
- /**
- * Indicates whether the default behaviour of this event can be cancelled via
- * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor.
- * @property cancelable
- * @type Boolean
- * @default false
- * @readonly
- */
- this.cancelable = !!cancelable;
-
- /**
- * The epoch time at which this event was created.
- * @property timeStamp
- * @type Number
- * @default 0
- * @readonly
- */
- this.timeStamp = (new Date()).getTime();
-
- /**
- * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
- * on this event.
- * @property defaultPrevented
- * @type Boolean
- * @default false
- * @readonly
- */
- this.defaultPrevented = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or
- * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event.
- * @property propagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.propagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
- * on this event.
- * @property immediatePropagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.immediatePropagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
- * @property removed
- * @type Boolean
- * @default false
- * @readonly
- */
- this.removed = false;
- }
- var p = Event.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-// public methods:
- /**
- * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable.
- * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will
- * cancel the default behaviour associated with the event.
- * @method preventDefault
- **/
- p.preventDefault = function() {
- this.defaultPrevented = this.cancelable&&true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopPropagation
- **/
- p.stopPropagation = function() {
- this.propagationStopped = true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and
- * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopImmediatePropagation
- **/
- p.stopImmediatePropagation = function() {
- this.immediatePropagationStopped = this.propagationStopped = true;
- };
-
- /**
- * Causes the active listener to be removed via removeEventListener();
- *
- * myBtn.addEventListener("click", function(evt) {
- * // do stuff...
- * evt.remove(); // removes this listener.
- * });
- *
- * @method remove
- **/
- p.remove = function() {
- this.removed = true;
- };
-
- /**
- * Returns a clone of the Event instance.
- * @method clone
- * @return {Event} a clone of the Event instance.
- **/
- p.clone = function() {
- return new Event(this.type, this.bubbles, this.cancelable);
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the instance.
- * @return {Event} Returns the instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Event (type="+this.type+")]";
- };
-
- createjs.Event = Event;
-}());
-
-//##############################################################################
-// EventDispatcher.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * EventDispatcher provides methods for managing queues of event listeners and dispatching events.
- *
- * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the
- * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method.
- *
- * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the
- * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports
- * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent.
- *
- * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier
- * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The
- * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to
- * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}.
- *
- * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}}
- * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also
- * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener.
- *
- *
Example
- * Add EventDispatcher capabilities to the "MyClass" class.
- *
- * EventDispatcher.initialize(MyClass.prototype);
- *
- * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}).
- *
- * instance.addEventListener("eventName", handlerMethod);
- * function handlerMethod(event) {
- * console.log(event.target + " Was Clicked");
- * }
- *
- * Maintaining proper scope
- * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}}
- * method to subscribe to events simplifies this.
- *
- * instance.addEventListener("click", function(event) {
- * console.log(instance == this); // false, scope is ambiguous.
- * });
- *
- * instance.on("click", function(event) {
- * console.log(instance == this); // true, "on" uses dispatcher scope by default.
- * });
- *
- * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage
- * scope.
- *
- * Browser support
- * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model
- * requires modern browsers (IE9+).
- *
- *
- * @class EventDispatcher
- * @constructor
- **/
- function EventDispatcher() {
-
-
- // private properties:
- /**
- * @protected
- * @property _listeners
- * @type Object
- **/
- this._listeners = null;
-
- /**
- * @protected
- * @property _captureListeners
- * @type Object
- **/
- this._captureListeners = null;
- }
- var p = EventDispatcher.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// static public methods:
- /**
- * Static initializer to mix EventDispatcher methods into a target object or prototype.
- *
- * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class
- * EventDispatcher.initialize(myObject); // add to a specific instance
- *
- * @method initialize
- * @static
- * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a
- * prototype.
- **/
- EventDispatcher.initialize = function(target) {
- target.addEventListener = p.addEventListener;
- target.on = p.on;
- target.removeEventListener = target.off = p.removeEventListener;
- target.removeAllEventListeners = p.removeAllEventListeners;
- target.hasEventListener = p.hasEventListener;
- target.dispatchEvent = p.dispatchEvent;
- target._dispatchEvent = p._dispatchEvent;
- target.willTrigger = p.willTrigger;
- };
-
-
-// public methods:
- /**
- * Adds the specified event listener. Note that adding multiple listeners to the same function will result in
- * multiple callbacks getting fired.
- *
- *
Example
- *
- * displayObject.addEventListener("click", handleClick);
- * function handleClick(event) {
- * // Click happened.
- * }
- *
- * @method addEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function | Object} Returns the listener for chaining or assignment.
- **/
- p.addEventListener = function(type, listener, useCapture) {
- var listeners;
- if (useCapture) {
- listeners = this._captureListeners = this._captureListeners||{};
- } else {
- listeners = this._listeners = this._listeners||{};
- }
- var arr = listeners[type];
- if (arr) { this.removeEventListener(type, listener, useCapture); }
- arr = listeners[type]; // remove may have deleted the array
- if (!arr) { listeners[type] = [listener]; }
- else { arr.push(listener); }
- return listener;
- };
-
- /**
- * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener
- * only run once, associate arbitrary data with the listener, and remove the listener.
- *
- * This method works by creating an anonymous wrapper function and subscribing it with addEventListener.
- * The wrapper function is returned for use with `removeEventListener` (or `off`).
- *
- * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use
- * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls
- * to `on` with the same params will create multiple listeners.
- *
- *
Example
- *
- * var listener = myBtn.on("click", handleClick, null, false, {count:3});
- * function handleClick(evt, data) {
- * data.count -= 1;
- * console.log(this == myBtn); // true - scope defaults to the dispatcher
- * if (data.count == 0) {
- * alert("clicked 3 times!");
- * myBtn.off("click", listener);
- * // alternately: evt.remove();
- * }
- * }
- *
- * @method on
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent).
- * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered.
- * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called.
- * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener.
- **/
- p.on = function(type, listener, scope, once, data, useCapture) {
- if (listener.handleEvent) {
- scope = scope||listener;
- listener = listener.handleEvent;
- }
- scope = scope||this;
- return this.addEventListener(type, function(evt) {
- listener.call(scope, evt, data);
- once&&evt.remove();
- }, useCapture);
- };
-
- /**
- * Removes the specified event listener.
- *
- * Important Note: that you must pass the exact function reference used when the event was added. If a proxy
- * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or
- * closure will not work.
- *
- *
Example
- *
- * displayObject.removeEventListener("click", handleClick);
- *
- * @method removeEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.removeEventListener = function(type, listener, useCapture) {
- var listeners = useCapture ? this._captureListeners : this._listeners;
- if (!listeners) { return; }
- var arr = listeners[type];
- if (!arr) { return; }
- for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See
- * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example.
- *
- * @method off
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.off = p.removeEventListener;
-
- /**
- * Removes all listeners for the specified type, or all listeners of all types.
- *
- *
Example
- *
- * // Remove all listeners
- * displayObject.removeAllEventListeners();
- *
- * // Remove all click listeners
- * displayObject.removeAllEventListeners("click");
- *
- * @method removeAllEventListeners
- * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed.
- **/
- p.removeAllEventListeners = function(type) {
- if (!type) { this._listeners = this._captureListeners = null; }
- else {
- if (this._listeners) { delete(this._listeners[type]); }
- if (this._captureListeners) { delete(this._captureListeners[type]); }
- }
- };
-
- /**
- * Dispatches the specified event to all listeners.
- *
- *
Example
- *
- * // Use a string event
- * this.dispatchEvent("complete");
- *
- * // Use an Event instance
- * var event = new createjs.Event("progress");
- * this.dispatchEvent(event);
- *
- * @method dispatchEvent
- * @param {Object | String | Event} eventObj An object with a "type" property, or a string type.
- * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used,
- * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can
- * be used to avoid event object instantiation for non-bubbling events that may not have any listeners.
- * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj.
- * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj.
- * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise.
- **/
- p.dispatchEvent = function(eventObj, bubbles, cancelable) {
- if (typeof eventObj == "string") {
- // skip everything if there's no listeners and it doesn't bubble:
- var listeners = this._listeners;
- if (!bubbles && (!listeners || !listeners[eventObj])) { return true; }
- eventObj = new createjs.Event(eventObj, bubbles, cancelable);
- } else if (eventObj.target && eventObj.clone) {
- // redispatching an active event object, so clone it:
- eventObj = eventObj.clone();
- }
-
- // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent
- try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events
-
- if (!eventObj.bubbles || !this.parent) {
- this._dispatchEvent(eventObj, 2);
- } else {
- var top=this, list=[top];
- while (top.parent) { list.push(top = top.parent); }
- var i, l=list.length;
-
- // capture & atTarget
- for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) {
- list[i]._dispatchEvent(eventObj, 1+(i==0));
- }
- // bubbling
- for (i=1; iExample
- *
- * createjs.Ticker.addEventListener("tick", handleTick);
- * function handleTick(event) {
- * // Actions carried out each tick (aka frame)
- * if (!event.paused) {
- * // Actions carried out when the Ticker is not paused.
- * }
- * }
- *
- * @class Ticker
- * @uses EventDispatcher
- * @static
- **/
- function Ticker() {
- throw "Ticker cannot be instantiated.";
- }
-
-
-// constants:
- /**
- * In this mode, Ticker uses the requestAnimationFrame API, but attempts to synch the ticks to target framerate. It
- * uses a simple heuristic that compares the time of the RAF return to the target time for the current frame and
- * dispatches the tick when the time is within a certain threshold.
- *
- * This mode has a higher variance for time between frames than {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}},
- * but does not require that content be time based as with {{#crossLink "Ticker/RAF:property"}}{{/crossLink}} while
- * gaining the benefits of that API (screen synch, background throttling).
- *
- * Variance is usually lowest for framerates that are a divisor of the RAF frequency. This is usually 60, so
- * framerates of 10, 12, 15, 20, and 30 work well.
- *
- * Falls back to {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}} if the requestAnimationFrame API is not
- * supported.
- * @property RAF_SYNCHED
- * @static
- * @type {String}
- * @default "synched"
- * @readonly
- **/
- Ticker.RAF_SYNCHED = "synched";
-
- /**
- * In this mode, Ticker passes through the requestAnimationFrame heartbeat, ignoring the target framerate completely.
- * Because requestAnimationFrame frequency is not deterministic, any content using this mode should be time based.
- * You can leverage {{#crossLink "Ticker/getTime"}}{{/crossLink}} and the {{#crossLink "Ticker/tick:event"}}{{/crossLink}}
- * event object's "delta" properties to make this easier.
- *
- * Falls back on {{#crossLink "Ticker/TIMEOUT:property"}}{{/crossLink}} if the requestAnimationFrame API is not
- * supported.
- * @property RAF
- * @static
- * @type {String}
- * @default "raf"
- * @readonly
- **/
- Ticker.RAF = "raf";
-
- /**
- * In this mode, Ticker uses the setTimeout API. This provides predictable, adaptive frame timing, but does not
- * provide the benefits of requestAnimationFrame (screen synch, background throttling).
- * @property TIMEOUT
- * @static
- * @type {String}
- * @default "timeout"
- * @readonly
- **/
- Ticker.TIMEOUT = "timeout";
-
-
-// static events:
- /**
- * Dispatched each tick. The event will be dispatched to each listener even when the Ticker has been paused using
- * {{#crossLink "Ticker/setPaused"}}{{/crossLink}}.
- *
- *
Example
- *
- * createjs.Ticker.addEventListener("tick", handleTick);
- * function handleTick(event) {
- * console.log("Paused:", event.paused, event.delta);
- * }
- *
- * @event tick
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {Boolean} paused Indicates whether the ticker is currently paused.
- * @param {Number} delta The time elapsed in ms since the last tick.
- * @param {Number} time The total time in ms since Ticker was initialized.
- * @param {Number} runTime The total time in ms that Ticker was not paused since it was initialized. For example,
- * you could determine the amount of time that the Ticker has been paused since initialization with `time-runTime`.
- * @since 0.6.0
- */
-
-
-// public static properties:
- /**
- * Deprecated in favour of {{#crossLink "Ticker/timingMode"}}{{/crossLink}}, and will be removed in a future version. If true, timingMode will
- * use {{#crossLink "Ticker/RAF_SYNCHED"}}{{/crossLink}} by default.
- * @deprecated Deprecated in favour of {{#crossLink "Ticker/timingMode"}}{{/crossLink}}.
- * @property useRAF
- * @static
- * @type {Boolean}
- * @default false
- **/
- Ticker.useRAF = false;
-
- /**
- * Specifies the timing api (setTimeout or requestAnimationFrame) and mode to use. See
- * {{#crossLink "Ticker/TIMEOUT"}}{{/crossLink}}, {{#crossLink "Ticker/RAF"}}{{/crossLink}}, and
- * {{#crossLink "Ticker/RAF_SYNCHED"}}{{/crossLink}} for mode details.
- * @property timingMode
- * @static
- * @type {String}
- * @default Ticker.TIMEOUT
- **/
- Ticker.timingMode = null;
-
- /**
- * Specifies a maximum value for the delta property in the tick event object. This is useful when building time
- * based animations and systems to prevent issues caused by large time gaps caused by background tabs, system sleep,
- * alert dialogs, or other blocking routines. Double the expected frame duration is often an effective value
- * (ex. maxDelta=50 when running at 40fps).
- *
- * This does not impact any other values (ex. time, runTime, etc), so you may experience issues if you enable maxDelta
- * when using both delta and other values.
- *
- * If 0, there is no maximum.
- * @property maxDelta
- * @static
- * @type {number}
- * @default 0
- */
- Ticker.maxDelta = 0;
-
- /**
- * When the ticker is paused, all listeners will still receive a tick event, but the paused property
- * of the event will be `true`. Also, while paused the `runTime` will not increase. See {{#crossLink "Ticker/tick:event"}}{{/crossLink}},
- * {{#crossLink "Ticker/getTime"}}{{/crossLink}}, and {{#crossLink "Ticker/getEventTime"}}{{/crossLink}} for more
- * info.
- *
- *
Example
- *
- * createjs.Ticker.addEventListener("tick", handleTick);
- * createjs.Ticker.paused = true;
- * function handleTick(event) {
- * console.log(event.paused,
- * createjs.Ticker.getTime(false),
- * createjs.Ticker.getTime(true));
- * }
- *
- * @property paused
- * @static
- * @type {Boolean}
- * @default false
- **/
- Ticker.paused = false;
-
-
-// mix-ins:
- // EventDispatcher methods:
- Ticker.removeEventListener = null;
- Ticker.removeAllEventListeners = null;
- Ticker.dispatchEvent = null;
- Ticker.hasEventListener = null;
- Ticker._listeners = null;
- createjs.EventDispatcher.initialize(Ticker); // inject EventDispatcher methods.
- Ticker._addEventListener = Ticker.addEventListener;
- Ticker.addEventListener = function() {
- !Ticker._inited&&Ticker.init();
- return Ticker._addEventListener.apply(Ticker, arguments);
- };
-
-
-// private static properties:
- /**
- * @property _inited
- * @static
- * @type {Boolean}
- * @protected
- **/
- Ticker._inited = false;
-
- /**
- * @property _startTime
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._startTime = 0;
-
- /**
- * @property _pausedTime
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._pausedTime=0;
-
- /**
- * The number of ticks that have passed
- * @property _ticks
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._ticks = 0;
-
- /**
- * The number of ticks that have passed while Ticker has been paused
- * @property _pausedTicks
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._pausedTicks = 0;
-
- /**
- * @property _interval
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._interval = 50;
-
- /**
- * @property _lastTime
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._lastTime = 0;
-
- /**
- * @property _times
- * @static
- * @type {Array}
- * @protected
- **/
- Ticker._times = null;
-
- /**
- * @property _tickTimes
- * @static
- * @type {Array}
- * @protected
- **/
- Ticker._tickTimes = null;
-
- /**
- * Stores the timeout or requestAnimationFrame id.
- * @property _timerId
- * @static
- * @type {Number}
- * @protected
- **/
- Ticker._timerId = null;
-
- /**
- * True if currently using requestAnimationFrame, false if using setTimeout. This may be different than timingMode
- * if that property changed and a tick hasn't fired.
- * @property _raf
- * @static
- * @type {Boolean}
- * @protected
- **/
- Ticker._raf = true;
-
-
-// static getter / setters:
- /**
- * Use the {{#crossLink "Ticker/interval:property"}}{{/crossLink}} property instead.
- * @method setInterval
- * @static
- * @param {Number} interval
- * @deprecated
- **/
- Ticker.setInterval = function(interval) {
- Ticker._interval = interval;
- if (!Ticker._inited) { return; }
- Ticker._setupTick();
- };
-
- /**
- * Use the {{#crossLink "Ticker/interval:property"}}{{/crossLink}} property instead.
- * @method getInterval
- * @static
- * @return {Number}
- * @deprecated
- **/
- Ticker.getInterval = function() {
- return Ticker._interval;
- };
-
- /**
- * Use the {{#crossLink "Ticker/framerate:property"}}{{/crossLink}} property instead.
- * @method setFPS
- * @static
- * @param {Number} value
- * @deprecated
- **/
- Ticker.setFPS = function(value) {
- Ticker.setInterval(1000/value);
- };
-
- /**
- * Use the {{#crossLink "Ticker/framerate:property"}}{{/crossLink}} property instead.
- * @method getFPS
- * @static
- * @return {Number}
- * @deprecated
- **/
- Ticker.getFPS = function() {
- return 1000/Ticker._interval;
- };
-
- /**
- * Indicates the target time (in milliseconds) between ticks. Default is 50 (20 FPS).
- * Note that actual time between ticks may be more than specified depending on CPU load.
- * This property is ignored if the ticker is using the `RAF` timing mode.
- * @property interval
- * @static
- * @type {Number}
- **/
-
- /**
- * Indicates the target frame rate in frames per second (FPS). Effectively just a shortcut to `interval`, where
- * `framerate == 1000/interval`.
- * @property framerate
- * @static
- * @type {Number}
- **/
- try {
- Object.defineProperties(Ticker, {
- interval: { get: Ticker.getInterval, set: Ticker.setInterval },
- framerate: { get: Ticker.getFPS, set: Ticker.setFPS }
- });
- } catch (e) { console.log(e); }
-
-
-// public static methods:
- /**
- * Starts the tick. This is called automatically when the first listener is added.
- * @method init
- * @static
- **/
- Ticker.init = function() {
- if (Ticker._inited) { return; }
- Ticker._inited = true;
- Ticker._times = [];
- Ticker._tickTimes = [];
- Ticker._startTime = Ticker._getTime();
- Ticker._times.push(Ticker._lastTime = 0);
- Ticker.interval = Ticker._interval;
- };
-
- /**
- * Stops the Ticker and removes all listeners. Use init() to restart the Ticker.
- * @method reset
- * @static
- **/
- Ticker.reset = function() {
- if (Ticker._raf) {
- var f = window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || window.oCancelAnimationFrame || window.msCancelAnimationFrame;
- f&&f(Ticker._timerId);
- } else {
- clearTimeout(Ticker._timerId);
- }
- Ticker.removeAllEventListeners("tick");
- Ticker._timerId = Ticker._times = Ticker._tickTimes = null;
- Ticker._startTime = Ticker._lastTime = Ticker._ticks = 0;
- Ticker._inited = false;
- };
-
- /**
- * Returns the average time spent within a tick. This can vary significantly from the value provided by getMeasuredFPS
- * because it only measures the time spent within the tick execution stack.
- *
- * Example 1: With a target FPS of 20, getMeasuredFPS() returns 20fps, which indicates an average of 50ms between
- * the end of one tick and the end of the next. However, getMeasuredTickTime() returns 15ms. This indicates that
- * there may be up to 35ms of "idle" time between the end of one tick and the start of the next.
- *
- * Example 2: With a target FPS of 30, getFPS() returns 10fps, which indicates an average of 100ms between the end of
- * one tick and the end of the next. However, getMeasuredTickTime() returns 20ms. This would indicate that something
- * other than the tick is using ~80ms (another script, DOM rendering, etc).
- * @method getMeasuredTickTime
- * @static
- * @param {Number} [ticks] The number of previous ticks over which to measure the average time spent in a tick.
- * Defaults to the number of ticks per second. To get only the last tick's time, pass in 1.
- * @return {Number} The average time spent in a tick in milliseconds.
- **/
- Ticker.getMeasuredTickTime = function(ticks) {
- var ttl=0, times=Ticker._tickTimes;
- if (!times || times.length < 1) { return -1; }
-
- // by default, calculate average for the past ~1 second:
- ticks = Math.min(times.length, ticks||(Ticker.getFPS()|0));
- for (var i=0; i= (Ticker._interval-1)*0.97) {
- Ticker._tick();
- }
- };
-
- /**
- * @method _handleRAF
- * @static
- * @protected
- **/
- Ticker._handleRAF = function() {
- Ticker._timerId = null;
- Ticker._setupTick();
- Ticker._tick();
- };
-
- /**
- * @method _handleTimeout
- * @static
- * @protected
- **/
- Ticker._handleTimeout = function() {
- Ticker._timerId = null;
- Ticker._setupTick();
- Ticker._tick();
- };
-
- /**
- * @method _setupTick
- * @static
- * @protected
- **/
- Ticker._setupTick = function() {
- if (Ticker._timerId != null) { return; } // avoid duplicates
-
- var mode = Ticker.timingMode||(Ticker.useRAF&&Ticker.RAF_SYNCHED);
- if (mode == Ticker.RAF_SYNCHED || mode == Ticker.RAF) {
- var f = window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame;
- if (f) {
- Ticker._timerId = f(mode == Ticker.RAF ? Ticker._handleRAF : Ticker._handleSynch);
- Ticker._raf = true;
- return;
- }
- }
- Ticker._raf = false;
- Ticker._timerId = setTimeout(Ticker._handleTimeout, Ticker._interval);
- };
-
- /**
- * @method _tick
- * @static
- * @protected
- **/
- Ticker._tick = function() {
- var paused = Ticker.paused;
- var time = Ticker._getTime();
- var elapsedTime = time-Ticker._lastTime;
- Ticker._lastTime = time;
- Ticker._ticks++;
-
- if (paused) {
- Ticker._pausedTicks++;
- Ticker._pausedTime += elapsedTime;
- }
-
- if (Ticker.hasEventListener("tick")) {
- var event = new createjs.Event("tick");
- var maxDelta = Ticker.maxDelta;
- event.delta = (maxDelta && elapsedTime > maxDelta) ? maxDelta : elapsedTime;
- event.paused = paused;
- event.time = time;
- event.runTime = time-Ticker._pausedTime;
- Ticker.dispatchEvent(event);
- }
-
- Ticker._tickTimes.unshift(Ticker._getTime()-time);
- while (Ticker._tickTimes.length > 100) { Ticker._tickTimes.pop(); }
-
- Ticker._times.unshift(time);
- while (Ticker._times.length > 100) { Ticker._times.pop(); }
- };
-
- /**
- * @method _getTime
- * @static
- * @protected
- **/
- var now = window.performance && (performance.now || performance.mozNow || performance.msNow || performance.oNow || performance.webkitNow);
- Ticker._getTime = function() {
- return ((now&&now.call(performance))||(new Date().getTime())) - Ticker._startTime;
- };
-
-
- createjs.Ticker = Ticker;
-}());
-
-//##############################################################################
-// UID.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Global utility for generating sequential unique ID numbers. The UID class uses a static interface (ex. UID.get())
- * and should not be instantiated.
- * @class UID
- * @static
- **/
- function UID() {
- throw "UID cannot be instantiated";
- }
-
-
-// private static properties:
- /**
- * @property _nextID
- * @type Number
- * @protected
- **/
- UID._nextID = 0;
-
-
-// public static methods:
- /**
- * Returns the next unique id.
- * @method get
- * @return {Number} The next unique id
- * @static
- **/
- UID.get = function() {
- return UID._nextID++;
- };
-
-
- createjs.UID = UID;
-}());
-
-//##############################################################################
-// MouseEvent.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Passed as the parameter to all mouse/pointer/touch related events. For a listing of mouse events and their properties,
- * see the {{#crossLink "DisplayObject"}}{{/crossLink}} and {{#crossLink "Stage"}}{{/crossLink}} event listings.
- * @class MouseEvent
- * @param {String} type The event type.
- * @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
- * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
- * @param {Number} stageX The normalized x position relative to the stage.
- * @param {Number} stageY The normalized y position relative to the stage.
- * @param {MouseEvent} nativeEvent The native DOM event related to this mouse event.
- * @param {Number} pointerID The unique id for the pointer.
- * @param {Boolean} primary Indicates whether this is the primary pointer in a multitouch environment.
- * @param {Number} rawX The raw x position relative to the stage.
- * @param {Number} rawY The raw y position relative to the stage.
- * @param {DisplayObject} relatedTarget The secondary target for the event.
- * @extends Event
- * @constructor
- **/
- function MouseEvent(type, bubbles, cancelable, stageX, stageY, nativeEvent, pointerID, primary, rawX, rawY, relatedTarget) {
- this.Event_constructor(type, bubbles, cancelable);
-
-
- // public properties:
- /**
- * The normalized x position on the stage. This will always be within the range 0 to stage width.
- * @property stageX
- * @type Number
- */
- this.stageX = stageX;
-
- /**
- * The normalized y position on the stage. This will always be within the range 0 to stage height.
- * @property stageY
- * @type Number
- **/
- this.stageY = stageY;
-
- /**
- * The raw x position relative to the stage. Normally this will be the same as the stageX value, unless
- * stage.mouseMoveOutside is true and the pointer is outside of the stage bounds.
- * @property rawX
- * @type Number
- */
- this.rawX = (rawX==null)?stageX:rawX;
-
- /**
- * The raw y position relative to the stage. Normally this will be the same as the stageY value, unless
- * stage.mouseMoveOutside is true and the pointer is outside of the stage bounds.
- * @property rawY
- * @type Number
- */
- this.rawY = (rawY==null)?stageY:rawY;
-
- /**
- * The native MouseEvent generated by the browser. The properties and API for this
- * event may differ between browsers. This property will be null if the
- * EaselJS property was not directly generated from a native MouseEvent.
- * @property nativeEvent
- * @type HtmlMouseEvent
- * @default null
- **/
- this.nativeEvent = nativeEvent;
-
- /**
- * The unique id for the pointer (touch point or cursor). This will be either -1 for the mouse, or the system
- * supplied id value.
- * @property pointerID
- * @type {Number}
- */
- this.pointerID = pointerID;
-
- /**
- * Indicates whether this is the primary pointer in a multitouch environment. This will always be true for the mouse.
- * For touch pointers, the first pointer in the current stack will be considered the primary pointer.
- * @property primary
- * @type {Boolean}
- */
- this.primary = !!primary;
-
- /**
- * The secondary target for the event, if applicable. This is used for mouseout/rollout
- * events to indicate the object that the mouse entered from, mouseover/rollover for the object the mouse exited,
- * and stagemousedown/stagemouseup events for the object that was the under the cursor, if any.
- *
- * Only valid interaction targets will be returned (ie. objects with mouse listeners or a cursor set).
- * @property relatedTarget
- * @type {DisplayObject}
- */
- this.relatedTarget = relatedTarget;
- }
- var p = createjs.extend(MouseEvent, createjs.Event);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// getter / setters:
- /**
- * Returns the x position of the mouse in the local coordinate system of the current target (ie. the dispatcher).
- * @property localX
- * @type {Number}
- * @readonly
- */
- p._get_localX = function() {
- return this.currentTarget.globalToLocal(this.rawX, this.rawY).x;
- };
-
- /**
- * Returns the y position of the mouse in the local coordinate system of the current target (ie. the dispatcher).
- * @property localY
- * @type {Number}
- * @readonly
- */
- p._get_localY = function() {
- return this.currentTarget.globalToLocal(this.rawX, this.rawY).y;
- };
-
- /**
- * Indicates whether the event was generated by a touch input (versus a mouse input).
- * @property isTouch
- * @type {Boolean}
- * @readonly
- */
- p._get_isTouch = function() {
- return this.pointerID !== -1;
- };
-
-
- try {
- Object.defineProperties(p, {
- localX: { get: p._get_localX },
- localY: { get: p._get_localY },
- isTouch: { get: p._get_isTouch }
- });
- } catch (e) {} // TODO: use Log
-
-
-// public methods:
- /**
- * Returns a clone of the MouseEvent instance.
- * @method clone
- * @return {MouseEvent} a clone of the MouseEvent instance.
- **/
- p.clone = function() {
- return new MouseEvent(this.type, this.bubbles, this.cancelable, this.stageX, this.stageY, this.nativeEvent, this.pointerID, this.primary, this.rawX, this.rawY);
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[MouseEvent (type="+this.type+" stageX="+this.stageX+" stageY="+this.stageY+")]";
- };
-
-
- createjs.MouseEvent = createjs.promote(MouseEvent, "Event");
-}());
-
-//##############################################################################
-// Matrix2D.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Represents an affine transformation matrix, and provides tools for constructing and concatenating matrices.
- *
- * This matrix can be visualized as:
- *
- * [ a c tx
- * b d ty
- * 0 0 1 ]
- *
- * Note the locations of b and c.
- *
- * @class Matrix2D
- * @param {Number} [a=1] Specifies the a property for the new matrix.
- * @param {Number} [b=0] Specifies the b property for the new matrix.
- * @param {Number} [c=0] Specifies the c property for the new matrix.
- * @param {Number} [d=1] Specifies the d property for the new matrix.
- * @param {Number} [tx=0] Specifies the tx property for the new matrix.
- * @param {Number} [ty=0] Specifies the ty property for the new matrix.
- * @constructor
- **/
- function Matrix2D(a, b, c, d, tx, ty) {
- this.setValues(a,b,c,d,tx,ty);
-
- // public properties:
- // assigned in the setValues method.
- /**
- * Position (0, 0) in a 3x3 affine transformation matrix.
- * @property a
- * @type Number
- **/
-
- /**
- * Position (0, 1) in a 3x3 affine transformation matrix.
- * @property b
- * @type Number
- **/
-
- /**
- * Position (1, 0) in a 3x3 affine transformation matrix.
- * @property c
- * @type Number
- **/
-
- /**
- * Position (1, 1) in a 3x3 affine transformation matrix.
- * @property d
- * @type Number
- **/
-
- /**
- * Position (2, 0) in a 3x3 affine transformation matrix.
- * @property tx
- * @type Number
- **/
-
- /**
- * Position (2, 1) in a 3x3 affine transformation matrix.
- * @property ty
- * @type Number
- **/
- }
- var p = Matrix2D.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// constants:
- /**
- * Multiplier for converting degrees to radians. Used internally by Matrix2D.
- * @property DEG_TO_RAD
- * @static
- * @final
- * @type Number
- * @readonly
- **/
- Matrix2D.DEG_TO_RAD = Math.PI/180;
-
-
-// static public properties:
- /**
- * An identity matrix, representing a null transformation.
- * @property identity
- * @static
- * @type Matrix2D
- * @readonly
- **/
- Matrix2D.identity = null; // set at bottom of class definition.
-
-
-// public methods:
- /**
- * Sets the specified values on this instance.
- * @method setValues
- * @param {Number} [a=1] Specifies the a property for the new matrix.
- * @param {Number} [b=0] Specifies the b property for the new matrix.
- * @param {Number} [c=0] Specifies the c property for the new matrix.
- * @param {Number} [d=1] Specifies the d property for the new matrix.
- * @param {Number} [tx=0] Specifies the tx property for the new matrix.
- * @param {Number} [ty=0] Specifies the ty property for the new matrix.
- * @return {Matrix2D} This instance. Useful for chaining method calls.
- */
- p.setValues = function(a, b, c, d, tx, ty) {
- // don't forget to update docs in the constructor if these change:
- this.a = (a == null) ? 1 : a;
- this.b = b || 0;
- this.c = c || 0;
- this.d = (d == null) ? 1 : d;
- this.tx = tx || 0;
- this.ty = ty || 0;
- return this;
- };
-
- /**
- * Appends the specified matrix properties to this matrix. All parameters are required.
- * This is the equivalent of multiplying `(this matrix) * (specified matrix)`.
- * @method append
- * @param {Number} a
- * @param {Number} b
- * @param {Number} c
- * @param {Number} d
- * @param {Number} tx
- * @param {Number} ty
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.append = function(a, b, c, d, tx, ty) {
- var a1 = this.a;
- var b1 = this.b;
- var c1 = this.c;
- var d1 = this.d;
- if (a != 1 || b != 0 || c != 0 || d != 1) {
- this.a = a1*a+c1*b;
- this.b = b1*a+d1*b;
- this.c = a1*c+c1*d;
- this.d = b1*c+d1*d;
- }
- this.tx = a1*tx+c1*ty+this.tx;
- this.ty = b1*tx+d1*ty+this.ty;
- return this;
- };
-
- /**
- * Prepends the specified matrix properties to this matrix.
- * This is the equivalent of multiplying `(specified matrix) * (this matrix)`.
- * All parameters are required.
- * @method prepend
- * @param {Number} a
- * @param {Number} b
- * @param {Number} c
- * @param {Number} d
- * @param {Number} tx
- * @param {Number} ty
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.prepend = function(a, b, c, d, tx, ty) {
- var a1 = this.a;
- var c1 = this.c;
- var tx1 = this.tx;
-
- this.a = a*a1+c*this.b;
- this.b = b*a1+d*this.b;
- this.c = a*c1+c*this.d;
- this.d = b*c1+d*this.d;
- this.tx = a*tx1+c*this.ty+tx;
- this.ty = b*tx1+d*this.ty+ty;
- return this;
- };
-
- /**
- * Appends the specified matrix to this matrix.
- * This is the equivalent of multiplying `(this matrix) * (specified matrix)`.
- * @method appendMatrix
- * @param {Matrix2D} matrix
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.appendMatrix = function(matrix) {
- return this.append(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
- };
-
- /**
- * Prepends the specified matrix to this matrix.
- * This is the equivalent of multiplying `(specified matrix) * (this matrix)`.
- * For example, you could calculate the combined transformation for a child object using:
- *
- * var o = myDisplayObject;
- * var mtx = o.getMatrix();
- * while (o = o.parent) {
- * // prepend each parent's transformation in turn:
- * o.prependMatrix(o.getMatrix());
- * }
- * @method prependMatrix
- * @param {Matrix2D} matrix
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.prependMatrix = function(matrix) {
- return this.prepend(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
- };
-
- /**
- * Generates matrix properties from the specified display object transform properties, and appends them to this matrix.
- * For example, you can use this to generate a matrix representing the transformations of a display object:
- *
- * var mtx = new createjs.Matrix2D();
- * mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation);
- * @method appendTransform
- * @param {Number} x
- * @param {Number} y
- * @param {Number} scaleX
- * @param {Number} scaleY
- * @param {Number} rotation
- * @param {Number} skewX
- * @param {Number} skewY
- * @param {Number} regX Optional.
- * @param {Number} regY Optional.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.appendTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
- if (rotation%360) {
- var r = rotation*Matrix2D.DEG_TO_RAD;
- var cos = Math.cos(r);
- var sin = Math.sin(r);
- } else {
- cos = 1;
- sin = 0;
- }
-
- if (skewX || skewY) {
- // TODO: can this be combined into a single append operation?
- skewX *= Matrix2D.DEG_TO_RAD;
- skewY *= Matrix2D.DEG_TO_RAD;
- this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y);
- this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0);
- } else {
- this.append(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y);
- }
-
- if (regX || regY) {
- // append the registration offset:
- this.tx -= regX*this.a+regY*this.c;
- this.ty -= regX*this.b+regY*this.d;
- }
- return this;
- };
-
- /**
- * Generates matrix properties from the specified display object transform properties, and prepends them to this matrix.
- * For example, you could calculate the combined transformation for a child object using:
- *
- * var o = myDisplayObject;
- * var mtx = new createjs.Matrix2D();
- * do {
- * // prepend each parent's transformation in turn:
- * mtx.prependTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY);
- * } while (o = o.parent);
- *
- * Note that the above example would not account for {{#crossLink "DisplayObject/transformMatrix:property"}}{{/crossLink}}
- * values. See {{#crossLink "Matrix2D/prependMatrix"}}{{/crossLink}} for an example that does.
- * @method prependTransform
- * @param {Number} x
- * @param {Number} y
- * @param {Number} scaleX
- * @param {Number} scaleY
- * @param {Number} rotation
- * @param {Number} skewX
- * @param {Number} skewY
- * @param {Number} regX Optional.
- * @param {Number} regY Optional.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.prependTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
- if (rotation%360) {
- var r = rotation*Matrix2D.DEG_TO_RAD;
- var cos = Math.cos(r);
- var sin = Math.sin(r);
- } else {
- cos = 1;
- sin = 0;
- }
-
- if (regX || regY) {
- // prepend the registration offset:
- this.tx -= regX; this.ty -= regY;
- }
- if (skewX || skewY) {
- // TODO: can this be combined into a single prepend operation?
- skewX *= Matrix2D.DEG_TO_RAD;
- skewY *= Matrix2D.DEG_TO_RAD;
- this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, 0, 0);
- this.prepend(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), x, y);
- } else {
- this.prepend(cos*scaleX, sin*scaleX, -sin*scaleY, cos*scaleY, x, y);
- }
- return this;
- };
-
- /**
- * Applies a clockwise rotation transformation to the matrix.
- * @method rotate
- * @param {Number} angle The angle to rotate by, in degrees. To use a value in radians, multiply it by `180/Math.PI`.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.rotate = function(angle) {
- angle = angle*Matrix2D.DEG_TO_RAD;
- var cos = Math.cos(angle);
- var sin = Math.sin(angle);
-
- var a1 = this.a;
- var b1 = this.b;
-
- this.a = a1*cos+this.c*sin;
- this.b = b1*cos+this.d*sin;
- this.c = -a1*sin+this.c*cos;
- this.d = -b1*sin+this.d*cos;
- return this;
- };
-
- /**
- * Applies a skew transformation to the matrix.
- * @method skew
- * @param {Number} skewX The amount to skew horizontally in degrees. To use a value in radians, multiply it by `180/Math.PI`.
- * @param {Number} skewY The amount to skew vertically in degrees.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- */
- p.skew = function(skewX, skewY) {
- skewX = skewX*Matrix2D.DEG_TO_RAD;
- skewY = skewY*Matrix2D.DEG_TO_RAD;
- this.append(Math.cos(skewY), Math.sin(skewY), -Math.sin(skewX), Math.cos(skewX), 0, 0);
- return this;
- };
-
- /**
- * Applies a scale transformation to the matrix.
- * @method scale
- * @param {Number} x The amount to scale horizontally. E.G. a value of 2 will double the size in the X direction, and 0.5 will halve it.
- * @param {Number} y The amount to scale vertically.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.scale = function(x, y) {
- this.a *= x;
- this.b *= x;
- this.c *= y;
- this.d *= y;
- //this.tx *= x;
- //this.ty *= y;
- return this;
- };
-
- /**
- * Translates the matrix on the x and y axes.
- * @method translate
- * @param {Number} x
- * @param {Number} y
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.translate = function(x, y) {
- this.tx += this.a*x + this.c*y;
- this.ty += this.b*x + this.d*y;
- return this;
- };
-
- /**
- * Sets the properties of the matrix to those of an identity matrix (one that applies a null transformation).
- * @method identity
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.identity = function() {
- this.a = this.d = 1;
- this.b = this.c = this.tx = this.ty = 0;
- return this;
- };
-
- /**
- * Inverts the matrix, causing it to perform the opposite transformation.
- * @method invert
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- **/
- p.invert = function() {
- var a1 = this.a;
- var b1 = this.b;
- var c1 = this.c;
- var d1 = this.d;
- var tx1 = this.tx;
- var n = a1*d1-b1*c1;
-
- this.a = d1/n;
- this.b = -b1/n;
- this.c = -c1/n;
- this.d = a1/n;
- this.tx = (c1*this.ty-d1*tx1)/n;
- this.ty = -(a1*this.ty-b1*tx1)/n;
- return this;
- };
-
- /**
- * Returns true if the matrix is an identity matrix.
- * @method isIdentity
- * @return {Boolean}
- **/
- p.isIdentity = function() {
- return this.tx === 0 && this.ty === 0 && this.a === 1 && this.b === 0 && this.c === 0 && this.d === 1;
- };
-
- /**
- * Returns true if this matrix is equal to the specified matrix (all property values are equal).
- * @method equals
- * @param {Matrix2D} matrix The matrix to compare.
- * @return {Boolean}
- **/
- p.equals = function(matrix) {
- return this.tx === matrix.tx && this.ty === matrix.ty && this.a === matrix.a && this.b === matrix.b && this.c === matrix.c && this.d === matrix.d;
- };
-
- /**
- * Transforms a point according to this matrix.
- * @method transformPoint
- * @param {Number} x The x component of the point to transform.
- * @param {Number} y The y component of the point to transform.
- * @param {Point | Object} [pt] An object to copy the result into. If omitted a generic object with x/y properties will be returned.
- * @return {Point} This matrix. Useful for chaining method calls.
- **/
- p.transformPoint = function(x, y, pt) {
- pt = pt||{};
- pt.x = x*this.a+y*this.c+this.tx;
- pt.y = x*this.b+y*this.d+this.ty;
- return pt;
- };
-
- /**
- * Decomposes the matrix into transform properties (x, y, scaleX, scaleY, and rotation). Note that these values
- * may not match the transform properties you used to generate the matrix, though they will produce the same visual
- * results.
- * @method decompose
- * @param {Object} target The object to apply the transform properties to. If null, then a new object will be returned.
- * @return {Object} The target, or a new generic object with the transform properties applied.
- */
- p.decompose = function(target) {
- // TODO: it would be nice to be able to solve for whether the matrix can be decomposed into only scale/rotation even when scale is negative
- if (target == null) { target = {}; }
- target.x = this.tx;
- target.y = this.ty;
- target.scaleX = Math.sqrt(this.a * this.a + this.b * this.b);
- target.scaleY = Math.sqrt(this.c * this.c + this.d * this.d);
-
- var skewX = Math.atan2(-this.c, this.d);
- var skewY = Math.atan2(this.b, this.a);
-
- var delta = Math.abs(1-skewX/skewY);
- if (delta < 0.00001) { // effectively identical, can use rotation:
- target.rotation = skewY/Matrix2D.DEG_TO_RAD;
- if (this.a < 0 && this.d >= 0) {
- target.rotation += (target.rotation <= 0) ? 180 : -180;
- }
- target.skewX = target.skewY = 0;
- } else {
- target.skewX = skewX/Matrix2D.DEG_TO_RAD;
- target.skewY = skewY/Matrix2D.DEG_TO_RAD;
- }
- return target;
- };
-
- /**
- * Copies all properties from the specified matrix to this matrix.
- * @method copy
- * @param {Matrix2D} matrix The matrix to copy properties from.
- * @return {Matrix2D} This matrix. Useful for chaining method calls.
- */
- p.copy = function(matrix) {
- return this.setValues(matrix.a, matrix.b, matrix.c, matrix.d, matrix.tx, matrix.ty);
- };
-
- /**
- * Returns a clone of the Matrix2D instance.
- * @method clone
- * @return {Matrix2D} a clone of the Matrix2D instance.
- **/
- p.clone = function() {
- return new Matrix2D(this.a, this.b, this.c, this.d, this.tx, this.ty);
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Matrix2D (a="+this.a+" b="+this.b+" c="+this.c+" d="+this.d+" tx="+this.tx+" ty="+this.ty+")]";
- };
-
- // this has to be populated after the class is defined:
- Matrix2D.identity = new Matrix2D();
-
-
- createjs.Matrix2D = Matrix2D;
-}());
-
-//##############################################################################
-// DisplayProps.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
- /**
- * Used for calculating and encapsulating display related properties.
- * @class DisplayProps
- * @param {Number} [visible=true] Visible value.
- * @param {Number} [alpha=1] Alpha value.
- * @param {Number} [shadow=null] A Shadow instance or null.
- * @param {Number} [compositeOperation=null] A compositeOperation value or null.
- * @param {Number} [matrix] A transformation matrix. Defaults to a new identity matrix.
- * @constructor
- **/
- function DisplayProps(visible, alpha, shadow, compositeOperation, matrix) {
- this.setValues(visible, alpha, shadow, compositeOperation, matrix);
-
- // public properties:
- // assigned in the setValues method.
- /**
- * Property representing the alpha that will be applied to a display object.
- * @property alpha
- * @type Number
- **/
-
- /**
- * Property representing the shadow that will be applied to a display object.
- * @property shadow
- * @type Shadow
- **/
-
- /**
- * Property representing the compositeOperation that will be applied to a display object.
- * You can find a list of valid composite operations at:
- * https://developer.mozilla.org/en/Canvas_tutorial/Compositing
- * @property compositeOperation
- * @type String
- **/
-
- /**
- * Property representing the value for visible that will be applied to a display object.
- * @property visible
- * @type Boolean
- **/
-
- /**
- * The transformation matrix that will be applied to a display object.
- * @property matrix
- * @type Matrix2D
- **/
- }
- var p = DisplayProps.prototype;
-
-// initialization:
- /**
- * Reinitializes the instance with the specified values.
- * @method setValues
- * @param {Number} [visible=true] Visible value.
- * @param {Number} [alpha=1] Alpha value.
- * @param {Number} [shadow=null] A Shadow instance or null.
- * @param {Number} [compositeOperation=null] A compositeOperation value or null.
- * @param {Number} [matrix] A transformation matrix. Defaults to an identity matrix.
- * @return {DisplayProps} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.setValues = function (visible, alpha, shadow, compositeOperation, matrix) {
- this.visible = visible == null ? true : !!visible;
- this.alpha = alpha == null ? 1 : alpha;
- this.shadow = shadow;
- this.compositeOperation = compositeOperation;
- this.matrix = matrix || (this.matrix&&this.matrix.identity()) || new createjs.Matrix2D();
- return this;
- };
-
-// public methods:
- /**
- * Appends the specified display properties. This is generally used to apply a child's properties its parent's.
- * @method append
- * @param {Boolean} visible desired visible value
- * @param {Number} alpha desired alpha value
- * @param {Shadow} shadow desired shadow value
- * @param {String} compositeOperation desired composite operation value
- * @param {Matrix2D} [matrix] a Matrix2D instance
- * @return {DisplayProps} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.append = function(visible, alpha, shadow, compositeOperation, matrix) {
- this.alpha *= alpha;
- this.shadow = shadow || this.shadow;
- this.compositeOperation = compositeOperation || this.compositeOperation;
- this.visible = this.visible && visible;
- matrix&&this.matrix.appendMatrix(matrix);
- return this;
- };
-
- /**
- * Prepends the specified display properties. This is generally used to apply a parent's properties to a child's.
- * For example, to get the combined display properties that would be applied to a child, you could use:
- *
- * var o = myDisplayObject;
- * var props = new createjs.DisplayProps();
- * do {
- * // prepend each parent's props in turn:
- * props.prepend(o.visible, o.alpha, o.shadow, o.compositeOperation, o.getMatrix());
- * } while (o = o.parent);
- *
- * @method prepend
- * @param {Boolean} visible desired visible value
- * @param {Number} alpha desired alpha value
- * @param {Shadow} shadow desired shadow value
- * @param {String} compositeOperation desired composite operation value
- * @param {Matrix2D} [matrix] a Matrix2D instance
- * @return {DisplayProps} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.prepend = function(visible, alpha, shadow, compositeOperation, matrix) {
- this.alpha *= alpha;
- this.shadow = this.shadow || shadow;
- this.compositeOperation = this.compositeOperation || compositeOperation;
- this.visible = this.visible && visible;
- matrix&&this.matrix.prependMatrix(matrix);
- return this;
- };
-
- /**
- * Resets this instance and its matrix to default values.
- * @method identity
- * @return {DisplayProps} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.identity = function() {
- this.visible = true;
- this.alpha = 1;
- this.shadow = this.compositeOperation = null;
- this.matrix.identity();
- return this;
- };
-
- /**
- * Returns a clone of the DisplayProps instance. Clones the associated matrix.
- * @method clone
- * @return {DisplayProps} a clone of the DisplayProps instance.
- **/
- p.clone = function() {
- return new DisplayProps(this.alpha, this.shadow, this.compositeOperation, this.visible, this.matrix.clone());
- };
-
-// private methods:
-
- createjs.DisplayProps = DisplayProps;
-})();
-
-//##############################################################################
-// Point.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Represents a point on a 2 dimensional x / y coordinate system.
- *
- *
Example
- *
- * var point = new createjs.Point(0, 100);
- *
- * @class Point
- * @param {Number} [x=0] X position.
- * @param {Number} [y=0] Y position.
- * @constructor
- **/
- function Point(x, y) {
- this.setValues(x, y);
-
-
- // public properties:
- // assigned in the setValues method.
- /**
- * X position.
- * @property x
- * @type Number
- **/
-
- /**
- * Y position.
- * @property y
- * @type Number
- **/
- }
- var p = Point.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// public methods:
- /**
- * Sets the specified values on this instance.
- * @method setValues
- * @param {Number} [x=0] X position.
- * @param {Number} [y=0] Y position.
- * @return {Point} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.setValues = function(x, y) {
- this.x = x||0;
- this.y = y||0;
- return this;
- };
-
- /**
- * Copies all properties from the specified point to this point.
- * @method copy
- * @param {Point} point The point to copy properties from.
- * @return {Point} This point. Useful for chaining method calls.
- * @chainable
- */
- p.copy = function(point) {
- this.x = point.x;
- this.y = point.y;
- return this;
- };
-
- /**
- * Returns a clone of the Point instance.
- * @method clone
- * @return {Point} a clone of the Point instance.
- **/
- p.clone = function() {
- return new Point(this.x, this.y);
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Point (x="+this.x+" y="+this.y+")]";
- };
-
-
- createjs.Point = Point;
-}());
-
-//##############################################################################
-// Rectangle.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Represents a rectangle as defined by the points (x, y) and (x+width, y+height).
- *
- *
Example
- *
- * var rect = new createjs.Rectangle(0, 0, 100, 100);
- *
- * @class Rectangle
- * @param {Number} [x=0] X position.
- * @param {Number} [y=0] Y position.
- * @param {Number} [width=0] The width of the Rectangle.
- * @param {Number} [height=0] The height of the Rectangle.
- * @constructor
- **/
- function Rectangle(x, y, width, height) {
- this.setValues(x, y, width, height);
-
-
- // public properties:
- // assigned in the setValues method.
- /**
- * X position.
- * @property x
- * @type Number
- **/
-
- /**
- * Y position.
- * @property y
- * @type Number
- **/
-
- /**
- * Width.
- * @property width
- * @type Number
- **/
-
- /**
- * Height.
- * @property height
- * @type Number
- **/
- }
- var p = Rectangle.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// public methods:
- /**
- * Sets the specified values on this instance.
- * @method setValues
- * @param {Number} [x=0] X position.
- * @param {Number} [y=0] Y position.
- * @param {Number} [width=0] The width of the Rectangle.
- * @param {Number} [height=0] The height of the Rectangle.
- * @return {Rectangle} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.setValues = function(x, y, width, height) {
- // don't forget to update docs in the constructor if these change:
- this.x = x||0;
- this.y = y||0;
- this.width = width||0;
- this.height = height||0;
- return this;
- };
-
- /**
- * Extends the rectangle's bounds to include the described point or rectangle.
- * @method extend
- * @param {Number} x X position of the point or rectangle.
- * @param {Number} y Y position of the point or rectangle.
- * @param {Number} [width=0] The width of the rectangle.
- * @param {Number} [height=0] The height of the rectangle.
- * @return {Rectangle} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.extend = function(x, y, width, height) {
- width = width||0;
- height = height||0;
- if (x+width > this.x+this.width) { this.width = x+width-this.x; }
- if (y+height > this.y+this.height) { this.height = y+height-this.y; }
- if (x < this.x) { this.width += this.x-x; this.x = x; }
- if (y < this.y) { this.height += this.y-y; this.y = y; }
- return this;
- };
-
- /**
- * Adds the specified padding to the rectangle's bounds.
- * @method pad
- * @param {Number} top
- * @param {Number} left
- * @param {Number} right
- * @param {Number} bottom
- * @return {Rectangle} This instance. Useful for chaining method calls.
- * @chainable
- */
- p.pad = function(top, left, bottom, right) {
- this.x -= left;
- this.y -= top;
- this.width += left+right;
- this.height += top+bottom;
- return this;
- };
-
- /**
- * Copies all properties from the specified rectangle to this rectangle.
- * @method copy
- * @param {Rectangle} rectangle The rectangle to copy properties from.
- * @return {Rectangle} This rectangle. Useful for chaining method calls.
- * @chainable
- */
- p.copy = function(rectangle) {
- return this.setValues(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
- };
-
- /**
- * Returns true if this rectangle fully encloses the described point or rectangle.
- * @method contains
- * @param {Number} x X position of the point or rectangle.
- * @param {Number} y Y position of the point or rectangle.
- * @param {Number} [width=0] The width of the rectangle.
- * @param {Number} [height=0] The height of the rectangle.
- * @return {Boolean} True if the described point or rectangle is contained within this rectangle.
- */
- p.contains = function(x, y, width, height) {
- width = width||0;
- height = height||0;
- return (x >= this.x && x+width <= this.x+this.width && y >= this.y && y+height <= this.y+this.height);
- };
-
- /**
- * Returns a new rectangle which contains this rectangle and the specified rectangle.
- * @method union
- * @param {Rectangle} rect The rectangle to calculate a union with.
- * @return {Rectangle} A new rectangle describing the union.
- */
- p.union = function(rect) {
- return this.clone().extend(rect.x, rect.y, rect.width, rect.height);
- };
-
- /**
- * Returns a new rectangle which describes the intersection (overlap) of this rectangle and the specified rectangle,
- * or null if they do not intersect.
- * @method intersection
- * @param {Rectangle} rect The rectangle to calculate an intersection with.
- * @return {Rectangle} A new rectangle describing the intersection or null.
- */
- p.intersection = function(rect) {
- var x1 = rect.x, y1 = rect.y, x2 = x1+rect.width, y2 = y1+rect.height;
- if (this.x > x1) { x1 = this.x; }
- if (this.y > y1) { y1 = this.y; }
- if (this.x + this.width < x2) { x2 = this.x + this.width; }
- if (this.y + this.height < y2) { y2 = this.y + this.height; }
- return (x2 <= x1 || y2 <= y1) ? null : new Rectangle(x1, y1, x2-x1, y2-y1);
- };
-
- /**
- * Returns true if the specified rectangle intersects (has any overlap) with this rectangle.
- * @method intersects
- * @param {Rectangle} rect The rectangle to compare.
- * @return {Boolean} True if the rectangles intersect.
- */
- p.intersects = function(rect) {
- return (rect.x <= this.x+this.width && this.x <= rect.x+rect.width && rect.y <= this.y+this.height && this.y <= rect.y + rect.height);
- };
-
- /**
- * Returns true if the width or height are equal or less than 0.
- * @method isEmpty
- * @return {Boolean} True if the rectangle is empty.
- */
- p.isEmpty = function() {
- return this.width <= 0 || this.height <= 0;
- };
-
- /**
- * Returns a clone of the Rectangle instance.
- * @method clone
- * @return {Rectangle} a clone of the Rectangle instance.
- **/
- p.clone = function() {
- return new Rectangle(this.x, this.y, this.width, this.height);
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Rectangle (x="+this.x+" y="+this.y+" width="+this.width+" height="+this.height+")]";
- };
-
-
- createjs.Rectangle = Rectangle;
-}());
-
-//##############################################################################
-// ButtonHelper.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * The ButtonHelper is a helper class to create interactive buttons from {{#crossLink "MovieClip"}}{{/crossLink}} or
- * {{#crossLink "Sprite"}}{{/crossLink}} instances. This class will intercept mouse events from an object, and
- * automatically call {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} or {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}},
- * to the respective animation labels, add a pointer cursor, and allows the user to define a hit state frame.
- *
- * The ButtonHelper instance does not need to be added to the stage, but a reference should be maintained to prevent
- * garbage collection.
- *
- * Note that over states will not work unless you call {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}.
- *
- *
Example
- *
- * var helper = new createjs.ButtonHelper(myInstance, "out", "over", "down", false, myInstance, "hit");
- * myInstance.addEventListener("click", handleClick);
- * function handleClick(event) {
- * // Click Happened.
- * }
- *
- * @class ButtonHelper
- * @param {Sprite|MovieClip} target The instance to manage.
- * @param {String} [outLabel="out"] The label or animation to go to when the user rolls out of the button.
- * @param {String} [overLabel="over"] The label or animation to go to when the user rolls over the button.
- * @param {String} [downLabel="down"] The label or animation to go to when the user presses the button.
- * @param {Boolean} [play=false] If the helper should call "gotoAndPlay" or "gotoAndStop" on the button when changing
- * states.
- * @param {DisplayObject} [hitArea] An optional item to use as the hit state for the button. If this is not defined,
- * then the button's visible states will be used instead. Note that the same instance as the "target" argument can be
- * used for the hitState.
- * @param {String} [hitLabel] The label or animation on the hitArea instance that defines the hitArea bounds. If this is
- * null, then the default state of the hitArea will be used. *
- * @constructor
- */
- function ButtonHelper(target, outLabel, overLabel, downLabel, play, hitArea, hitLabel) {
- if (!target.addEventListener) { return; }
-
-
- // public properties:
- /**
- * The target for this button helper.
- * @property target
- * @type MovieClip | Sprite
- * @readonly
- **/
- this.target = target;
-
- /**
- * The label name or frame number to display when the user mouses out of the target. Defaults to "over".
- * @property overLabel
- * @type String | Number
- **/
- this.overLabel = overLabel == null ? "over" : overLabel;
-
- /**
- * The label name or frame number to display when the user mouses over the target. Defaults to "out".
- * @property outLabel
- * @type String | Number
- **/
- this.outLabel = outLabel == null ? "out" : outLabel;
-
- /**
- * The label name or frame number to display when the user presses on the target. Defaults to "down".
- * @property downLabel
- * @type String | Number
- **/
- this.downLabel = downLabel == null ? "down" : downLabel;
-
- /**
- * If true, then ButtonHelper will call gotoAndPlay, if false, it will use gotoAndStop. Default is false.
- * @property play
- * @default false
- * @type Boolean
- **/
- this.play = play;
-
-
- // private properties
- /**
- * @property _isPressed
- * @type Boolean
- * @protected
- **/
- this._isPressed = false;
-
- /**
- * @property _isOver
- * @type Boolean
- * @protected
- **/
- this._isOver = false;
-
- /**
- * @property _enabled
- * @type Boolean
- * @protected
- **/
- this._enabled = false;
-
- // setup:
- target.mouseChildren = false; // prevents issues when children are removed from the display list when state changes.
- this.enabled = true;
- this.handleEvent({});
- if (hitArea) {
- if (hitLabel) {
- hitArea.actionsEnabled = false;
- hitArea.gotoAndStop&&hitArea.gotoAndStop(hitLabel);
- }
- target.hitArea = hitArea;
- }
- }
- var p = ButtonHelper.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "ButtonHelper/enabled:property"}}{{/crossLink}} property instead.
- * @method setEnabled
- * @param {Boolean} value
- * @deprecated
- **/
- p.setEnabled = function(value) { // TODO: deprecated.
- if (value == this._enabled) { return; }
- var o = this.target;
- this._enabled = value;
- if (value) {
- o.cursor = "pointer";
- o.addEventListener("rollover", this);
- o.addEventListener("rollout", this);
- o.addEventListener("mousedown", this);
- o.addEventListener("pressup", this);
- if (o._reset) { o.__reset = o._reset; o._reset = this._reset;}
- } else {
- o.cursor = null;
- o.removeEventListener("rollover", this);
- o.removeEventListener("rollout", this);
- o.removeEventListener("mousedown", this);
- o.removeEventListener("pressup", this);
- if (o.__reset) { o._reset = o.__reset; delete(o.__reset); }
- }
- };
- /**
- * Use the {{#crossLink "ButtonHelper/enabled:property"}}{{/crossLink}} property instead.
- * @method getEnabled
- * @return {Boolean}
- * @deprecated
- **/
- p.getEnabled = function() {
- return this._enabled;
- };
-
- /**
- * Enables or disables the button functionality on the target.
- * @property enabled
- * @type {Boolean}
- **/
- try {
- Object.defineProperties(p, {
- enabled: { get: p.getEnabled, set: p.setEnabled }
- });
- } catch (e) {} // TODO: use Log
-
-
-// public methods:
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[ButtonHelper]";
- };
-
-
-// private methods:
- /**
- * @method handleEvent
- * @param {Object} evt The mouse event to handle.
- * @protected
- **/
- p.handleEvent = function(evt) {
- var label, t = this.target, type = evt.type;
- if (type == "mousedown") {
- this._isPressed = true;
- label = this.downLabel;
- } else if (type == "pressup") {
- this._isPressed = false;
- label = this._isOver ? this.overLabel : this.outLabel;
- } else if (type == "rollover") {
- this._isOver = true;
- label = this._isPressed ? this.downLabel : this.overLabel;
- } else { // rollout and default
- this._isOver = false;
- label = this._isPressed ? this.overLabel : this.outLabel;
- }
- if (this.play) {
- t.gotoAndPlay&&t.gotoAndPlay(label);
- } else {
- t.gotoAndStop&&t.gotoAndStop(label);
- }
- };
-
- /**
- * Injected into target. Preserves the paused state through a reset.
- * @method _reset
- * @protected
- **/
- p._reset = function() {
- // TODO: explore better ways to handle this issue. This is hacky & disrupts object signatures.
- var p = this.paused;
- this.__reset();
- this.paused = p;
- };
-
-
- createjs.ButtonHelper = ButtonHelper;
-}());
-
-//##############################################################################
-// Shadow.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * This class encapsulates the properties required to define a shadow to apply to a {{#crossLink "DisplayObject"}}{{/crossLink}}
- * via its shadow property.
- *
- *
Example
- *
- * myImage.shadow = new createjs.Shadow("#000000", 5, 5, 10);
- *
- * @class Shadow
- * @constructor
- * @param {String} color The color of the shadow. This can be any valid CSS color value.
- * @param {Number} offsetX The x offset of the shadow in pixels.
- * @param {Number} offsetY The y offset of the shadow in pixels.
- * @param {Number} blur The size of the blurring effect.
- **/
- function Shadow(color, offsetX, offsetY, blur) {
-
-
- // public properties:
- /**
- * The color of the shadow. This can be any valid CSS color value.
- * @property color
- * @type String
- * @default null
- */
- this.color = color||"black";
-
- /** The x offset of the shadow.
- * @property offsetX
- * @type Number
- * @default 0
- */
- this.offsetX = offsetX||0;
-
- /** The y offset of the shadow.
- * @property offsetY
- * @type Number
- * @default 0
- */
- this.offsetY = offsetY||0;
-
- /** The blur of the shadow.
- * @property blur
- * @type Number
- * @default 0
- */
- this.blur = blur||0;
- }
- var p = Shadow.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// static public properties:
- /**
- * An identity shadow object (all properties are set to 0).
- * @property identity
- * @type Shadow
- * @static
- * @final
- * @readonly
- **/
- Shadow.identity = new Shadow("transparent", 0, 0, 0);
-
-
-// public methods:
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Shadow]";
- };
-
- /**
- * Returns a clone of this Shadow instance.
- * @method clone
- * @return {Shadow} A clone of the current Shadow instance.
- **/
- p.clone = function() {
- return new Shadow(this.color, this.offsetX, this.offsetY, this.blur);
- };
-
-
- createjs.Shadow = Shadow;
-}());
-
-//##############################################################################
-// SpriteSheet.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Encapsulates the properties and methods associated with a sprite sheet. A sprite sheet is a series of images (usually
- * animation frames) combined into a larger image (or images). For example, an animation consisting of eight 100x100
- * images could be combined into a single 400x200 sprite sheet (4 frames across by 2 high).
- *
- * The data passed to the SpriteSheet constructor defines:
- *
- *
The source image or images to use.
- *
The positions of individual image frames.
- *
Sequences of frames that form named animations. Optional.
- *
The target playback framerate. Optional.
- *
- *
SpriteSheet Format
- * SpriteSheets are an object with two required properties (`images` and `frames`), and two optional properties
- * (`framerate` and `animations`). This makes them easy to define in javascript code, or in JSON.
- *
- *
images
- * An array of source images. Images can be either an HTMlimage
- * instance, or a uri to an image. The former is recommended to control preloading.
- *
- * images: [image1, "path/to/image2.png"],
- *
- *
frames
- * Defines the individual frames. There are two supported formats for frame data:
- * When all of the frames are the same size (in a grid), use an object with `width`, `height`, `regX`, `regY`,
- * and `count` properties.
- *
- *
- *
`width` & `height` are required and specify the dimensions of the frames
- *
`regX` & `regY` indicate the registration point or "origin" of the frames
- *
`spacing` indicate the spacing between frames
- *
`margin` specify the margin around the image(s)
- *
`count` allows you to specify the total number of frames in the spritesheet; if omitted, this will
- * be calculated based on the dimensions of the source images and the frames. Frames will be assigned
- * indexes based on their position in the source images (left to right, top to bottom).
- *
- *
- * frames: {width:64, height:64, count:20, regX: 32, regY:64, spacing:0, margin:0}
- *
- * If the frames are of different sizes, use an array of frame definitions. Each definition is itself an array
- * with 4 required and 3 optional entries, in the order:
- *
- *
- *
The first four, `x`, `y`, `width`, and `height` are required and define the frame rectangle.
- *
The fifth, `imageIndex`, specifies the index of the source image (defaults to 0)
- *
The last two, `regX` and `regY` specify the registration point of the frame
- * Optional. An object defining sequences of frames to play as named animations. Each property corresponds to an
- * animation of the same name. Each animation must specify the frames to play, and may
- * also include a relative playback `speed` (ex. 2 would playback at double speed, 0.5 at half), and
- * the name of the `next` animation to sequence to after it completes.
- *
- * There are three formats supported for defining the frames in an animation, which can be mixed and matched as appropriate:
- *
- *
for a single frame animation, you can simply specify the frame index
- *
- * animations: {
- * sit: 7
- * }
- *
- *
- *
- * for an animation of consecutive frames, you can use an array with two required, and two optional entries
- * in the order: `start`, `end`, `next`, and `speed`. This will play the frames from start to end inclusive.
- *
- * animations: {
- * // start, end, next*, speed*
- * run: [0, 8],
- * jump: [9, 12, "run", 2]
- * }
- *
- *
- *
- * for non-consecutive frames, you can use an object with a `frames` property defining an array of frame
- * indexes to play in order. The object can also specify `next` and `speed` properties.
- *
- * animations: {
- * walk: {
- * frames: [1,2,3,3,2,1]
- * },
- * shoot: {
- * frames: [1,4,5,6],
- * next: "walk",
- * speed: 0.5
- * }
- * }
- *
- *
- *
- * Note: the `speed` property was added in EaselJS 0.7.0. Earlier versions had a `frequency`
- * property instead, which was the inverse of `speed`. For example, a value of "4" would be 1/4 normal speed in
- * earlier versions, but is 4x normal speed in EaselJS 0.7.0+.
- *
- *
framerate
- * Optional. Indicates the default framerate to play this spritesheet at in frames per second. See
- * {{#crossLink "SpriteSheet/framerate:property"}}{{/crossLink}} for more information.
- *
- * framerate: 20
- *
- * Note that the Sprite framerate will only work if the stage update method is provided with the {{#crossLink "Ticker/tick:event"}}{{/crossLink}}
- * event generated by the {{#crossLink "Ticker"}}{{/crossLink}}.
- *
- * createjs.Ticker.on("tick", handleTick);
- * function handleTick(event) {
- * stage.update(event);
- * }
- *
- *
Example
- * To define a simple sprite sheet, with a single image "sprites.jpg" arranged in a regular 50x50 grid with three
- * animations: "stand" showing the first frame, "run" looping frame 1-5 inclusive, and "jump" playing frame 6-8 and
- * sequencing back to run.
- *
- * var data = {
- * images: ["sprites.jpg"],
- * frames: {width:50, height:50},
- * animations: {
- * stand:0,
- * run:[1,5],
- * jump:[6,8,"run"]
- * }
- * };
- * var spriteSheet = new createjs.SpriteSheet(data);
- * var animation = new createjs.Sprite(spriteSheet, "run");
- *
- *
Generating SpriteSheet Images
- * Spritesheets can be created manually by combining images in PhotoShop, and specifying the frame size or
- * coordinates manually, however there are a number of tools that facilitate this.
- *
- *
Exporting SpriteSheets or HTML5 content from Flash Pro supports the EaselJS SpriteSheet format.
SWF animations in Flash can be exported to SpriteSheets using
- *
- *
- *
Cross Origin Issues
- * Warning: Images loaded cross-origin will throw cross-origin security errors when interacted with
- * using:
- *
- *
a mouse
- *
methods such as {{#crossLink "Container/getObjectUnderPoint"}}{{/crossLink}}
- *
Filters (see {{#crossLink "Filter"}}{{/crossLink}})
- *
caching (see {{#crossLink "DisplayObject/cache"}}{{/crossLink}})
- *
- * You can get around this by setting `crossOrigin` property on your images before passing them to EaselJS, or
- * setting the `crossOrigin` property on PreloadJS' LoadQueue or LoadItems.
- *
- * var image = new Image();
- * img.crossOrigin="Anonymous";
- * img.src = "http://server-with-CORS-support.com/path/to/image.jpg";
- *
- * If you pass string paths to SpriteSheets, they will not work cross-origin. The server that stores the image must
- * support cross-origin requests, or this will not work. For more information, check out
- * CORS overview on MDN.
- *
- * @class SpriteSheet
- * @constructor
- * @param {Object} data An object describing the SpriteSheet data.
- * @extends EventDispatcher
- **/
- function SpriteSheet(data) {
- this.EventDispatcher_constructor();
-
-
- // public properties:
- /**
- * Indicates whether all images are finished loading.
- * @property complete
- * @type Boolean
- * @readonly
- **/
- this.complete = true;
-
- /**
- * Specifies the framerate to use by default for Sprite instances using the SpriteSheet. See the Sprite class
- * {{#crossLink "Sprite/framerate:property"}}{{/crossLink}} for more information.
- * @property framerate
- * @type Number
- **/
- this.framerate = 0;
-
-
- // private properties:
- /**
- * @property _animations
- * @protected
- * @type Array
- **/
- this._animations = null;
-
- /**
- * @property _frames
- * @protected
- * @type Array
- **/
- this._frames = null;
-
- /**
- * @property _images
- * @protected
- * @type Array
- **/
- this._images = null;
-
- /**
- * @property _data
- * @protected
- * @type Object
- **/
- this._data = null;
-
- /**
- * @property _loadCount
- * @protected
- * @type Number
- **/
- this._loadCount = 0;
-
- // only used for simple frame defs:
- /**
- * @property _frameHeight
- * @protected
- * @type Number
- **/
- this._frameHeight = 0;
-
- /**
- * @property _frameWidth
- * @protected
- * @type Number
- **/
- this._frameWidth = 0;
-
- /**
- * @property _numFrames
- * @protected
- * @type Number
- **/
- this._numFrames = 0;
-
- /**
- * @property _regX
- * @protected
- * @type Number
- **/
- this._regX = 0;
-
- /**
- * @property _regY
- * @protected
- * @type Number
- **/
- this._regY = 0;
-
- /**
- * @property _spacing
- * @protected
- * @type Number
- **/
- this._spacing = 0;
-
- /**
- * @property _margin
- * @protected
- * @type Number
- **/
- this._margin = 0;
-
- // setup:
- this._parseData(data);
- }
- var p = createjs.extend(SpriteSheet, createjs.EventDispatcher);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// events:
- /**
- * Dispatched when all images are loaded. Note that this only fires if the images
- * were not fully loaded when the sprite sheet was initialized. You should check the complete property
- * to prior to adding a listener. Ex.
- *
- * var sheet = new createjs.SpriteSheet(data);
- * if (!sheet.complete) {
- * // not preloaded, listen for the complete event:
- * sheet.addEventListener("complete", handler);
- * }
- *
- * @event complete
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.6.0
- */
-
- /**
- * Dispatched when getFrame is called with a valid frame index. This is primarily intended for use by {{#crossLink "SpriteSheetBuilder"}}{{/crossLink}}
- * when doing on-demand rendering.
- * @event getframe
- * @param {Number} index The frame index.
- * @param {Object} frame The frame object that getFrame will return.
- */
-
- /**
- * Dispatched when an image encounters an error. A SpriteSheet will dispatch an error event for each image that
- * encounters an error, and will still dispatch a {{#crossLink "SpriteSheet/complete:event"}}{{/crossLink}}
- * event once all images are finished processing, even if an error is encountered.
- * @event error
- * @param {String} src The source of the image that failed to load.
- * @since 0.8.2
- */
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "SpriteSheet/animations:property"}}{{/crossLink}} property instead.
- * @method getAnimations
- * @return {Array}
- * @deprecated
- **/
- p.getAnimations = function() {
- return this._animations.slice();
- };
-
- /**
- * Returns an array of all available animation names available on this sprite sheet as strings.
- * @property animations
- * @type {Array}
- * @readonly
- **/
- try {
- Object.defineProperties(p, {
- animations: { get: p.getAnimations }
- });
- } catch (e) {}
-
-
-// public methods:
- /**
- * Returns the total number of frames in the specified animation, or in the whole sprite
- * sheet if the animation param is omitted. Returns 0 if the spritesheet relies on calculated frame counts, and
- * the images have not been fully loaded.
- * @method getNumFrames
- * @param {String} animation The name of the animation to get a frame count for.
- * @return {Number} The number of frames in the animation, or in the entire sprite sheet if the animation param is omitted.
- */
- p.getNumFrames = function(animation) {
- if (animation == null) {
- return this._frames ? this._frames.length : this._numFrames || 0;
- } else {
- var data = this._data[animation];
- if (data == null) { return 0; }
- else { return data.frames.length; }
- }
- };
-
- /**
- * Returns an object defining the specified animation. The returned object contains:
- *
frames: an array of the frame ids in the animation
- *
speed: the playback speed for this animation
- *
name: the name of the animation
- *
next: the default animation to play next. If the animation loops, the name and next property will be the
- * same.
- *
- * @method getAnimation
- * @param {String} name The name of the animation to get.
- * @return {Object} a generic object with frames, speed, name, and next properties.
- **/
- p.getAnimation = function(name) {
- return this._data[name];
- };
-
- /**
- * Returns an object specifying the image and source rect of the specified frame. The returned object has:
- *
an image property holding a reference to the image object in which the frame is found
- *
a rect property containing a Rectangle instance which defines the boundaries for the frame within that
- * image.
- *
A regX and regY property corresponding to the regX/Y values for the frame.
- *
- * @method getFrame
- * @param {Number} frameIndex The index of the frame.
- * @return {Object} a generic object with image and rect properties. Returns null if the frame does not exist.
- **/
- p.getFrame = function(frameIndex) {
- var frame;
- if (this._frames && (frame=this._frames[frameIndex])) { return frame; }
- return null;
- };
-
- /**
- * Returns a {{#crossLink "Rectangle"}}{{/crossLink}} instance defining the bounds of the specified frame relative
- * to the origin. For example, a 90 x 70 frame with a regX of 50 and a regY of 40 would return:
- *
- * [x=-50, y=-40, width=90, height=70]
- *
- * @method getFrameBounds
- * @param {Number} frameIndex The index of the frame.
- * @param {Rectangle} [rectangle] A Rectangle instance to copy the values into. By default a new instance is created.
- * @return {Rectangle} A Rectangle instance. Returns null if the frame does not exist, or the image is not fully loaded.
- **/
- p.getFrameBounds = function(frameIndex, rectangle) {
- var frame = this.getFrame(frameIndex);
- return frame ? (rectangle||new createjs.Rectangle()).setValues(-frame.regX, -frame.regY, frame.rect.width, frame.rect.height) : null;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[SpriteSheet]";
- };
-
- /**
- * SpriteSheet cannot be cloned. A SpriteSheet can be shared by multiple Sprite instances without cloning it.
- * @method clone
- **/
- p.clone = function() {
- throw("SpriteSheet cannot be cloned.")
- };
-
-// private methods:
- /**
- * @method _parseData
- * @param {Object} data An object describing the SpriteSheet data.
- * @protected
- **/
- p._parseData = function(data) {
- var i,l,o,a;
- if (data == null) { return; }
-
- this.framerate = data.framerate||0;
-
- // parse images:
- if (data.images && (l=data.images.length) > 0) {
- a = this._images = [];
- for (i=0; i= maxFrames) { break imgLoop; }
- frameCount++;
- this._frames.push({
- image: img,
- rect: new createjs.Rectangle(x, y, frameWidth, frameHeight),
- regX: this._regX,
- regY: this._regY
- });
- x += frameWidth+spacing;
- }
- y += frameHeight+spacing;
- }
- }
- this._numFrames = frameCount;
- };
-
-
- createjs.SpriteSheet = createjs.promote(SpriteSheet, "EventDispatcher");
-}());
-
-//##############################################################################
-// Graphics.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * The Graphics class exposes an easy to use API for generating vector drawing instructions and drawing them to a
- * specified context. Note that you can use Graphics without any dependency on the EaselJS framework by calling {{#crossLink "Graphics/draw"}}{{/crossLink}}
- * directly, or it can be used with the {{#crossLink "Shape"}}{{/crossLink}} object to draw vector graphics within the
- * context of an EaselJS display list.
- *
- * There are two approaches to working with Graphics object: calling methods on a Graphics instance (the "Graphics API"), or
- * instantiating Graphics command objects and adding them to the graphics queue via {{#crossLink "Graphics/append"}}{{/crossLink}}.
- * The former abstracts the latter, simplifying beginning and ending paths, fills, and strokes.
- *
- * var g = new createjs.Graphics();
- * g.setStrokeStyle(1);
- * g.beginStroke("#000000");
- * g.beginFill("red");
- * g.drawCircle(0,0,30);
- *
- * All drawing methods in Graphics return the Graphics instance, so they can be chained together. For example,
- * the following line of code would generate the instructions to draw a rectangle with a red stroke and blue fill:
- *
- * myGraphics.beginStroke("red").beginFill("blue").drawRect(20, 20, 100, 50);
- *
- * Each graphics API call generates a command object (see below). The last command to be created can be accessed via
- * {{#crossLink "Graphics/command:property"}}{{/crossLink}}:
- *
- * var fillCommand = myGraphics.beginFill("red").command;
- * // ... later, update the fill style/color:
- * fillCommand.style = "blue";
- * // or change it to a bitmap fill:
- * fillCommand.bitmap(myImage);
- *
- * For more direct control of rendering, you can instantiate and append command objects to the graphics queue directly. In this case, you
- * need to manage path creation manually, and ensure that fill/stroke is applied to a defined path:
- *
- * // start a new path. Graphics.beginCmd is a reusable BeginPath instance:
- * myGraphics.append(createjs.Graphics.beginCmd);
- * // we need to define the path before applying the fill:
- * var circle = new createjs.Graphics.Circle(0,0,30);
- * myGraphics.append(circle);
- * // fill the path we just defined:
- * var fill = new createjs.Graphics.Fill("red");
- * myGraphics.append(fill);
- *
- * These approaches can be used together, for example to insert a custom command:
- *
- * myGraphics.beginFill("red");
- * var customCommand = new CustomSpiralCommand(etc);
- * myGraphics.append(customCommand);
- * myGraphics.beginFill("blue");
- * myGraphics.drawCircle(0, 0, 30);
- *
- * See {{#crossLink "Graphics/append"}}{{/crossLink}} for more info on creating custom commands.
- *
- *
Tiny API
- * The Graphics class also includes a "tiny API", which is one or two-letter methods that are shortcuts for all of the
- * Graphics methods. These methods are great for creating compact instructions, and is used by the Toolkit for CreateJS
- * to generate readable code. All tiny methods are marked as protected, so you can view them by enabling protected
- * descriptions in the docs.
- *
- *
- *
- * Here is the above example, using the tiny API instead.
- *
- * myGraphics.s("red").f("blue").r(20, 20, 100, 50);
- *
- * @class Graphics
- * @constructor
- **/
- function Graphics() {
-
-
- // public properties
- /**
- * Holds a reference to the last command that was created or appended. For example, you could retain a reference
- * to a Fill command in order to dynamically update the color later by using:
- *
- * var myFill = myGraphics.beginFill("red").command;
- * // update color later:
- * myFill.style = "yellow";
- *
- * @property command
- * @type Object
- **/
- this.command = null;
-
-
- // private properties
- /**
- * @property _stroke
- * @protected
- * @type {Stroke}
- **/
- this._stroke = null;
-
- /**
- * @property _strokeStyle
- * @protected
- * @type {StrokeStyle}
- **/
- this._strokeStyle = null;
-
- /**
- * @property _oldStrokeStyle
- * @protected
- * @type {StrokeStyle}
- **/
- this._oldStrokeStyle = null;
-
- /**
- * @property _strokeDash
- * @protected
- * @type {StrokeDash}
- **/
- this._strokeDash = null;
-
- /**
- * @property _oldStrokeDash
- * @protected
- * @type {StrokeDash}
- **/
- this._oldStrokeDash = null;
-
- /**
- * @property _strokeIgnoreScale
- * @protected
- * @type Boolean
- **/
- this._strokeIgnoreScale = false;
-
- /**
- * @property _fill
- * @protected
- * @type {Fill}
- **/
- this._fill = null;
-
- /**
- * @property _instructions
- * @protected
- * @type {Array}
- **/
- this._instructions = [];
-
- /**
- * Indicates the last instruction index that was committed.
- * @property _commitIndex
- * @protected
- * @type {Number}
- **/
- this._commitIndex = 0;
-
- /**
- * Uncommitted instructions.
- * @property _activeInstructions
- * @protected
- * @type {Array}
- **/
- this._activeInstructions = [];
-
- /**
- * This indicates that there have been changes to the activeInstruction list since the last updateInstructions call.
- * @property _dirty
- * @protected
- * @type {Boolean}
- * @default false
- **/
- this._dirty = false;
-
- /**
- * Index to draw from if a store operation has happened.
- * @property _storeIndex
- * @protected
- * @type {Number}
- * @default 0
- **/
- this._storeIndex = 0;
-
- // setup:
- this.clear();
- }
- var p = Graphics.prototype;
- var G = Graphics; // shortcut
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// static public methods:
- /**
- * Returns a CSS compatible color string based on the specified RGB numeric color values in the format
- * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)". For example,
- *
- * createjs.Graphics.getRGB(50, 100, 150, 0.5);
- * // Returns "rgba(50,100,150,0.5)"
- *
- * It also supports passing a single hex color value as the first param, and an optional alpha value as the second
- * param. For example,
- *
- * createjs.Graphics.getRGB(0xFF00FF, 0.2);
- * // Returns "rgba(255,0,255,0.2)"
- *
- * @method getRGB
- * @static
- * @param {Number} r The red component for the color, between 0 and 0xFF (255).
- * @param {Number} g The green component for the color, between 0 and 0xFF (255).
- * @param {Number} b The blue component for the color, between 0 and 0xFF (255).
- * @param {Number} [alpha] The alpha component for the color where 0 is fully transparent and 1 is fully opaque.
- * @return {String} A CSS compatible color string based on the specified RGB numeric color values in the format
- * "rgba(255,255,255,1.0)", or if alpha is null then in the format "rgb(255,255,255)".
- **/
- Graphics.getRGB = function(r, g, b, alpha) {
- if (r != null && b == null) {
- alpha = g;
- b = r&0xFF;
- g = r>>8&0xFF;
- r = r>>16&0xFF;
- }
- if (alpha == null) {
- return "rgb("+r+","+g+","+b+")";
- } else {
- return "rgba("+r+","+g+","+b+","+alpha+")";
- }
- };
-
- /**
- * Returns a CSS compatible color string based on the specified HSL numeric color values in the format "hsla(360,100,100,1.0)",
- * or if alpha is null then in the format "hsl(360,100,100)".
- *
- * createjs.Graphics.getHSL(150, 100, 70);
- * // Returns "hsl(150,100,70)"
- *
- * @method getHSL
- * @static
- * @param {Number} hue The hue component for the color, between 0 and 360.
- * @param {Number} saturation The saturation component for the color, between 0 and 100.
- * @param {Number} lightness The lightness component for the color, between 0 and 100.
- * @param {Number} [alpha] The alpha component for the color where 0 is fully transparent and 1 is fully opaque.
- * @return {String} A CSS compatible color string based on the specified HSL numeric color values in the format
- * "hsla(360,100,100,1.0)", or if alpha is null then in the format "hsl(360,100,100)".
- **/
- Graphics.getHSL = function(hue, saturation, lightness, alpha) {
- if (alpha == null) {
- return "hsl("+(hue%360)+","+saturation+"%,"+lightness+"%)";
- } else {
- return "hsla("+(hue%360)+","+saturation+"%,"+lightness+"%,"+alpha+")";
- }
- };
-
-
-// static properties:
- /**
- * A reusable instance of {{#crossLink "Graphics/BeginPath"}}{{/crossLink}} to avoid
- * unnecessary instantiation.
- * @property beginCmd
- * @type {Graphics.BeginPath}
- * @static
- **/
- // defined at the bottom of this file.
-
- /**
- * Map of Base64 characters to values. Used by {{#crossLink "Graphics/decodePath"}}{{/crossLink}}.
- * @property BASE_64
- * @static
- * @final
- * @readonly
- * @type {Object}
- **/
- Graphics.BASE_64 = {"A":0,"B":1,"C":2,"D":3,"E":4,"F":5,"G":6,"H":7,"I":8,"J":9,"K":10,"L":11,"M":12,"N":13,"O":14,"P":15,"Q":16,"R":17,"S":18,"T":19,"U":20,"V":21,"W":22,"X":23,"Y":24,"Z":25,"a":26,"b":27,"c":28,"d":29,"e":30,"f":31,"g":32,"h":33,"i":34,"j":35,"k":36,"l":37,"m":38,"n":39,"o":40,"p":41,"q":42,"r":43,"s":44,"t":45,"u":46,"v":47,"w":48,"x":49,"y":50,"z":51,"0":52,"1":53,"2":54,"3":55,"4":56,"5":57,"6":58,"7":59,"8":60,"9":61,"+":62,"/":63};
-
- /**
- * Maps numeric values for the caps parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to
- * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to
- * "butt", 1 to "round", and 2 to "square".
- * For example, to set the line caps to "square":
- *
- * myGraphics.ss(16, 2);
- *
- * @property STROKE_CAPS_MAP
- * @static
- * @final
- * @readonly
- * @type {Array}
- **/
- Graphics.STROKE_CAPS_MAP = ["butt", "round", "square"];
-
- /**
- * Maps numeric values for the joints parameter of {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} to
- * corresponding string values. This is primarily for use with the tiny API. The mappings are as follows: 0 to
- * "miter", 1 to "round", and 2 to "bevel".
- * For example, to set the line joints to "bevel":
- *
- * myGraphics.ss(16, 0, 2);
- *
- * @property STROKE_JOINTS_MAP
- * @static
- * @final
- * @readonly
- * @type {Array}
- **/
- Graphics.STROKE_JOINTS_MAP = ["miter", "round", "bevel"];
-
- /**
- * @property _ctx
- * @static
- * @protected
- * @type {CanvasRenderingContext2D}
- **/
- var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"));
- if (canvas.getContext) {
- Graphics._ctx = canvas.getContext("2d");
- canvas.width = canvas.height = 1;
- }
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "Graphics/instructions:property"}}{{/crossLink}} property instead.
- * @method getInstructions
- * @return {Array}
- * @deprecated
- **/
- p.getInstructions = function() {
- this._updateInstructions();
- return this._instructions;
- };
-
- /**
- * Returns the graphics instructions array. Each entry is a graphics command object (ex. Graphics.Fill, Graphics.Rect)
- * Modifying the returned array directly is not recommended, and is likely to result in unexpected behaviour.
- *
- * This property is mainly intended for introspection of the instructions (ex. for graphics export).
- * @property instructions
- * @type {Array}
- * @readonly
- **/
- try {
- Object.defineProperties(p, {
- instructions: { get: p.getInstructions }
- });
- } catch (e) {}
-
-
-// public methods:
- /**
- * Returns true if this Graphics instance has no drawing commands.
- * @method isEmpty
- * @return {Boolean} Returns true if this Graphics instance has no drawing commands.
- **/
- p.isEmpty = function() {
- return !(this._instructions.length || this._activeInstructions.length);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Object} data Optional data that is passed to graphics command exec methods. When called from a Shape instance, the shape passes itself as the data parameter. This can be used by custom graphic commands to insert contextual data.
- **/
- p.draw = function(ctx, data) {
- this._updateInstructions();
- var instr = this._instructions;
- for (var i=this._storeIndex, l=instr.length; iDisplayObject.mask to draw the clipping path, for example.
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method drawAsPath
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- **/
- p.drawAsPath = function(ctx) {
- this._updateInstructions();
- var instr, instrs = this._instructions;
- for (var i=this._storeIndex, l=instrs.length; i
- * whatwg spec.
- * @method lineTo
- * @param {Number} x The x coordinate the drawing point should draw to.
- * @param {Number} y The y coordinate the drawing point should draw to.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.lineTo = function(x, y) {
- return this.append(new G.LineTo(x,y));
- };
-
- /**
- * Draws an arc with the specified control points and radius. For detailed information, read the
- *
- * whatwg spec. A tiny API method "at" also exists.
- * @method arcTo
- * @param {Number} x1
- * @param {Number} y1
- * @param {Number} x2
- * @param {Number} y2
- * @param {Number} radius
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.arcTo = function(x1, y1, x2, y2, radius) {
- return this.append(new G.ArcTo(x1, y1, x2, y2, radius));
- };
-
- /**
- * Draws an arc defined by the radius, startAngle and endAngle arguments, centered at the position (x, y). For
- * example, to draw a full circle with a radius of 20 centered at (100, 100):
- *
- * arc(100, 100, 20, 0, Math.PI*2);
- *
- * For detailed information, read the
- * whatwg spec.
- * A tiny API method "a" also exists.
- * @method arc
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- * @param {Number} startAngle Measured in radians.
- * @param {Number} endAngle Measured in radians.
- * @param {Boolean} anticlockwise
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.arc = function(x, y, radius, startAngle, endAngle, anticlockwise) {
- return this.append(new G.Arc(x, y, radius, startAngle, endAngle, anticlockwise));
- };
-
- /**
- * Draws a quadratic curve from the current drawing point to (x, y) using the control point (cpx, cpy). For detailed
- * information, read the
- * whatwg spec. A tiny API method "qt" also exists.
- * @method quadraticCurveTo
- * @param {Number} cpx
- * @param {Number} cpy
- * @param {Number} x
- * @param {Number} y
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.quadraticCurveTo = function(cpx, cpy, x, y) {
- return this.append(new G.QuadraticCurveTo(cpx, cpy, x, y));
- };
-
- /**
- * Draws a bezier curve from the current drawing point to (x, y) using the control points (cp1x, cp1y) and (cp2x,
- * cp2y). For detailed information, read the
- *
- * whatwg spec. A tiny API method "bt" also exists.
- * @method bezierCurveTo
- * @param {Number} cp1x
- * @param {Number} cp1y
- * @param {Number} cp2x
- * @param {Number} cp2y
- * @param {Number} x
- * @param {Number} y
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.bezierCurveTo = function(cp1x, cp1y, cp2x, cp2y, x, y) {
- return this.append(new G.BezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y));
- };
-
- /**
- * Draws a rectangle at (x, y) with the specified width and height using the current fill and/or stroke.
- * For detailed information, read the
- *
- * whatwg spec. A tiny API method "r" also exists.
- * @method rect
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w Width of the rectangle
- * @param {Number} h Height of the rectangle
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.rect = function(x, y, w, h) {
- return this.append(new G.Rect(x, y, w, h));
- };
-
- /**
- * Closes the current path, effectively drawing a line from the current drawing point to the first drawing point specified
- * since the fill or stroke was last set. A tiny API method "cp" also exists.
- * @method closePath
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.closePath = function() {
- return this._activeInstructions.length ? this.append(new G.ClosePath()) : this;
- };
-
-
-// public methods that roughly map to Flash graphics APIs:
- /**
- * Clears all drawing instructions, effectively resetting this Graphics instance. Any line and fill styles will need
- * to be redefined to draw shapes following a clear call. A tiny API method "c" also exists.
- * @method clear
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.clear = function() {
- this._instructions.length = this._activeInstructions.length = this._commitIndex = 0;
- this._strokeStyle = this._oldStrokeStyle = this._stroke = this._fill = this._strokeDash = this._oldStrokeDash = null;
- this._dirty = this._strokeIgnoreScale = false;
- return this;
- };
-
- /**
- * Begins a fill with the specified color. This ends the current sub-path. A tiny API method "f" also exists.
- * @method beginFill
- * @param {String} color A CSS compatible color value (ex. "red", "#FF0000", or "rgba(255,0,0,0.5)"). Setting to
- * null will result in no fill.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginFill = function(color) {
- return this._setFill(color ? new G.Fill(color) : null);
- };
-
- /**
- * Begins a linear gradient fill defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For
- * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a
- * square to display it:
- *
- * myGraphics.beginLinearGradientFill(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120);
- *
- * A tiny API method "lf" also exists.
- * @method beginLinearGradientFill
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define a gradient
- * drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, 0.9] would draw
- * the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size.
- * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginLinearGradientFill = function(colors, ratios, x0, y0, x1, y1) {
- return this._setFill(new G.Fill().linearGradient(colors, ratios, x0, y0, x1, y1));
- };
-
- /**
- * Begins a radial gradient fill. This ends the current sub-path. For example, the following code defines a red to
- * blue radial gradient centered at (100, 100), with a radius of 50, and draws a circle to display it:
- *
- * myGraphics.beginRadialGradientFill(["#F00","#00F"], [0, 1], 100, 100, 0, 100, 100, 50).drawCircle(100, 100, 50);
- *
- * A tiny API method "rf" also exists.
- * @method beginRadialGradientFill
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 Center position of the inner circle that defines the gradient.
- * @param {Number} y0 Center position of the inner circle that defines the gradient.
- * @param {Number} r0 Radius of the inner circle that defines the gradient.
- * @param {Number} x1 Center position of the outer circle that defines the gradient.
- * @param {Number} y1 Center position of the outer circle that defines the gradient.
- * @param {Number} r1 Radius of the outer circle that defines the gradient.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginRadialGradientFill = function(colors, ratios, x0, y0, r0, x1, y1, r1) {
- return this._setFill(new G.Fill().radialGradient(colors, ratios, x0, y0, r0, x1, y1, r1));
- };
-
- /**
- * Begins a pattern fill using the specified image. This ends the current sub-path. A tiny API method "bf" also
- * exists.
- * @method beginBitmapFill
- * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use
- * as the pattern. Must be loaded prior to creating a bitmap fill, or the fill will be empty.
- * @param {String} repetition Optional. Indicates whether to repeat the image in the fill area. One of "repeat",
- * "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". Note that Firefox does not support "repeat-x" or
- * "repeat-y" (latest tests were in FF 20.0), and will default to "repeat".
- * @param {Matrix2D} matrix Optional. Specifies a transformation matrix for the bitmap fill. This transformation
- * will be applied relative to the parent transform.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginBitmapFill = function(image, repetition, matrix) {
- return this._setFill(new G.Fill(null,matrix).bitmap(image, repetition));
- };
-
- /**
- * Ends the current sub-path, and begins a new one with no fill. Functionally identical to beginFill(null).
- * A tiny API method "ef" also exists.
- * @method endFill
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.endFill = function() {
- return this.beginFill();
- };
-
- /**
- * Sets the stroke style. Like all drawing methods, this can be chained, so you can define
- * the stroke style and color in a single line of code like so:
- *
- * myGraphics.setStrokeStyle(8,"round").beginStroke("#F00");
- *
- * A tiny API method "ss" also exists.
- * @method setStrokeStyle
- * @param {Number} thickness The width of the stroke.
- * @param {String | Number} [caps=0] Indicates the type of caps to use at the end of lines. One of butt,
- * round, or square. Defaults to "butt". Also accepts the values 0 (butt), 1 (round), and 2 (square) for use with
- * the tiny API.
- * @param {String | Number} [joints=0] Specifies the type of joints that should be used where two lines meet.
- * One of bevel, round, or miter. Defaults to "miter". Also accepts the values 0 (miter), 1 (round), and 2 (bevel)
- * for use with the tiny API.
- * @param {Number} [miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which
- * controls at what point a mitered joint will be clipped.
- * @param {Boolean} [ignoreScale=false] If true, the stroke will be drawn at the specified thickness regardless
- * of active transformations.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.setStrokeStyle = function(thickness, caps, joints, miterLimit, ignoreScale) {
- this._updateInstructions(true);
- this._strokeStyle = this.command = new G.StrokeStyle(thickness, caps, joints, miterLimit, ignoreScale);
-
- // ignoreScale lives on Stroke, not StrokeStyle, so we do a little trickery:
- if (this._stroke) { this._stroke.ignoreScale = ignoreScale; }
- this._strokeIgnoreScale = ignoreScale;
- return this;
- };
-
- /**
- * Sets or clears the stroke dash pattern.
- *
- * myGraphics.setStrokeDash([20, 10], 0);
- *
- * A tiny API method `sd` also exists.
- * @method setStrokeDash
- * @param {Array} [segments] An array specifying the dash pattern, alternating between line and gap.
- * For example, `[20,10]` would create a pattern of 20 pixel lines with 10 pixel gaps between them.
- * Passing null or an empty array will clear the existing stroke dash.
- * @param {Number} [offset=0] The offset of the dash pattern. For example, you could increment this value to create a "marching ants" effect.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.setStrokeDash = function(segments, offset) {
- this._updateInstructions(true);
- this._strokeDash = this.command = new G.StrokeDash(segments, offset);
- return this;
- };
-
- /**
- * Begins a stroke with the specified color. This ends the current sub-path. A tiny API method "s" also exists.
- * @method beginStroke
- * @param {String} color A CSS compatible color value (ex. "#FF0000", "red", or "rgba(255,0,0,0.5)"). Setting to
- * null will result in no stroke.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginStroke = function(color) {
- return this._setStroke(color ? new G.Stroke(color) : null);
- };
-
- /**
- * Begins a linear gradient stroke defined by the line (x0, y0) to (x1, y1). This ends the current sub-path. For
- * example, the following code defines a black to white vertical gradient ranging from 20px to 120px, and draws a
- * square to display it:
- *
- * myGraphics.setStrokeStyle(10).
- * beginLinearGradientStroke(["#000","#FFF"], [0, 1], 0, 20, 0, 120).drawRect(20, 20, 120, 120);
- *
- * A tiny API method "ls" also exists.
- * @method beginLinearGradientStroke
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size.
- * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginLinearGradientStroke = function(colors, ratios, x0, y0, x1, y1) {
- return this._setStroke(new G.Stroke().linearGradient(colors, ratios, x0, y0, x1, y1));
- };
-
- /**
- * Begins a radial gradient stroke. This ends the current sub-path. For example, the following code defines a red to
- * blue radial gradient centered at (100, 100), with a radius of 50, and draws a rectangle to display it:
- *
- * myGraphics.setStrokeStyle(10)
- * .beginRadialGradientStroke(["#F00","#00F"], [0, 1], 100, 100, 0, 100, 100, 50)
- * .drawRect(50, 90, 150, 110);
- *
- * A tiny API method "rs" also exists.
- * @method beginRadialGradientStroke
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%, then draw the second color
- * to 100%.
- * @param {Number} x0 Center position of the inner circle that defines the gradient.
- * @param {Number} y0 Center position of the inner circle that defines the gradient.
- * @param {Number} r0 Radius of the inner circle that defines the gradient.
- * @param {Number} x1 Center position of the outer circle that defines the gradient.
- * @param {Number} y1 Center position of the outer circle that defines the gradient.
- * @param {Number} r1 Radius of the outer circle that defines the gradient.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginRadialGradientStroke = function(colors, ratios, x0, y0, r0, x1, y1, r1) {
- return this._setStroke(new G.Stroke().radialGradient(colors, ratios, x0, y0, r0, x1, y1, r1));
- };
-
- /**
- * Begins a pattern fill using the specified image. This ends the current sub-path. Note that unlike bitmap fills,
- * strokes do not currently support a matrix parameter due to limitations in the canvas API. A tiny API method "bs"
- * also exists.
- * @method beginBitmapStroke
- * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use
- * as the pattern. Must be loaded prior to creating a bitmap fill, or the fill will be empty.
- * @param {String} [repetition=repeat] Optional. Indicates whether to repeat the image in the fill area. One of
- * "repeat", "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat".
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.beginBitmapStroke = function(image, repetition) {
- // NOTE: matrix is not supported for stroke because transforms on strokes also affect the drawn stroke width.
- return this._setStroke(new G.Stroke().bitmap(image, repetition));
- };
-
- /**
- * Ends the current sub-path, and begins a new one with no stroke. Functionally identical to beginStroke(null).
- * A tiny API method "es" also exists.
- * @method endStroke
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.endStroke = function() {
- return this.beginStroke();
- };
-
- /**
- * Maps the familiar ActionScript curveTo() method to the functionally similar {{#crossLink "Graphics/quadraticCurveTo"}}{{/crossLink}}
- * method.
- * @method quadraticCurveTo
- * @param {Number} cpx
- * @param {Number} cpy
- * @param {Number} x
- * @param {Number} y
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.curveTo = p.quadraticCurveTo;
-
- /**
- *
- * Maps the familiar ActionScript drawRect() method to the functionally similar {{#crossLink "Graphics/rect"}}{{/crossLink}}
- * method.
- * @method drawRect
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w Width of the rectangle
- * @param {Number} h Height of the rectangle
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawRect = p.rect;
-
- /**
- * Draws a rounded rectangle with all corners with the specified radius.
- * @method drawRoundRect
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- * @param {Number} radius Corner radius.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawRoundRect = function(x, y, w, h, radius) {
- return this.drawRoundRectComplex(x, y, w, h, radius, radius, radius, radius);
- };
-
- /**
- * Draws a rounded rectangle with different corner radii. Supports positive and negative corner radii. A tiny API
- * method "rc" also exists.
- * @method drawRoundRectComplex
- * @param {Number} x The horizontal coordinate to draw the round rect.
- * @param {Number} y The vertical coordinate to draw the round rect.
- * @param {Number} w The width of the round rect.
- * @param {Number} h The height of the round rect.
- * @param {Number} radiusTL Top left corner radius.
- * @param {Number} radiusTR Top right corner radius.
- * @param {Number} radiusBR Bottom right corner radius.
- * @param {Number} radiusBL Bottom left corner radius.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawRoundRectComplex = function(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL) {
- return this.append(new G.RoundRect(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL));
- };
-
- /**
- * Draws a circle with the specified radius at (x, y).
- *
- * var g = new createjs.Graphics();
- * g.setStrokeStyle(1);
- * g.beginStroke(createjs.Graphics.getRGB(0,0,0));
- * g.beginFill(createjs.Graphics.getRGB(255,0,0));
- * g.drawCircle(0,0,3);
- *
- * var s = new createjs.Shape(g);
- * s.x = 100;
- * s.y = 100;
- *
- * stage.addChild(s);
- * stage.update();
- *
- * A tiny API method "dc" also exists.
- * @method drawCircle
- * @param {Number} x x coordinate center point of circle.
- * @param {Number} y y coordinate center point of circle.
- * @param {Number} radius Radius of circle.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawCircle = function(x, y, radius) {
- return this.append(new G.Circle(x, y, radius));
- };
-
- /**
- * Draws an ellipse (oval) with a specified width (w) and height (h). Similar to {{#crossLink "Graphics/drawCircle"}}{{/crossLink}},
- * except the width and height can be different. A tiny API method "de" also exists.
- * @method drawEllipse
- * @param {Number} x The left coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}
- * which draws from center.
- * @param {Number} y The top coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}
- * which draws from the center.
- * @param {Number} w The height (horizontal diameter) of the ellipse. The horizontal radius will be half of this
- * number.
- * @param {Number} h The width (vertical diameter) of the ellipse. The vertical radius will be half of this number.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawEllipse = function(x, y, w, h) {
- return this.append(new G.Ellipse(x, y, w, h));
- };
-
- /**
- * Draws a star if pointSize is greater than 0, or a regular polygon if pointSize is 0 with the specified number of
- * points. For example, the following code will draw a familiar 5 pointed star shape centered at 100, 100 and with a
- * radius of 50:
- *
- * myGraphics.beginFill("#FF0").drawPolyStar(100, 100, 50, 5, 0.6, -90);
- * // Note: -90 makes the first point vertical
- *
- * A tiny API method "dp" also exists.
- *
- * @method drawPolyStar
- * @param {Number} x Position of the center of the shape.
- * @param {Number} y Position of the center of the shape.
- * @param {Number} radius The outer radius of the shape.
- * @param {Number} sides The number of points on the star or sides on the polygon.
- * @param {Number} pointSize The depth or "pointy-ness" of the star points. A pointSize of 0 will draw a regular
- * polygon (no points), a pointSize of 1 will draw nothing because the points are infinitely pointy.
- * @param {Number} angle The angle of the first point / corner. For example a value of 0 will draw the first point
- * directly to the right of the center.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.drawPolyStar = function(x, y, radius, sides, pointSize, angle) {
- return this.append(new G.PolyStar(x, y, radius, sides, pointSize, angle));
- };
-
- // TODO: deprecated.
- /**
- * Removed in favour of using custom command objects with {{#crossLink "Graphics/append"}}{{/crossLink}}.
- * @method inject
- * @deprecated
- **/
-
- /**
- * Appends a graphics command object to the graphics queue. Command objects expose an "exec" method
- * that accepts two parameters: the Context2D to operate on, and an arbitrary data object passed into
- * {{#crossLink "Graphics/draw"}}{{/crossLink}}. The latter will usually be the Shape instance that called draw.
- *
- * This method is used internally by Graphics methods, such as drawCircle, but can also be used directly to insert
- * built-in or custom graphics commands. For example:
- *
- * // attach data to our shape, so we can access it during the draw:
- * myShape.color = "red";
- *
- * // append a Circle command object:
- * myShape.graphics.append(new createjs.Graphics.Circle(50, 50, 30));
- *
- * // append a custom command object with an exec method that sets the fill style
- * // based on the shape's data, and then fills the circle.
- * myShape.graphics.append({exec:function(ctx, shape) {
- * ctx.fillStyle = shape.color;
- * ctx.fill();
- * }});
- *
- * @method append
- * @param {Object} command A graphics command object exposing an "exec" method.
- * @param {boolean} clean The clean param is primarily for internal use. A value of true indicates that a command does not generate a path that should be stroked or filled.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.append = function(command, clean) {
- this._activeInstructions.push(command);
- this.command = command;
- if (!clean) { this._dirty = true; }
- return this;
- };
-
- /**
- * Decodes a compact encoded path string into a series of draw instructions.
- * This format is not intended to be human readable, and is meant for use by authoring tools.
- * The format uses a base64 character set, with each character representing 6 bits, to define a series of draw
- * commands.
- *
- * Each command is comprised of a single "header" character followed by a variable number of alternating x and y
- * position values. Reading the header bits from left to right (most to least significant): bits 1 to 3 specify the
- * type of operation (0-moveTo, 1-lineTo, 2-quadraticCurveTo, 3-bezierCurveTo, 4-closePath, 5-7 unused). Bit 4
- * indicates whether position values use 12 bits (2 characters) or 18 bits (3 characters), with a one indicating the
- * latter. Bits 5 and 6 are currently unused.
- *
- * Following the header is a series of 0 (closePath), 2 (moveTo, lineTo), 4 (quadraticCurveTo), or 6 (bezierCurveTo)
- * parameters. These parameters are alternating x/y positions represented by 2 or 3 characters (as indicated by the
- * 4th bit in the command char). These characters consist of a 1 bit sign (1 is negative, 0 is positive), followed
- * by an 11 (2 char) or 17 (3 char) bit integer value. All position values are in tenths of a pixel. Except in the
- * case of move operations which are absolute, this value is a delta from the previous x or y position (as
- * appropriate).
- *
- * For example, the string "A3cAAMAu4AAA" represents a line starting at -150,0 and ending at 150,0.
- * A - bits 000000. First 3 bits (000) indicate a moveTo operation. 4th bit (0) indicates 2 chars per
- * parameter.
- * n0 - 110111011100. Absolute x position of -150.0px. First bit indicates a negative value, remaining bits
- * indicate 1500 tenths of a pixel.
- * AA - 000000000000. Absolute y position of 0.
- * I - 001100. First 3 bits (001) indicate a lineTo operation. 4th bit (1) indicates 3 chars per parameter.
- * Au4 - 000000101110111000. An x delta of 300.0px, which is added to the previous x value of -150.0px to
- * provide an absolute position of +150.0px.
- * AAA - 000000000000000000. A y delta value of 0.
- *
- * A tiny API method "p" also exists.
- * @method decodePath
- * @param {String} str The path string to decode.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.decodePath = function(str) {
- var instructions = [this.moveTo, this.lineTo, this.quadraticCurveTo, this.bezierCurveTo, this.closePath];
- var paramCount = [2, 2, 4, 6, 0];
- var i=0, l=str.length;
- var params = [];
- var x=0, y=0;
- var base64 = Graphics.BASE_64;
-
- while (i>3; // highest order bits 1-3 code for operation.
- var f = instructions[fi];
- // check that we have a valid instruction & that the unused bits are empty:
- if (!f || (n&3)) { throw("bad path data (@"+i+"): "+c); }
- var pl = paramCount[fi];
- if (!fi) { x=y=0; } // move operations reset the position.
- params.length = 0;
- i++;
- var charCount = (n>>2&1)+2; // 4th header bit indicates number size for this operation.
- for (var p=0; p>5) ? -1 : 1;
- num = ((num&31)<<6)|(base64[str.charAt(i+1)]);
- if (charCount == 3) { num = (num<<6)|(base64[str.charAt(i+2)]); }
- num = sign*num/10;
- if (p%2) { x = (num += x); }
- else { y = (num += y); }
- params[p] = num;
- i += charCount;
- }
- f.apply(this,params);
- }
- return this;
- };
-
- /**
- * Stores all graphics commands so they won't be executed in future draws. Calling store() a second time adds to
- * the existing store. This also affects `drawAsPath()`.
- *
- * This is useful in cases where you are creating vector graphics in an iterative manner (ex. generative art), so
- * that only new graphics need to be drawn (which can provide huge performance benefits), but you wish to retain all
- * of the vector instructions for later use (ex. scaling, modifying, or exporting).
- *
- * Note that calling store() will force the active path (if any) to be ended in a manner similar to changing
- * the fill or stroke.
- *
- * For example, consider a application where the user draws lines with the mouse. As each line segment (or collection of
- * segments) are added to a Shape, it can be rasterized using {{#crossLink "DisplayObject/updateCache"}}{{/crossLink}},
- * and then stored, so that it can be redrawn at a different scale when the application is resized, or exported to SVG.
- *
- * // set up cache:
- * myShape.cache(0,0,500,500,scale);
- *
- * // when the user drags, draw a new line:
- * myShape.graphics.moveTo(oldX,oldY).lineTo(newX,newY);
- * // then draw it into the existing cache:
- * myShape.updateCache("source-over");
- * // store the new line, so it isn't redrawn next time:
- * myShape.store();
- *
- * // then, when the window resizes, we can re-render at a different scale:
- * // first, unstore all our lines:
- * myShape.unstore();
- * // then cache using the new scale:
- * myShape.cache(0,0,500,500,newScale);
- * // finally, store the existing commands again:
- * myShape.store();
- *
- * @method store
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.store = function() {
- this._updateInstructions(true);
- this._storeIndex = this._instructions.length;
- return this;
- };
-
- /**
- * Unstores any graphics commands that were previously stored using {{#crossLink "Graphics/store"}}{{/crossLink}}
- * so that they will be executed in subsequent draw calls.
- *
- * @method unstore
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.unstore = function() {
- this._storeIndex = 0;
- return this;
- };
-
- /**
- * Returns a clone of this Graphics instance. Note that the individual command objects are not cloned.
- * @method clone
- * @return {Graphics} A clone of the current Graphics instance.
- **/
- p.clone = function() {
- var o = new Graphics();
- o.command = this.command;
- o._stroke = this._stroke;
- o._strokeStyle = this._strokeStyle;
- o._strokeDash = this._strokeDash;
- o._strokeIgnoreScale = this._strokeIgnoreScale;
- o._fill = this._fill;
- o._instructions = this._instructions.slice();
- o._commitIndex = this._commitIndex;
- o._activeInstructions = this._activeInstructions.slice();
- o._dirty = this._dirty;
- o._storeIndex = this._storeIndex;
- return o;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Graphics]";
- };
-
-
-// tiny API:
- /**
- * Shortcut to moveTo.
- * @method mt
- * @param {Number} x The x coordinate the drawing point should move to.
- * @param {Number} y The y coordinate the drawing point should move to.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls).
- * @chainable
- * @protected
- **/
- p.mt = p.moveTo;
-
- /**
- * Shortcut to lineTo.
- * @method lt
- * @param {Number} x The x coordinate the drawing point should draw to.
- * @param {Number} y The y coordinate the drawing point should draw to.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.lt = p.lineTo;
-
- /**
- * Shortcut to arcTo.
- * @method at
- * @param {Number} x1
- * @param {Number} y1
- * @param {Number} x2
- * @param {Number} y2
- * @param {Number} radius
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.at = p.arcTo;
-
- /**
- * Shortcut to bezierCurveTo.
- * @method bt
- * @param {Number} cp1x
- * @param {Number} cp1y
- * @param {Number} cp2x
- * @param {Number} cp2y
- * @param {Number} x
- * @param {Number} y
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.bt = p.bezierCurveTo;
-
- /**
- * Shortcut to quadraticCurveTo / curveTo.
- * @method qt
- * @param {Number} cpx
- * @param {Number} cpy
- * @param {Number} x
- * @param {Number} y
- * @protected
- * @chainable
- **/
- p.qt = p.quadraticCurveTo;
-
- /**
- * Shortcut to arc.
- * @method a
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- * @param {Number} startAngle Measured in radians.
- * @param {Number} endAngle Measured in radians.
- * @param {Boolean} anticlockwise
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @protected
- * @chainable
- **/
- p.a = p.arc;
-
- /**
- * Shortcut to rect.
- * @method r
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w Width of the rectangle
- * @param {Number} h Height of the rectangle
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.r = p.rect;
-
- /**
- * Shortcut to closePath.
- * @method cp
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.cp = p.closePath;
-
- /**
- * Shortcut to clear.
- * @method c
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.c = p.clear;
-
- /**
- * Shortcut to beginFill.
- * @method f
- * @param {String} color A CSS compatible color value (ex. "red", "#FF0000", or "rgba(255,0,0,0.5)"). Setting to
- * null will result in no fill.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.f = p.beginFill;
-
- /**
- * Shortcut to beginLinearGradientFill.
- * @method lf
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define a gradient
- * drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1, 0.9] would draw
- * the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size.
- * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.lf = p.beginLinearGradientFill;
-
- /**
- * Shortcut to beginRadialGradientFill.
- * @method rf
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 Center position of the inner circle that defines the gradient.
- * @param {Number} y0 Center position of the inner circle that defines the gradient.
- * @param {Number} r0 Radius of the inner circle that defines the gradient.
- * @param {Number} x1 Center position of the outer circle that defines the gradient.
- * @param {Number} y1 Center position of the outer circle that defines the gradient.
- * @param {Number} r1 Radius of the outer circle that defines the gradient.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.rf = p.beginRadialGradientFill;
-
- /**
- * Shortcut to beginBitmapFill.
- * @method bf
- * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use
- * as the pattern.
- * @param {String} repetition Optional. Indicates whether to repeat the image in the fill area. One of "repeat",
- * "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat". Note that Firefox does not support "repeat-x" or
- * "repeat-y" (latest tests were in FF 20.0), and will default to "repeat".
- * @param {Matrix2D} matrix Optional. Specifies a transformation matrix for the bitmap fill. This transformation
- * will be applied relative to the parent transform.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.bf = p.beginBitmapFill;
-
- /**
- * Shortcut to endFill.
- * @method ef
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.ef = p.endFill;
-
- /**
- * Shortcut to setStrokeStyle.
- * @method ss
- * @param {Number} thickness The width of the stroke.
- * @param {String | Number} [caps=0] Indicates the type of caps to use at the end of lines. One of butt,
- * round, or square. Defaults to "butt". Also accepts the values 0 (butt), 1 (round), and 2 (square) for use with
- * the tiny API.
- * @param {String | Number} [joints=0] Specifies the type of joints that should be used where two lines meet.
- * One of bevel, round, or miter. Defaults to "miter". Also accepts the values 0 (miter), 1 (round), and 2 (bevel)
- * for use with the tiny API.
- * @param {Number} [miterLimit=10] If joints is set to "miter", then you can specify a miter limit ratio which
- * controls at what point a mitered joint will be clipped.
- * @param {Boolean} [ignoreScale=false] If true, the stroke will be drawn at the specified thickness regardless
- * of active transformations.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.ss = p.setStrokeStyle;
-
- /**
- * Shortcut to setStrokeDash.
- * @method sd
- * @param {Array} [segments] An array specifying the dash pattern, alternating between line and gap.
- * For example, [20,10] would create a pattern of 20 pixel lines with 10 pixel gaps between them.
- * Passing null or an empty array will clear any existing dash.
- * @param {Number} [offset=0] The offset of the dash pattern. For example, you could increment this value to create a "marching ants" effect.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.sd = p.setStrokeDash;
-
- /**
- * Shortcut to beginStroke.
- * @method s
- * @param {String} color A CSS compatible color value (ex. "#FF0000", "red", or "rgba(255,0,0,0.5)"). Setting to
- * null will result in no stroke.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.s = p.beginStroke;
-
- /**
- * Shortcut to beginLinearGradientStroke.
- * @method ls
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%.
- * @param {Number} x0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} y0 The position of the first point defining the line that defines the gradient direction and size.
- * @param {Number} x1 The position of the second point defining the line that defines the gradient direction and size.
- * @param {Number} y1 The position of the second point defining the line that defines the gradient direction and size.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.ls = p.beginLinearGradientStroke;
-
- /**
- * Shortcut to beginRadialGradientStroke.
- * @method rs
- * @param {Array} colors An array of CSS compatible color values. For example, ["#F00","#00F"] would define
- * a gradient drawing from red to blue.
- * @param {Array} ratios An array of gradient positions which correspond to the colors. For example, [0.1,
- * 0.9] would draw the first color to 10% then interpolating to the second color at 90%, then draw the second color
- * to 100%.
- * @param {Number} x0 Center position of the inner circle that defines the gradient.
- * @param {Number} y0 Center position of the inner circle that defines the gradient.
- * @param {Number} r0 Radius of the inner circle that defines the gradient.
- * @param {Number} x1 Center position of the outer circle that defines the gradient.
- * @param {Number} y1 Center position of the outer circle that defines the gradient.
- * @param {Number} r1 Radius of the outer circle that defines the gradient.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.rs = p.beginRadialGradientStroke;
-
- /**
- * Shortcut to beginBitmapStroke.
- * @method bs
- * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement} image The Image, Canvas, or Video object to use
- * as the pattern.
- * @param {String} [repetition=repeat] Optional. Indicates whether to repeat the image in the fill area. One of
- * "repeat", "repeat-x", "repeat-y", or "no-repeat". Defaults to "repeat".
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.bs = p.beginBitmapStroke;
-
- /**
- * Shortcut to endStroke.
- * @method es
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.es = p.endStroke;
-
- /**
- * Shortcut to drawRect.
- * @method dr
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w Width of the rectangle
- * @param {Number} h Height of the rectangle
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.dr = p.drawRect;
-
- /**
- * Shortcut to drawRoundRect.
- * @method rr
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- * @param {Number} radius Corner radius.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.rr = p.drawRoundRect;
-
- /**
- * Shortcut to drawRoundRectComplex.
- * @method rc
- * @param {Number} x The horizontal coordinate to draw the round rect.
- * @param {Number} y The vertical coordinate to draw the round rect.
- * @param {Number} w The width of the round rect.
- * @param {Number} h The height of the round rect.
- * @param {Number} radiusTL Top left corner radius.
- * @param {Number} radiusTR Top right corner radius.
- * @param {Number} radiusBR Bottom right corner radius.
- * @param {Number} radiusBL Bottom left corner radius.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.rc = p.drawRoundRectComplex;
-
- /**
- * Shortcut to drawCircle.
- * @method dc
- * @param {Number} x x coordinate center point of circle.
- * @param {Number} y y coordinate center point of circle.
- * @param {Number} radius Radius of circle.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.dc = p.drawCircle;
-
- /**
- * Shortcut to drawEllipse.
- * @method de
- * @param {Number} x The left coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}
- * which draws from center.
- * @param {Number} y The top coordinate point of the ellipse. Note that this is different from {{#crossLink "Graphics/drawCircle"}}{{/crossLink}}
- * which draws from the center.
- * @param {Number} w The height (horizontal diameter) of the ellipse. The horizontal radius will be half of this
- * number.
- * @param {Number} h The width (vertical diameter) of the ellipse. The vertical radius will be half of this number.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.de = p.drawEllipse;
-
- /**
- * Shortcut to drawPolyStar.
- * @method dp
- * @param {Number} x Position of the center of the shape.
- * @param {Number} y Position of the center of the shape.
- * @param {Number} radius The outer radius of the shape.
- * @param {Number} sides The number of points on the star or sides on the polygon.
- * @param {Number} pointSize The depth or "pointy-ness" of the star points. A pointSize of 0 will draw a regular
- * polygon (no points), a pointSize of 1 will draw nothing because the points are infinitely pointy.
- * @param {Number} angle The angle of the first point / corner. For example a value of 0 will draw the first point
- * directly to the right of the center.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.dp = p.drawPolyStar;
-
- /**
- * Shortcut to decodePath.
- * @method p
- * @param {String} str The path string to decode.
- * @return {Graphics} The Graphics instance the method is called on (useful for chaining calls.)
- * @chainable
- * @protected
- **/
- p.p = p.decodePath;
-
-
-// private methods:
- /**
- * @method _updateInstructions
- * @param commit
- * @protected
- **/
- p._updateInstructions = function(commit) {
- var instr = this._instructions, active = this._activeInstructions, commitIndex = this._commitIndex;
-
- if (this._dirty && active.length) {
- instr.length = commitIndex; // remove old, uncommitted commands
- instr.push(Graphics.beginCmd);
-
- var l = active.length, ll = instr.length;
- instr.length = ll+l;
- for (var i=0; i= 2) {
- var o = this.style = Graphics._ctx.createPattern(image, repetition || "");
- o.props = {image: image, repetition: repetition, type: "bitmap"};
- }
- return this;
- };
- p.path = false;
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/beginStroke"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class Stroke
- * @constructor
- * @param {Object} style A valid Context2D fillStyle.
- * @param {Boolean} ignoreScale
- **/
- /**
- * A valid Context2D strokeStyle.
- * @property style
- * @type Object
- */
- /**
- * @property ignoreScale
- * @type Boolean
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- p = (G.Stroke = function(style, ignoreScale) {
- this.style = style;
- this.ignoreScale = ignoreScale;
- }).prototype;
- p.exec = function(ctx) {
- if (!this.style) { return; }
- ctx.strokeStyle = this.style;
- if (this.ignoreScale) { ctx.save(); ctx.setTransform(1,0,0,1,0,0); }
- ctx.stroke();
- if (this.ignoreScale) { ctx.restore(); }
- };
- /**
- * Creates a linear gradient style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}.
- * See {{#crossLink "Graphics/beginLinearGradientStroke"}}{{/crossLink}} for more information.
- * @method linearGradient
- * @param {Array} colors
- * @param {Array} ratios
- * @param {Number} x0
- * @param {Number} y0
- * @param {Number} x1
- * @param {Number} y1
- * @return {Fill} Returns this Stroke object for chaining or assignment.
- */
- p.linearGradient = G.Fill.prototype.linearGradient;
- /**
- * Creates a radial gradient style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}.
- * See {{#crossLink "Graphics/beginRadialGradientStroke"}}{{/crossLink}} for more information.
- * @method radialGradient
- * @param {Array} colors
- * @param {Array} ratios
- * @param {Number} x0
- * @param {Number} y0
- * @param {Number} r0
- * @param {Number} x1
- * @param {Number} y1
- * @param {Number} r1
- * @return {Fill} Returns this Stroke object for chaining or assignment.
- */
- p.radialGradient = G.Fill.prototype.radialGradient;
- /**
- * Creates a bitmap fill style and assigns it to {{#crossLink "Stroke/style:property"}}{{/crossLink}}.
- * See {{#crossLink "Graphics/beginBitmapStroke"}}{{/crossLink}} for more information.
- * @method bitmap
- * @param {HTMLImageElement} image
- * @param {String} [repetition] One of: repeat, repeat-x, repeat-y, or no-repeat.
- * @return {Fill} Returns this Stroke object for chaining or assignment.
- */
- p.bitmap = G.Fill.prototype.bitmap;
- p.path = false;
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/setStrokeStyle"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class StrokeStyle
- * @constructor
- * @param {Number} width
- * @param {String} [caps=butt]
- * @param {String} [joints=miter]
- * @param {Number} [miterLimit=10]
- * @param {Boolean} [ignoreScale=false]
- **/
- /**
- * @property width
- * @type Number
- */
- /**
- * One of: butt, round, square
- * @property caps
- * @type String
- */
- /**
- * One of: round, bevel, miter
- * @property joints
- * @type String
- */
- /**
- * @property miterLimit
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- p = (G.StrokeStyle = function(width, caps, joints, miterLimit, ignoreScale) {
- this.width = width;
- this.caps = caps;
- this.joints = joints;
- this.miterLimit = miterLimit;
- this.ignoreScale = ignoreScale;
- }).prototype;
- p.exec = function(ctx) {
- ctx.lineWidth = (this.width == null ? "1" : this.width);
- ctx.lineCap = (this.caps == null ? "butt" : (isNaN(this.caps) ? this.caps : Graphics.STROKE_CAPS_MAP[this.caps]));
- ctx.lineJoin = (this.joints == null ? "miter" : (isNaN(this.joints) ? this.joints : Graphics.STROKE_JOINTS_MAP[this.joints]));
- ctx.miterLimit = (this.miterLimit == null ? "10" : this.miterLimit);
- ctx.ignoreScale = (this.ignoreScale == null ? false : this.ignoreScale);
- };
- p.path = false;
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/setStrokeDash"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class StrokeDash
- * @constructor
- * @param {Array} [segments]
- * @param {Number} [offset=0]
- **/
- /**
- * @property segments
- * @type Array
- */
- /**
- * @property offset
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- (G.StrokeDash = function(segments, offset) {
- this.segments = segments;
- this.offset = offset||0;
- }).prototype.exec = function(ctx) {
- if (ctx.setLineDash) { // feature detection.
- ctx.setLineDash(this.segments|| G.StrokeDash.EMPTY_SEGMENTS); // instead of [] to reduce churn.
- ctx.lineDashOffset = this.offset||0;
- }
- };
- /**
- * The default value for segments (ie. no dash).
- * @property EMPTY_SEGMENTS
- * @static
- * @final
- * @readonly
- * @protected
- * @type {Array}
- **/
- G.StrokeDash.EMPTY_SEGMENTS = [];
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/drawRoundRectComplex"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class RoundRect
- * @constructor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- * @param {Number} radiusTL
- * @param {Number} radiusTR
- * @param {Number} radiusBR
- * @param {Number} radiusBL
- **/
- /**
- * @property x
- * @type Number
- */
- /**
- * @property y
- * @type Number
- */
- /**
- * @property w
- * @type Number
- */
- /**
- * @property h
- * @type Number
- */
- /**
- * @property radiusTL
- * @type Number
- */
- /**
- * @property radiusTR
- * @type Number
- */
- /**
- * @property radiusBR
- * @type Number
- */
- /**
- * @property radiusBL
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- (G.RoundRect = function(x, y, w, h, radiusTL, radiusTR, radiusBR, radiusBL) {
- this.x = x; this.y = y;
- this.w = w; this.h = h;
- this.radiusTL = radiusTL; this.radiusTR = radiusTR;
- this.radiusBR = radiusBR; this.radiusBL = radiusBL;
- }).prototype.exec = function(ctx) {
- var max = (w max) { rTL = max; }
- if (rTR < 0) { rTR *= (mTR=-1); }
- if (rTR > max) { rTR = max; }
- if (rBR < 0) { rBR *= (mBR=-1); }
- if (rBR > max) { rBR = max; }
- if (rBL < 0) { rBL *= (mBL=-1); }
- if (rBL > max) { rBL = max; }
-
- ctx.moveTo(x+w-rTR, y);
- ctx.arcTo(x+w+rTR*mTR, y-rTR*mTR, x+w, y+rTR, rTR);
- ctx.lineTo(x+w, y+h-rBR);
- ctx.arcTo(x+w+rBR*mBR, y+h+rBR*mBR, x+w-rBR, y+h, rBR);
- ctx.lineTo(x+rBL, y+h);
- ctx.arcTo(x-rBL*mBL, y+h+rBL*mBL, x, y+h-rBL, rBL);
- ctx.lineTo(x, y+rTL);
- ctx.arcTo(x-rTL*mTL, y-rTL*mTL, x+rTL, y, rTL);
- ctx.closePath();
- };
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/drawCircle"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class Circle
- * @constructor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- **/
- /**
- * @property x
- * @type Number
- */
- /**
- * @property y
- * @type Number
- */
- /**
- * @property radius
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- (G.Circle = function(x, y, radius) {
- this.x = x; this.y = y;
- this.radius = radius;
- }).prototype.exec = function(ctx) { ctx.arc(this.x, this.y, this.radius, 0, Math.PI*2); };
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/drawEllipse"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class Ellipse
- * @constructor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} w
- * @param {Number} h
- **/
- /**
- * @property x
- * @type Number
- */
- /**
- * @property y
- * @type Number
- */
- /**
- * @property w
- * @type Number
- */
- /**
- * @property h
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- (G.Ellipse = function(x, y, w, h) {
- this.x = x; this.y = y;
- this.w = w; this.h = h;
- }).prototype.exec = function(ctx) {
- var x = this.x, y = this.y;
- var w = this.w, h = this.h;
-
- var k = 0.5522848;
- var ox = (w / 2) * k;
- var oy = (h / 2) * k;
- var xe = x + w;
- var ye = y + h;
- var xm = x + w / 2;
- var ym = y + h / 2;
-
- ctx.moveTo(x, ym);
- ctx.bezierCurveTo(x, ym-oy, xm-ox, y, xm, y);
- ctx.bezierCurveTo(xm+ox, y, xe, ym-oy, xe, ym);
- ctx.bezierCurveTo(xe, ym+oy, xm+ox, ye, xm, ye);
- ctx.bezierCurveTo(xm-ox, ye, x, ym+oy, x, ym);
- };
-
- /**
- * Graphics command object. See {{#crossLink "Graphics/drawPolyStar"}}{{/crossLink}} and {{#crossLink "Graphics/append"}}{{/crossLink}} for more information.
- * @class PolyStar
- * @constructor
- * @param {Number} x
- * @param {Number} y
- * @param {Number} radius
- * @param {Number} sides
- * @param {Number} pointSize
- * @param {Number} angle
- **/
- /**
- * @property x
- * @type Number
- */
- /**
- * @property y
- * @type Number
- */
- /**
- * @property radius
- * @type Number
- */
- /**
- * @property sides
- * @type Number
- */
- /**
- * @property pointSize
- * @type Number
- */
- /**
- * @property angle
- * @type Number
- */
- /**
- * Execute the Graphics command in the provided Canvas context.
- * @method exec
- * @param {CanvasRenderingContext2D} ctx The canvas rendering context
- */
- (G.PolyStar = function(x, y, radius, sides, pointSize, angle) {
- this.x = x; this.y = y;
- this.radius = radius;
- this.sides = sides;
- this.pointSize = pointSize;
- this.angle = angle;
- }).prototype.exec = function(ctx) {
- var x = this.x, y = this.y;
- var radius = this.radius;
- var angle = (this.angle||0)/180*Math.PI;
- var sides = this.sides;
- var ps = 1-(this.pointSize||0);
- var a = Math.PI/sides;
-
- ctx.moveTo(x+Math.cos(angle)*radius, y+Math.sin(angle)*radius);
- for (var i=0; iNote: In EaselJS 0.7.0, the mouseEnabled property will not work properly with nested Containers. Please
- * check out the latest NEXT version in GitHub for an updated version with this issue resolved. The fix will be
- * provided in the next release of EaselJS.
- * @property mouseEnabled
- * @type {Boolean}
- * @default true
- **/
- this.mouseEnabled = true;
-
- /**
- * If false, the tick will not run on this display object (or its children). This can provide some performance benefits.
- * In addition to preventing the "tick" event from being dispatched, it will also prevent tick related updates
- * on some display objects (ex. Sprite & MovieClip frame advancing, DOMElement visibility handling).
- * @property tickEnabled
- * @type Boolean
- * @default true
- **/
- this.tickEnabled = true;
-
- /**
- * An optional name for this display object. Included in {{#crossLink "DisplayObject/toString"}}{{/crossLink}} . Useful for
- * debugging.
- * @property name
- * @type {String}
- * @default null
- **/
- this.name = null;
-
- /**
- * A reference to the {{#crossLink "Container"}}{{/crossLink}} or {{#crossLink "Stage"}}{{/crossLink}} object that
- * contains this display object, or null if it has not been added
- * to one.
- * @property parent
- * @final
- * @type {Container}
- * @default null
- * @readonly
- **/
- this.parent = null;
-
- /**
- * The left offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate
- * around its center, you would set regX and {{#crossLink "DisplayObject/regY:property"}}{{/crossLink}} to 50.
- * @property regX
- * @type {Number}
- * @default 0
- **/
- this.regX = 0;
-
- /**
- * The y offset for this display object's registration point. For example, to make a 100x100px Bitmap rotate around
- * its center, you would set {{#crossLink "DisplayObject/regX:property"}}{{/crossLink}} and regY to 50.
- * @property regY
- * @type {Number}
- * @default 0
- **/
- this.regY = 0;
-
- /**
- * The rotation in degrees for this display object.
- * @property rotation
- * @type {Number}
- * @default 0
- **/
- this.rotation = 0;
-
- /**
- * The factor to stretch this display object horizontally. For example, setting scaleX to 2 will stretch the display
- * object to twice its nominal width. To horizontally flip an object, set the scale to a negative number.
- * @property scaleX
- * @type {Number}
- * @default 1
- **/
- this.scaleX = 1;
-
- /**
- * The factor to stretch this display object vertically. For example, setting scaleY to 0.5 will stretch the display
- * object to half its nominal height. To vertically flip an object, set the scale to a negative number.
- * @property scaleY
- * @type {Number}
- * @default 1
- **/
- this.scaleY = 1;
-
- /**
- * The factor to skew this display object horizontally.
- * @property skewX
- * @type {Number}
- * @default 0
- **/
- this.skewX = 0;
-
- /**
- * The factor to skew this display object vertically.
- * @property skewY
- * @type {Number}
- * @default 0
- **/
- this.skewY = 0;
-
- /**
- * A shadow object that defines the shadow to render on this display object. Set to `null` to remove a shadow. If
- * null, this property is inherited from the parent container.
- * @property shadow
- * @type {Shadow}
- * @default null
- **/
- this.shadow = null;
-
- /**
- * Indicates whether this display object should be rendered to the canvas and included when running the Stage
- * {{#crossLink "Stage/getObjectsUnderPoint"}}{{/crossLink}} method.
- * @property visible
- * @type {Boolean}
- * @default true
- **/
- this.visible = true;
-
- /**
- * The x (horizontal) position of the display object, relative to its parent.
- * @property x
- * @type {Number}
- * @default 0
- **/
- this.x = 0;
-
- /** The y (vertical) position of the display object, relative to its parent.
- * @property y
- * @type {Number}
- * @default 0
- **/
- this.y = 0;
-
- /**
- * If set, defines the transformation for this display object, overriding all other transformation properties
- * (x, y, rotation, scale, skew).
- * @property transformMatrix
- * @type {Matrix2D}
- * @default null
- **/
- this.transformMatrix = null;
-
- /**
- * The composite operation indicates how the pixels of this display object will be composited with the elements
- * behind it. If `null`, this property is inherited from the parent container. For more information, read the
- *
- * whatwg spec on compositing.
- * @property compositeOperation
- * @type {String}
- * @default null
- **/
- this.compositeOperation = null;
-
- /**
- * Indicates whether the display object should be drawn to a whole pixel when
- * {{#crossLink "Stage/snapToPixelEnabled"}}{{/crossLink}} is true. To enable/disable snapping on whole
- * categories of display objects, set this value on the prototype (Ex. Text.prototype.snapToPixel = true).
- * @property snapToPixel
- * @type {Boolean}
- * @default true
- **/
- this.snapToPixel = true;
-
- /**
- * An array of Filter objects to apply to this display object. Filters are only applied / updated when {{#crossLink "cache"}}{{/crossLink}}
- * or {{#crossLink "updateCache"}}{{/crossLink}} is called on the display object, and only apply to the area that is
- * cached.
- * @property filters
- * @type {Array}
- * @default null
- **/
- this.filters = null;
-
- /**
- * A Shape instance that defines a vector mask (clipping path) for this display object. The shape's transformation
- * will be applied relative to the display object's parent coordinates (as if it were a child of the parent).
- * @property mask
- * @type {Shape}
- * @default null
- */
- this.mask = null;
-
- /**
- * A display object that will be tested when checking mouse interactions or testing {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}.
- * The hit area will have its transformation applied relative to this display object's coordinate space (as though
- * the hit test object were a child of this display object and relative to its regX/Y). The hitArea will be tested
- * using only its own `alpha` value regardless of the alpha value on the target display object, or the target's
- * ancestors (parents).
- *
- * If set on a {{#crossLink "Container"}}{{/crossLink}}, children of the Container will not receive mouse events.
- * This is similar to setting {{#crossLink "mouseChildren"}}{{/crossLink}} to false.
- *
- * Note that hitArea is NOT currently used by the `hitTest()` method, nor is it supported for {{#crossLink "Stage"}}{{/crossLink}}.
- * @property hitArea
- * @type {DisplayObject}
- * @default null
- */
- this.hitArea = null;
-
- /**
- * A CSS cursor (ex. "pointer", "help", "text", etc) that will be displayed when the user hovers over this display
- * object. You must enable mouseover events using the {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}} method to
- * use this property. Setting a non-null cursor on a Container will override the cursor set on its descendants.
- * @property cursor
- * @type {String}
- * @default null
- */
- this.cursor = null;
-
-
- // private properties:
- /**
- * @property _cacheOffsetX
- * @protected
- * @type {Number}
- * @default 0
- **/
- this._cacheOffsetX = 0;
-
- /**
- * @property _cacheOffsetY
- * @protected
- * @type {Number}
- * @default 0
- **/
- this._cacheOffsetY = 0;
-
- /**
- * @property _filterOffsetX
- * @protected
- * @type {Number}
- * @default 0
- **/
- this._filterOffsetX = 0;
-
- /**
- * @property _filterOffsetY
- * @protected
- * @type {Number}
- * @default 0
- **/
- this._filterOffsetY = 0;
-
- /**
- * @property _cacheScale
- * @protected
- * @type {Number}
- * @default 1
- **/
- this._cacheScale = 1;
-
- /**
- * @property _cacheDataURLID
- * @protected
- * @type {Number}
- * @default 0
- */
- this._cacheDataURLID = 0;
-
- /**
- * @property _cacheDataURL
- * @protected
- * @type {String}
- * @default null
- */
- this._cacheDataURL = null;
-
- /**
- * @property _props
- * @protected
- * @type {DisplayObject}
- * @default null
- **/
- this._props = new createjs.DisplayProps();
-
- /**
- * @property _rectangle
- * @protected
- * @type {Rectangle}
- * @default null
- **/
- this._rectangle = new createjs.Rectangle();
-
- /**
- * @property _bounds
- * @protected
- * @type {Rectangle}
- * @default null
- **/
- this._bounds = null;
- }
- var p = createjs.extend(DisplayObject, createjs.EventDispatcher);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-// static properties:
- /**
- * Listing of mouse event names. Used in _hasMouseEventListener.
- * @property _MOUSE_EVENTS
- * @protected
- * @static
- * @type {Array}
- **/
- DisplayObject._MOUSE_EVENTS = ["click","dblclick","mousedown","mouseout","mouseover","pressmove","pressup","rollout","rollover"];
-
- /**
- * Suppresses errors generated when using features like hitTest, mouse events, and {{#crossLink "getObjectsUnderPoint"}}{{/crossLink}}
- * with cross domain content.
- * @property suppressCrossDomainErrors
- * @static
- * @type {Boolean}
- * @default false
- **/
- DisplayObject.suppressCrossDomainErrors = false;
-
- /**
- * @property _snapToPixelEnabled
- * @protected
- * @static
- * @type {Boolean}
- * @default false
- **/
- DisplayObject._snapToPixelEnabled = false; // stage.snapToPixelEnabled is temporarily copied here during a draw to provide global access.
-
- /**
- * @property _hitTestCanvas
- * @type {HTMLCanvasElement | Object}
- * @static
- * @protected
- **/
- /**
- * @property _hitTestContext
- * @type {CanvasRenderingContext2D}
- * @static
- * @protected
- **/
- var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); // prevent errors on load in browsers without canvas.
- if (canvas.getContext) {
- DisplayObject._hitTestCanvas = canvas;
- DisplayObject._hitTestContext = canvas.getContext("2d");
- canvas.width = canvas.height = 1;
- }
-
- /**
- * @property _nextCacheID
- * @type {Number}
- * @static
- * @protected
- **/
- DisplayObject._nextCacheID = 1;
-
-
-// events:
- /**
- * Dispatched when the user presses their left mouse button over the display object. See the
- * {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event mousedown
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user presses their left mouse button and then releases it while over the display object.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event click
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user double clicks their left mouse button over this display object.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event dblclick
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user's mouse enters this display object. This event must be enabled using
- * {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollover:event"}}{{/crossLink}}.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event mouseover
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user's mouse leaves this display object. This event must be enabled using
- * {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}. See also {{#crossLink "DisplayObject/rollout:event"}}{{/crossLink}}.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event mouseout
- * @since 0.6.0
- */
-
- /**
- * This event is similar to {{#crossLink "DisplayObject/mouseover:event"}}{{/crossLink}}, with the following
- * differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an
- * aggregate of their content.
- *
- * For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over
- * shapeA and then directly on to shapeB. With a listener for {{#crossLink "mouseover:event"}}{{/crossLink}} on
- * myContainer, two events would be received, each targeting a child element:
- *
when the mouse enters shapeA (target=shapeA)
- *
when the mouse enters shapeB (target=shapeB)
- *
- * However, with a listener for "rollover" instead, only a single event is received when the mouse first enters
- * the aggregate myContainer content (target=myContainer).
- *
- * This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event rollover
- * @since 0.7.0
- */
-
- /**
- * This event is similar to {{#crossLink "DisplayObject/mouseout:event"}}{{/crossLink}}, with the following
- * differences: it does not bubble, and it considers {{#crossLink "Container"}}{{/crossLink}} instances as an
- * aggregate of their content.
- *
- * For example, myContainer contains two overlapping children: shapeA and shapeB. The user moves their mouse over
- * shapeA, then directly on to shapeB, then off both. With a listener for {{#crossLink "mouseout:event"}}{{/crossLink}}
- * on myContainer, two events would be received, each targeting a child element:
- *
when the mouse leaves shapeA (target=shapeA)
- *
when the mouse leaves shapeB (target=shapeB)
- *
- * However, with a listener for "rollout" instead, only a single event is received when the mouse leaves
- * the aggregate myContainer content (target=myContainer).
- *
- * This event must be enabled using {{#crossLink "Stage/enableMouseOver"}}{{/crossLink}}.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event rollout
- * @since 0.7.0
- */
-
- /**
- * After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressmove
- * event will be generated on that object whenever the mouse moves until the mouse press is released. This can be
- * useful for dragging and similar operations.
- * @event pressmove
- * @since 0.7.0
- */
-
- /**
- * After a {{#crossLink "DisplayObject/mousedown:event"}}{{/crossLink}} occurs on a display object, a pressup event
- * will be generated on that object when that mouse press is released. This can be useful for dragging and similar
- * operations.
- * @event pressup
- * @since 0.7.0
- */
-
- /**
- * Dispatched when the display object is added to a parent container.
- * @event added
- */
-
- /**
- * Dispatched when the display object is removed from its parent container.
- * @event removed
- */
-
- /**
- * Dispatched on each display object on a stage whenever the stage updates. This occurs immediately before the
- * rendering (draw) pass. When {{#crossLink "Stage/update"}}{{/crossLink}} is called, first all display objects on
- * the stage dispatch the tick event, then all of the display objects are drawn to stage. Children will have their
- * {{#crossLink "tick:event"}}{{/crossLink}} event dispatched in order of their depth prior to the event being
- * dispatched on their parent.
- * @event tick
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {Array} params An array containing any arguments that were passed to the Stage.update() method. For
- * example if you called stage.update("hello"), then the params would be ["hello"].
- * @since 0.6.0
- */
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "DisplayObject/stage:property"}}{{/crossLink}} property instead.
- * @method getStage
- * @return {Stage}
- * @deprecated
- **/
- p.getStage = function() {
- // uses dynamic access to avoid circular dependencies;
- var o = this, _Stage = createjs["Stage"];
- while (o.parent) { o = o.parent; }
- if (o instanceof _Stage) { return o; }
- return null;
- };
-
- /**
- * Returns the Stage instance that this display object will be rendered on, or null if it has not been added to one.
- * @property stage
- * @type {Stage}
- * @readonly
- **/
- try {
- Object.defineProperties(p, {
- stage: { get: p.getStage }
- });
- } catch (e) {}
-
-
-// public methods:
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. For example,
- * used for drawing the cache (to prevent it from simply drawing an existing cache back into itself).
- * @return {Boolean}
- **/
- p.draw = function(ctx, ignoreCache) {
- var cacheCanvas = this.cacheCanvas;
- if (ignoreCache || !cacheCanvas) { return false; }
- var scale = this._cacheScale;
- ctx.drawImage(cacheCanvas, this._cacheOffsetX+this._filterOffsetX, this._cacheOffsetY+this._filterOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale);
- return true;
- };
-
- /**
- * Applies this display object's transformation, alpha, globalCompositeOperation, clipping path (mask), and shadow
- * to the specified context. This is typically called prior to {{#crossLink "DisplayObject/draw"}}{{/crossLink}}.
- * @method updateContext
- * @param {CanvasRenderingContext2D} ctx The canvas 2D to update.
- **/
- p.updateContext = function(ctx) {
- var o=this, mask=o.mask, mtx= o._props.matrix;
-
- if (mask && mask.graphics && !mask.graphics.isEmpty()) {
- mask.getMatrix(mtx);
- ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
-
- mask.graphics.drawAsPath(ctx);
- ctx.clip();
-
- mtx.invert();
- ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx, mtx.ty);
- }
-
- this.getMatrix(mtx);
- var tx = mtx.tx, ty = mtx.ty;
- if (DisplayObject._snapToPixelEnabled && o.snapToPixel) {
- tx = tx + (tx < 0 ? -0.5 : 0.5) | 0;
- ty = ty + (ty < 0 ? -0.5 : 0.5) | 0;
- }
- ctx.transform(mtx.a, mtx.b, mtx.c, mtx.d, tx, ty);
- ctx.globalAlpha *= o.alpha;
- if (o.compositeOperation) { ctx.globalCompositeOperation = o.compositeOperation; }
- if (o.shadow) { this._applyShadow(ctx, o.shadow); }
- };
-
- /**
- * Draws the display object into a new canvas, which is then used for subsequent draws. For complex content
- * that does not change frequently (ex. a Container with many children that do not move, or a complex vector Shape),
- * this can provide for much faster rendering because the content does not need to be re-rendered each tick. The
- * cached display object can be moved, rotated, faded, etc freely, however if its content changes, you must
- * manually update the cache by calling updateCache() or cache() again. You must specify
- * the cache area via the x, y, w, and h parameters. This defines the rectangle that will be rendered and cached
- * using this display object's coordinates.
- *
- *
Example
- * For example if you defined a Shape that drew a circle at 0, 0 with a radius of 25:
- *
- * var shape = new createjs.Shape();
- * shape.graphics.beginFill("#ff0000").drawCircle(0, 0, 25);
- * myShape.cache(-25, -25, 50, 50);
- *
- * Note that filters need to be defined before the cache is applied. Check out the {{#crossLink "Filter"}}{{/crossLink}}
- * class for more information. Some filters (ex. BlurFilter) will not work as expected in conjunction with the scale param.
- *
- * Usually, the resulting cacheCanvas will have the dimensions width*scale by height*scale, however some filters (ex. BlurFilter)
- * will add padding to the canvas dimensions.
- *
- * @method cache
- * @param {Number} x The x coordinate origin for the cache region.
- * @param {Number} y The y coordinate origin for the cache region.
- * @param {Number} width The width of the cache region.
- * @param {Number} height The height of the cache region.
- * @param {Number} [scale=1] The scale at which the cache will be created. For example, if you cache a vector shape using
- * myShape.cache(0,0,100,100,2) then the resulting cacheCanvas will be 200x200 px. This lets you scale and rotate
- * cached elements with greater fidelity. Default is 1.
- **/
- p.cache = function(x, y, width, height, scale) {
- // draw to canvas.
- scale = scale||1;
- if (!this.cacheCanvas) { this.cacheCanvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); }
- this._cacheWidth = width;
- this._cacheHeight = height;
- this._cacheOffsetX = x;
- this._cacheOffsetY = y;
- this._cacheScale = scale;
- this.updateCache();
- };
-
- /**
- * Redraws the display object to its cache. Calling updateCache without an active cache will throw an error.
- * If compositeOperation is null the current cache will be cleared prior to drawing. Otherwise the display object
- * will be drawn over the existing cache using the specified compositeOperation.
- *
- *
Example
- * Clear the current graphics of a cached shape, draw some new instructions, and then update the cache. The new line
- * will be drawn on top of the old one.
- *
- * // Not shown: Creating the shape, and caching it.
- * shapeInstance.clear();
- * shapeInstance.setStrokeStyle(3).beginStroke("#ff0000").moveTo(100, 100).lineTo(200,200);
- * shapeInstance.updateCache();
- *
- * @method updateCache
- * @param {String} compositeOperation The compositeOperation to use, or null to clear the cache and redraw it.
- *
- * whatwg spec on compositing.
- **/
- p.updateCache = function(compositeOperation) {
- var cacheCanvas = this.cacheCanvas;
- if (!cacheCanvas) { throw "cache() must be called before updateCache()"; }
- var scale = this._cacheScale, offX = this._cacheOffsetX*scale, offY = this._cacheOffsetY*scale;
- var w = this._cacheWidth, h = this._cacheHeight, ctx = cacheCanvas.getContext("2d");
-
- var fBounds = this._getFilterBounds();
- offX += (this._filterOffsetX = fBounds.x);
- offY += (this._filterOffsetY = fBounds.y);
-
- w = Math.ceil(w*scale) + fBounds.width;
- h = Math.ceil(h*scale) + fBounds.height;
- if (w != cacheCanvas.width || h != cacheCanvas.height) {
- // TODO: it would be nice to preserve the content if there is a compositeOperation.
- cacheCanvas.width = w;
- cacheCanvas.height = h;
- } else if (!compositeOperation) {
- ctx.clearRect(0, 0, w+1, h+1);
- }
-
- ctx.save();
- ctx.globalCompositeOperation = compositeOperation;
- ctx.setTransform(scale, 0, 0, scale, -offX, -offY);
- this.draw(ctx, true);
- // TODO: filters and cache scale don't play well together at present.
- this._applyFilters();
- ctx.restore();
- this.cacheID = DisplayObject._nextCacheID++;
- };
-
- /**
- * Clears the current cache. See {{#crossLink "DisplayObject/cache"}}{{/crossLink}} for more information.
- * @method uncache
- **/
- p.uncache = function() {
- this._cacheDataURL = this.cacheCanvas = null;
- this.cacheID = this._cacheOffsetX = this._cacheOffsetY = this._filterOffsetX = this._filterOffsetY = 0;
- this._cacheScale = 1;
- };
-
- /**
- * Returns a data URL for the cache, or null if this display object is not cached.
- * Uses cacheID to ensure a new data URL is not generated if the cache has not changed.
- * @method getCacheDataURL
- * @return {String} The image data url for the cache.
- **/
- p.getCacheDataURL = function() {
- if (!this.cacheCanvas) { return null; }
- if (this.cacheID != this._cacheDataURLID) { this._cacheDataURL = this.cacheCanvas.toDataURL(); }
- return this._cacheDataURL;
- };
-
- /**
- * Transforms the specified x and y position from the coordinate space of the display object
- * to the global (stage) coordinate space. For example, this could be used to position an HTML label
- * over a specific point on a nested display object. Returns a Point instance with x and y properties
- * correlating to the transformed coordinates on the stage.
- *
- *
Example
- *
- * displayObject.x = 300;
- * displayObject.y = 200;
- * stage.addChild(displayObject);
- * var point = displayObject.localToGlobal(100, 100);
- * // Results in x=400, y=300
- *
- * @method localToGlobal
- * @param {Number} x The x position in the source display object to transform.
- * @param {Number} y The y position in the source display object to transform.
- * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
- * @return {Point} A Point instance with x and y properties correlating to the transformed coordinates
- * on the stage.
- **/
- p.localToGlobal = function(x, y, pt) {
- return this.getConcatenatedMatrix(this._props.matrix).transformPoint(x,y, pt||new createjs.Point());
- };
-
- /**
- * Transforms the specified x and y position from the global (stage) coordinate space to the
- * coordinate space of the display object. For example, this could be used to determine
- * the current mouse position within the display object. Returns a Point instance with x and y properties
- * correlating to the transformed position in the display object's coordinate space.
- *
- *
Example
- *
- * displayObject.x = 300;
- * displayObject.y = 200;
- * stage.addChild(displayObject);
- * var point = displayObject.globalToLocal(100, 100);
- * // Results in x=-200, y=-100
- *
- * @method globalToLocal
- * @param {Number} x The x position on the stage to transform.
- * @param {Number} y The y position on the stage to transform.
- * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
- * @return {Point} A Point instance with x and y properties correlating to the transformed position in the
- * display object's coordinate space.
- **/
- p.globalToLocal = function(x, y, pt) {
- return this.getConcatenatedMatrix(this._props.matrix).invert().transformPoint(x,y, pt||new createjs.Point());
- };
-
- /**
- * Transforms the specified x and y position from the coordinate space of this display object to the coordinate
- * space of the target display object. Returns a Point instance with x and y properties correlating to the
- * transformed position in the target's coordinate space. Effectively the same as using the following code with
- * {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}} and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}.
- *
- * var pt = this.localToGlobal(x, y);
- * pt = target.globalToLocal(pt.x, pt.y);
- *
- * @method localToLocal
- * @param {Number} x The x position in the source display object to transform.
- * @param {Number} y The y position on the source display object to transform.
- * @param {DisplayObject} target The target display object to which the coordinates will be transformed.
- * @param {Point | Object} [pt] An object to copy the result into. If omitted a new Point object with x/y properties will be returned.
- * @return {Point} Returns a Point instance with x and y properties correlating to the transformed position
- * in the target's coordinate space.
- **/
- p.localToLocal = function(x, y, target, pt) {
- pt = this.localToGlobal(x, y, pt);
- return target.globalToLocal(pt.x, pt.y, pt);
- };
-
- /**
- * Shortcut method to quickly set the transform properties on the display object. All parameters are optional.
- * Omitted parameters will have the default value set.
- *
- *
Example
- *
- * displayObject.setTransform(100, 100, 2, 2);
- *
- * @method setTransform
- * @param {Number} [x=0] The horizontal translation (x position) in pixels
- * @param {Number} [y=0] The vertical translation (y position) in pixels
- * @param {Number} [scaleX=1] The horizontal scale, as a percentage of 1
- * @param {Number} [scaleY=1] the vertical scale, as a percentage of 1
- * @param {Number} [rotation=0] The rotation, in degrees
- * @param {Number} [skewX=0] The horizontal skew factor
- * @param {Number} [skewY=0] The vertical skew factor
- * @param {Number} [regX=0] The horizontal registration point in pixels
- * @param {Number} [regY=0] The vertical registration point in pixels
- * @return {DisplayObject} Returns this instance. Useful for chaining commands.
- * @chainable
- */
- p.setTransform = function(x, y, scaleX, scaleY, rotation, skewX, skewY, regX, regY) {
- this.x = x || 0;
- this.y = y || 0;
- this.scaleX = scaleX == null ? 1 : scaleX;
- this.scaleY = scaleY == null ? 1 : scaleY;
- this.rotation = rotation || 0;
- this.skewX = skewX || 0;
- this.skewY = skewY || 0;
- this.regX = regX || 0;
- this.regY = regY || 0;
- return this;
- };
-
- /**
- * Returns a matrix based on this object's current transform.
- * @method getMatrix
- * @param {Matrix2D} matrix Optional. A Matrix2D object to populate with the calculated values. If null, a new
- * Matrix object is returned.
- * @return {Matrix2D} A matrix representing this display object's transform.
- **/
- p.getMatrix = function(matrix) {
- var o = this, mtx = matrix&&matrix.identity() || new createjs.Matrix2D();
- return o.transformMatrix ? mtx.copy(o.transformMatrix) : mtx.appendTransform(o.x, o.y, o.scaleX, o.scaleY, o.rotation, o.skewX, o.skewY, o.regX, o.regY);
- };
-
- /**
- * Generates a Matrix2D object representing the combined transform of the display object and all of its
- * parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}). This can
- * be used to transform positions between coordinate spaces, such as with {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}}
- * and {{#crossLink "DisplayObject/globalToLocal"}}{{/crossLink}}.
- * @method getConcatenatedMatrix
- * @param {Matrix2D} [matrix] A {{#crossLink "Matrix2D"}}{{/crossLink}} object to populate with the calculated values.
- * If null, a new Matrix2D object is returned.
- * @return {Matrix2D} The combined matrix.
- **/
- p.getConcatenatedMatrix = function(matrix) {
- var o = this, mtx = this.getMatrix(matrix);
- while (o = o.parent) {
- mtx.prependMatrix(o.getMatrix(o._props.matrix));
- }
- return mtx;
- };
-
- /**
- * Generates a DisplayProps object representing the combined display properties of the object and all of its
- * parent Containers up to the highest level ancestor (usually the {{#crossLink "Stage"}}{{/crossLink}}).
- * @method getConcatenatedDisplayProps
- * @param {DisplayProps} [props] A {{#crossLink "DisplayProps"}}{{/crossLink}} object to populate with the calculated values.
- * If null, a new DisplayProps object is returned.
- * @return {DisplayProps} The combined display properties.
- **/
- p.getConcatenatedDisplayProps = function(props) {
- props = props ? props.identity() : new createjs.DisplayProps();
- var o = this, mtx = o.getMatrix(props.matrix);
- do {
- props.prepend(o.visible, o.alpha, o.shadow, o.compositeOperation);
-
- // we do this to avoid problems with the matrix being used for both operations when o._props.matrix is passed in as the props param.
- // this could be simplified (ie. just done as part of the prepend above) if we switched to using a pool.
- if (o != this) { mtx.prependMatrix(o.getMatrix(o._props.matrix)); }
- } while (o = o.parent);
- return props;
- };
-
- /**
- * Tests whether the display object intersects the specified point in local coordinates (ie. draws a pixel
- * with alpha > 0 at the specified position). This ignores the alpha, shadow, hitArea, mask, and compositeOperation
- * of the display object.
- *
- *
Example
- *
- * var myShape = new createjs.Shape();
- * myShape.graphics.beginFill("red").drawRect(100, 100, 20, 50);
- *
- * console.log(myShape.hitTest(10,10); // false
- * console.log(myShape.hitTest(110, 25); // true
- *
- * Note that to use Stage coordinates (such as {{#crossLink "Stage/mouseX:property"}}{{/crossLink}}), they must
- * first be converted to local coordinates:
- *
- * stage.addEventListener("stagemousedown", handleMouseDown);
- * function handleMouseDown(event) {
- * var p = myShape.globalToLocal(stage.mouseX, stage.mouseY);
- * var hit = myShape.hitTest(p.x, p.y);
- * }
- *
- * Shape-to-shape collision is not currently supported by EaselJS.
- *
- * @method hitTest
- * @param {Number} x The x position to check in the display object's local coordinates.
- * @param {Number} y The y position to check in the display object's local coordinates.
- * @return {Boolean} A Boolean indicating whether a visible portion of the DisplayObject intersect the specified
- * local Point.
- */
- p.hitTest = function(x, y) {
- var ctx = DisplayObject._hitTestContext;
- ctx.setTransform(1, 0, 0, 1, -x, -y);
- this.draw(ctx);
-
- var hit = this._testHit(ctx);
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.clearRect(0, 0, 2, 2);
- return hit;
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- *
Example
- *
- * var myGraphics = new createjs.Graphics().beginFill("#ff0000").drawCircle(0, 0, 25);
- * var shape = stage.addChild(new createjs.Shape()).set({graphics:myGraphics, x:100, y:100, alpha:0.5});
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the DisplayObject instance.
- * @return {DisplayObject} Returns the instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- /**
- * Returns a rectangle representing this object's bounds in its local coordinate system (ie. with no transformation).
- * Objects that have been cached will return the bounds of the cache.
- *
- * Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use
- * {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container
- * bounds.
- *
- *
- *
All
- * All display objects support setting bounds manually using setBounds(). Likewise, display objects that
- * have been cached using cache() will return the bounds of their cache. Manual and cache bounds will override
- * the automatic calculations listed below.
- *
- *
Bitmap
- * Returns the width and height of the sourceRect (if specified) or image, extending from (x=0,y=0).
- *
- *
Sprite
- * Returns the bounds of the current frame. May have non-zero x/y if a frame registration point was specified
- * in the spritesheet data. See also {{#crossLink "SpriteSheet/getFrameBounds"}}{{/crossLink}}
- *
- *
Container
- * Returns the aggregate (combined) bounds of all children that return a non-null value from getBounds().
- *
- *
Shape
- * Does not currently support automatic bounds calculations. Use setBounds() to manually define bounds.
- *
- *
Text
- * Returns approximate bounds. Horizontal values (x/width) are quite accurate, but vertical values (y/height) are
- * not, especially when using textBaseline values other than "top".
- *
- *
BitmapText
- * Returns approximate bounds. Values will be more accurate if spritesheet frame registration points are close
- * to (x=0,y=0).
- *
- *
- *
- * Bounds can be expensive to calculate for some objects (ex. text, or containers with many children), and
- * are recalculated each time you call getBounds(). You can prevent recalculation on static objects by setting the
- * bounds explicitly:
- *
- * var bounds = obj.getBounds();
- * obj.setBounds(bounds.x, bounds.y, bounds.width, bounds.height);
- * // getBounds will now use the set values, instead of recalculating
- *
- * To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its
- * values if you need to retain it.
- *
- * var myBounds = obj.getBounds().clone();
- * // OR:
- * myRect.copy(obj.getBounds());
- *
- * @method getBounds
- * @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this
- * object.
- **/
- p.getBounds = function() {
- if (this._bounds) { return this._rectangle.copy(this._bounds); }
- var cacheCanvas = this.cacheCanvas;
- if (cacheCanvas) {
- var scale = this._cacheScale;
- return this._rectangle.setValues(this._cacheOffsetX, this._cacheOffsetY, cacheCanvas.width/scale, cacheCanvas.height/scale);
- }
- return null;
- };
-
- /**
- * Returns a rectangle representing this object's bounds in its parent's coordinate system (ie. with transformations applied).
- * Objects that have been cached will return the transformed bounds of the cache.
- *
- * Not all display objects can calculate their own bounds (ex. Shape). For these objects, you can use
- * {{#crossLink "DisplayObject/setBounds"}}{{/crossLink}} so that they are included when calculating Container
- * bounds.
- *
- * To reduce memory impact, the returned Rectangle instance may be reused internally; clone the instance or copy its
- * values if you need to retain it.
- *
- * Container instances calculate aggregate bounds for all children that return bounds via getBounds.
- * @method getTransformedBounds
- * @return {Rectangle} A Rectangle instance representing the bounds, or null if bounds are not available for this object.
- **/
- p.getTransformedBounds = function() {
- return this._getBounds();
- };
-
- /**
- * Allows you to manually specify the bounds of an object that either cannot calculate their own bounds (ex. Shape &
- * Text) for future reference, or so the object can be included in Container bounds. Manually set bounds will always
- * override calculated bounds.
- *
- * The bounds should be specified in the object's local (untransformed) coordinates. For example, a Shape instance
- * with a 25px radius circle centered at 0,0 would have bounds of (-25, -25, 50, 50).
- * @method setBounds
- * @param {Number} x The x origin of the bounds. Pass null to remove the manual bounds.
- * @param {Number} y The y origin of the bounds.
- * @param {Number} width The width of the bounds.
- * @param {Number} height The height of the bounds.
- **/
- p.setBounds = function(x, y, width, height) {
- if (x == null) { this._bounds = x; }
- this._bounds = (this._bounds || new createjs.Rectangle()).setValues(x, y, width, height);
- };
-
- /**
- * Returns a clone of this DisplayObject. Some properties that are specific to this instance's current context are
- * reverted to their defaults (for example .parent). Caches are not maintained across clones, and some elements
- * are copied by reference (masks, individual filter instances, hit area)
- * @method clone
- * @return {DisplayObject} A clone of the current DisplayObject instance.
- **/
- p.clone = function() {
- return this._cloneProps(new DisplayObject());
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[DisplayObject (name="+ this.name +")]";
- };
-
-
-// private methods:
- // separated so it can be used more easily in subclasses:
- /**
- * @method _cloneProps
- * @param {DisplayObject} o The DisplayObject instance which will have properties from the current DisplayObject
- * instance copied into.
- * @return {DisplayObject} o
- * @protected
- **/
- p._cloneProps = function(o) {
- o.alpha = this.alpha;
- o.mouseEnabled = this.mouseEnabled;
- o.tickEnabled = this.tickEnabled;
- o.name = this.name;
- o.regX = this.regX;
- o.regY = this.regY;
- o.rotation = this.rotation;
- o.scaleX = this.scaleX;
- o.scaleY = this.scaleY;
- o.shadow = this.shadow;
- o.skewX = this.skewX;
- o.skewY = this.skewY;
- o.visible = this.visible;
- o.x = this.x;
- o.y = this.y;
- o.compositeOperation = this.compositeOperation;
- o.snapToPixel = this.snapToPixel;
- o.filters = this.filters==null?null:this.filters.slice(0);
- o.mask = this.mask;
- o.hitArea = this.hitArea;
- o.cursor = this.cursor;
- o._bounds = this._bounds;
- return o;
- };
-
- /**
- * @method _applyShadow
- * @protected
- * @param {CanvasRenderingContext2D} ctx
- * @param {Shadow} shadow
- **/
- p._applyShadow = function(ctx, shadow) {
- shadow = shadow || Shadow.identity;
- ctx.shadowColor = shadow.color;
- ctx.shadowOffsetX = shadow.offsetX;
- ctx.shadowOffsetY = shadow.offsetY;
- ctx.shadowBlur = shadow.blur;
- };
-
-
- /**
- * @method _tick
- * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
- * @protected
- **/
- p._tick = function(evtObj) {
- // because tick can be really performance sensitive, check for listeners before calling dispatchEvent.
- var ls = this._listeners;
- if (ls && ls["tick"]) {
- // reset & reuse the event object to avoid construction / GC costs:
- evtObj.target = null;
- evtObj.propagationStopped = evtObj.immediatePropagationStopped = false;
- this.dispatchEvent(evtObj);
- }
- };
-
- /**
- * @method _testHit
- * @protected
- * @param {CanvasRenderingContext2D} ctx
- * @return {Boolean}
- **/
- p._testHit = function(ctx) {
- try {
- var hit = ctx.getImageData(0, 0, 1, 1).data[3] > 1;
- } catch (e) {
- if (!DisplayObject.suppressCrossDomainErrors) {
- throw "An error has occurred. This is most likely due to security restrictions on reading canvas pixel data with local or cross-domain images.";
- }
- }
- return hit;
- };
-
- /**
- * @method _applyFilters
- * @protected
- **/
- p._applyFilters = function() {
- if (!this.filters || this.filters.length == 0 || !this.cacheCanvas) { return; }
- var l = this.filters.length;
- var ctx = this.cacheCanvas.getContext("2d");
- var w = this.cacheCanvas.width;
- var h = this.cacheCanvas.height;
- for (var i=0; i maxX) { maxX = x; }
- if ((x = x_a + y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; }
- if ((x = y_c + tx) < minX) { minX = x; } else if (x > maxX) { maxX = x; }
-
- if ((y = x_b + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
- if ((y = x_b + y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
- if ((y = y_d + ty) < minY) { minY = y; } else if (y > maxY) { maxY = y; }
-
- return bounds.setValues(minX, minY, maxX-minX, maxY-minY);
- };
-
- /**
- * Indicates whether the display object has any mouse event listeners or a cursor.
- * @method _isMouseOpaque
- * @return {Boolean}
- * @protected
- **/
- p._hasMouseEventListener = function() {
- var evts = DisplayObject._MOUSE_EVENTS;
- for (var i= 0, l=evts.length; itransform and alpha properties concatenated with their parent
- * Container.
- *
- * For example, a {{#crossLink "Shape"}}{{/crossLink}} with x=100 and alpha=0.5, placed in a Container with x=50
- * and alpha=0.7 will be rendered to the canvas at x=150 and alpha=0.35.
- * Containers have some overhead, so you generally shouldn't create a Container to hold a single child.
- *
- *
Example
- *
- * var container = new createjs.Container();
- * container.addChild(bitmapInstance, shapeInstance);
- * container.x = 100;
- *
- * @class Container
- * @extends DisplayObject
- * @constructor
- **/
- function Container() {
- this.DisplayObject_constructor();
-
- // public properties:
- /**
- * The array of children in the display list. You should usually use the child management methods such as
- * {{#crossLink "Container/addChild"}}{{/crossLink}}, {{#crossLink "Container/removeChild"}}{{/crossLink}},
- * {{#crossLink "Container/swapChildren"}}{{/crossLink}}, etc, rather than accessing this directly, but it is
- * included for advanced uses.
- * @property children
- * @type Array
- * @default null
- **/
- this.children = [];
-
- /**
- * Indicates whether the children of this container are independently enabled for mouse/pointer interaction.
- * If false, the children will be aggregated under the container - for example, a click on a child shape would
- * trigger a click event on the container.
- * @property mouseChildren
- * @type Boolean
- * @default true
- **/
- this.mouseChildren = true;
-
- /**
- * If false, the tick will not be propagated to children of this Container. This can provide some performance benefits.
- * In addition to preventing the "tick" event from being dispatched, it will also prevent tick related updates
- * on some display objects (ex. Sprite & MovieClip frame advancing, DOMElement visibility handling).
- * @property tickChildren
- * @type Boolean
- * @default true
- **/
- this.tickChildren = true;
- }
- var p = createjs.extend(Container, createjs.DisplayObject);
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "Container/numChildren:property"}}{{/crossLink}} property instead.
- * @method getNumChildren
- * @return {Number}
- * @deprecated
- **/
- p.getNumChildren = function() {
- return this.children.length;
- };
-
- /**
- * Returns the number of children in the container.
- * @property numChildren
- * @type {Number}
- * @readonly
- **/
- try {
- Object.defineProperties(p, {
- numChildren: { get: p.getNumChildren }
- });
- } catch (e) {}
-
-
-// public methods:
- /**
- * Constructor alias for backwards compatibility. This method will be removed in future versions.
- * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}.
- * @method initialize
- * @deprecated in favour of `createjs.promote()`
- **/
- p.initialize = Container; // TODO: deprecated.
-
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var hasContent = this.cacheCanvas || this.children.length;
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
-
- // this ensures we don't have issues with display list changes that occur during a draw:
- var list = this.children.slice();
- for (var i=0,l=list.length; iExample
- *
- * container.addChild(bitmapInstance);
- *
- * You can also add multiple children at once:
- *
- * container.addChild(bitmapInstance, shapeInstance, textInstance);
- *
- * @method addChild
- * @param {DisplayObject} child The display object to add.
- * @return {DisplayObject} The child that was added, or the last child if multiple children were added.
- **/
- p.addChild = function(child) {
- if (child == null) { return child; }
- var l = arguments.length;
- if (l > 1) {
- for (var i=0; iExample
- *
- * addChildAt(child1, index);
- *
- * You can also add multiple children, such as:
- *
- * addChildAt(child1, child2, ..., index);
- *
- * The index must be between 0 and numChildren. For example, to add myShape under otherShape in the display list,
- * you could use:
- *
- * container.addChildAt(myShape, container.getChildIndex(otherShape));
- *
- * This would also bump otherShape's index up by one. Fails silently if the index is out of range.
- *
- * @method addChildAt
- * @param {DisplayObject} child The display object to add.
- * @param {Number} index The index to add the child at.
- * @return {DisplayObject} Returns the last child that was added, or the last child if multiple children were added.
- **/
- p.addChildAt = function(child, index) {
- var l = arguments.length;
- var indx = arguments[l-1]; // can't use the same name as the index param or it replaces arguments[1]
- if (indx < 0 || indx > this.children.length) { return arguments[l-2]; }
- if (l > 2) {
- for (var i=0; iExample
- *
- * container.removeChild(child);
- *
- * You can also remove multiple children:
- *
- * removeChild(child1, child2, ...);
- *
- * Returns true if the child (or children) was removed, or false if it was not in the display list.
- * @method removeChild
- * @param {DisplayObject} child The child to remove.
- * @return {Boolean} true if the child (or children) was removed, or false if it was not in the display list.
- **/
- p.removeChild = function(child) {
- var l = arguments.length;
- if (l > 1) {
- var good = true;
- for (var i=0; iExample
- *
- * container.removeChildAt(2);
- *
- * You can also remove multiple children:
- *
- * container.removeChild(2, 7, ...)
- *
- * Returns true if the child (or children) was removed, or false if any index was out of range.
- * @method removeChildAt
- * @param {Number} index The index of the child to remove.
- * @return {Boolean} true if the child (or children) was removed, or false if any index was out of range.
- **/
- p.removeChildAt = function(index) {
- var l = arguments.length;
- if (l > 1) {
- var a = [];
- for (var i=0; i this.children.length-1) { return false; }
- var child = this.children[index];
- if (child) { child.parent = null; }
- this.children.splice(index, 1);
- child.dispatchEvent("removed");
- return true;
- };
-
- /**
- * Removes all children from the display list.
- *
- *
Example
- *
- * container.removeAllChildren();
- *
- * @method removeAllChildren
- **/
- p.removeAllChildren = function() {
- var kids = this.children;
- while (kids.length) { this.removeChildAt(0); }
- };
-
- /**
- * Returns the child at the specified index.
- *
- *
Example
- *
- * container.getChildAt(2);
- *
- * @method getChildAt
- * @param {Number} index The index of the child to return.
- * @return {DisplayObject} The child at the specified index. Returns null if there is no child at the index.
- **/
- p.getChildAt = function(index) {
- return this.children[index];
- };
-
- /**
- * Returns the child with the specified name.
- * @method getChildByName
- * @param {String} name The name of the child to return.
- * @return {DisplayObject} The child with the specified name.
- **/
- p.getChildByName = function(name) {
- var kids = this.children;
- for (var i=0,l=kids.length;iExample: Display children with a higher y in front.
- *
- * var sortFunction = function(obj1, obj2, options) {
- * if (obj1.y > obj2.y) { return 1; }
- * if (obj1.y < obj2.y) { return -1; }
- * return 0;
- * }
- * container.sortChildren(sortFunction);
- *
- * @method sortChildren
- * @param {Function} sortFunction the function to use to sort the child list. See JavaScript's Array.sort
- * documentation for details.
- **/
- p.sortChildren = function(sortFunction) {
- this.children.sort(sortFunction);
- };
-
- /**
- * Returns the index of the specified child in the display list, or -1 if it is not in the display list.
- *
- *
Example
- *
- * var index = container.getChildIndex(child);
- *
- * @method getChildIndex
- * @param {DisplayObject} child The child to return the index of.
- * @return {Number} The index of the specified child. -1 if the child is not found.
- **/
- p.getChildIndex = function(child) {
- return createjs.indexOf(this.children, child);
- };
-
- /**
- * Swaps the children at the specified indexes. Fails silently if either index is out of range.
- * @method swapChildrenAt
- * @param {Number} index1
- * @param {Number} index2
- **/
- p.swapChildrenAt = function(index1, index2) {
- var kids = this.children;
- var o1 = kids[index1];
- var o2 = kids[index2];
- if (!o1 || !o2) { return; }
- kids[index1] = o2;
- kids[index2] = o1;
- };
-
- /**
- * Swaps the specified children's depth in the display list. Fails silently if either child is not a child of this
- * Container.
- * @method swapChildren
- * @param {DisplayObject} child1
- * @param {DisplayObject} child2
- **/
- p.swapChildren = function(child1, child2) {
- var kids = this.children;
- var index1,index2;
- for (var i=0,l=kids.length;i= l) { return; }
- for (var i=0;i 0 at the
- * specified position). This ignores the alpha, shadow and compositeOperation of the display object, and all
- * transform properties including regX/Y.
- * @method hitTest
- * @param {Number} x The x position to check in the display object's local coordinates.
- * @param {Number} y The y position to check in the display object's local coordinates.
- * @return {Boolean} A Boolean indicating whether there is a visible section of a DisplayObject that overlaps the specified
- * coordinates.
- **/
- p.hitTest = function(x, y) {
- // TODO: optimize to use the fast cache check where possible.
- return (this.getObjectUnderPoint(x, y) != null);
- };
-
- /**
- * Returns an array of all display objects under the specified coordinates that are in this container's display
- * list. This routine ignores any display objects with {{#crossLink "DisplayObject/mouseEnabled:property"}}{{/crossLink}}
- * set to `false`. The array will be sorted in order of visual depth, with the top-most display object at index 0.
- * This uses shape based hit detection, and can be an expensive operation to run, so it is best to use it carefully.
- * For example, if testing for objects under the mouse, test on tick (instead of on {{#crossLink "DisplayObject/mousemove:event"}}{{/crossLink}}),
- * and only if the mouse's position has changed.
- *
- *
- *
By default (mode=0) this method evaluates all display objects.
- *
By setting the `mode` parameter to `1`, the {{#crossLink "DisplayObject/mouseEnabled:property"}}{{/crossLink}}
- * and {{#crossLink "mouseChildren:property"}}{{/crossLink}} properties will be respected.
- *
Setting the `mode` to `2` additionally excludes display objects that do not have active mouse event
- * listeners or a {{#crossLink "DisplayObject:cursor:property"}}{{/crossLink}} property. That is, only objects
- * that would normally intercept mouse interaction will be included. This can significantly improve performance
- * in some cases by reducing the number of display objects that need to be tested.
- *
- *
- * This method accounts for both {{#crossLink "DisplayObject/hitArea:property"}}{{/crossLink}} and {{#crossLink "DisplayObject/mask:property"}}{{/crossLink}}.
- * @method getObjectsUnderPoint
- * @param {Number} x The x position in the container to test.
- * @param {Number} y The y position in the container to test.
- * @param {Number} [mode=0] The mode to use to determine which display objects to include. 0-all, 1-respect mouseEnabled/mouseChildren, 2-only mouse opaque objects.
- * @return {Array} An Array of DisplayObjects under the specified coordinates.
- **/
- p.getObjectsUnderPoint = function(x, y, mode) {
- var arr = [];
- var pt = this.localToGlobal(x, y);
- this._getObjectsUnderPoint(pt.x, pt.y, arr, mode>0, mode==1);
- return arr;
- };
-
- /**
- * Similar to {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}}, but returns only the top-most display
- * object. This runs significantly faster than getObjectsUnderPoint(), but is still potentially an expensive
- * operation. See {{#crossLink "Container/getObjectsUnderPoint"}}{{/crossLink}} for more information.
- * @method getObjectUnderPoint
- * @param {Number} x The x position in the container to test.
- * @param {Number} y The y position in the container to test.
- * @param {Number} mode The mode to use to determine which display objects to include. 0-all, 1-respect mouseEnabled/mouseChildren, 2-only mouse opaque objects.
- * @return {DisplayObject} The top-most display object under the specified coordinates.
- **/
- p.getObjectUnderPoint = function(x, y, mode) {
- var pt = this.localToGlobal(x, y);
- return this._getObjectsUnderPoint(pt.x, pt.y, null, mode>0, mode==1);
- };
-
- /**
- * Docced in superclass.
- */
- p.getBounds = function() {
- return this._getBounds(null, true);
- };
-
-
- /**
- * Docced in superclass.
- */
- p.getTransformedBounds = function() {
- return this._getBounds();
- };
-
- /**
- * Returns a clone of this Container. Some properties that are specific to this instance's current context are
- * reverted to their defaults (for example .parent).
- * @method clone
- * @param {Boolean} [recursive=false] If true, all of the descendants of this container will be cloned recursively. If false, the
- * properties of the container will be cloned, but the new instance will not have any children.
- * @return {Container} A clone of the current Container instance.
- **/
- p.clone = function(recursive) {
- var o = this._cloneProps(new Container());
- if (recursive) { this._cloneChildren(o); }
- return o;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Container (name="+ this.name +")]";
- };
-
-
-// private methods:
- /**
- * @method _tick
- * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
- * @protected
- **/
- p._tick = function(evtObj) {
- if (this.tickChildren) {
- for (var i=this.children.length-1; i>=0; i--) {
- var child = this.children[i];
- if (child.tickEnabled && child._tick) { child._tick(evtObj); }
- }
- }
- this.DisplayObject__tick(evtObj);
- };
-
- /**
- * Recursively clones all children of this container, and adds them to the target container.
- * @method cloneChildren
- * @protected
- * @param {Container} o The target container.
- **/
- p._cloneChildren = function(o) {
- if (o.children.length) { o.removeAllChildren(); }
- var arr = o.children;
- for (var i=0, l=this.children.length; i=0; i--) {
- var child = children[i];
- var hitArea = child.hitArea;
- if (!child.visible || (!hitArea && !child.isVisible()) || (mouse && !child.mouseEnabled)) { continue; }
- if (!hitArea && !this._testMask(child, x, y)) { continue; }
-
- // if a child container has a hitArea then we only need to check its hitArea, so we can treat it as a normal DO:
- if (!hitArea && child instanceof Container) {
- var result = child._getObjectsUnderPoint(x, y, arr, mouse, activeListener, currentDepth+1);
- if (!arr && result) { return (mouse && !this.mouseChildren) ? this : result; }
- } else {
- if (mouse && !activeListener && !child._hasMouseEventListener()) { continue; }
-
- // TODO: can we pass displayProps forward, to avoid having to calculate this backwards every time? It's kind of a mixed bag. When we're only hunting for DOs with event listeners, it may not make sense.
- var props = child.getConcatenatedDisplayProps(child._props);
- mtx = props.matrix;
-
- if (hitArea) {
- mtx.appendMatrix(hitArea.getMatrix(hitArea._props.matrix));
- props.alpha = hitArea.alpha;
- }
-
- ctx.globalAlpha = props.alpha;
- ctx.setTransform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx-x, mtx.ty-y);
- (hitArea||child).draw(ctx);
- if (!this._testHit(ctx)) { continue; }
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.clearRect(0, 0, 2, 2);
- if (arr) { arr.push(child); }
- else { return (mouse && !this.mouseChildren) ? this : child; }
- }
- }
- return null;
- };
-
- /**
- * @method _testMask
- * @param {DisplayObject} target
- * @param {Number} x
- * @param {Number} y
- * @return {Boolean} Indicates whether the x/y is within the masked region.
- * @protected
- **/
- p._testMask = function(target, x, y) {
- var mask = target.mask;
- if (!mask || !mask.graphics || mask.graphics.isEmpty()) { return true; }
-
- var mtx = this._props.matrix, parent = target.parent;
- mtx = parent ? parent.getConcatenatedMatrix(mtx) : mtx.identity();
- mtx = mask.getMatrix(mask._props.matrix).prependMatrix(mtx);
-
- var ctx = createjs.DisplayObject._hitTestContext;
- ctx.setTransform(mtx.a, mtx.b, mtx.c, mtx.d, mtx.tx-x, mtx.ty-y);
-
- // draw the mask as a solid fill:
- mask.graphics.drawAsPath(ctx);
- ctx.fillStyle = "#000";
- ctx.fill();
-
- if (!this._testHit(ctx)) { return false; }
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.clearRect(0, 0, 2, 2);
-
- return true;
- };
-
- /**
- * @method _getBounds
- * @param {Matrix2D} matrix
- * @param {Boolean} ignoreTransform If true, does not apply this object's transform.
- * @return {Rectangle}
- * @protected
- **/
- p._getBounds = function(matrix, ignoreTransform) {
- var bounds = this.DisplayObject_getBounds();
- if (bounds) { return this._transformBounds(bounds, matrix, ignoreTransform); }
-
- var mtx = this._props.matrix;
- mtx = ignoreTransform ? mtx.identity() : this.getMatrix(mtx);
- if (matrix) { mtx.prependMatrix(matrix); }
-
- var l = this.children.length, rect=null;
- for (var i=0; iExample
- * This example creates a stage, adds a child to it, then uses {{#crossLink "Ticker"}}{{/crossLink}} to update the child
- * and redraw the stage using {{#crossLink "Stage/update"}}{{/crossLink}}.
- *
- * var stage = new createjs.Stage("canvasElementId");
- * var image = new createjs.Bitmap("imagePath.png");
- * stage.addChild(image);
- * createjs.Ticker.addEventListener("tick", handleTick);
- * function handleTick(event) {
- * image.x += 10;
- * stage.update();
- * }
- *
- * @class Stage
- * @extends Container
- * @constructor
- * @param {HTMLCanvasElement | String | Object} canvas A canvas object that the Stage will render to, or the string id
- * of a canvas object in the current document.
- **/
- function Stage(canvas) {
- this.Container_constructor();
-
-
- // public properties:
- /**
- * Indicates whether the stage should automatically clear the canvas before each render. You can set this to false
- * to manually control clearing (for generative art, or when pointing multiple stages at the same canvas for
- * example).
- *
- *
Example
- *
- * var stage = new createjs.Stage("canvasId");
- * stage.autoClear = false;
- *
- * @property autoClear
- * @type Boolean
- * @default true
- **/
- this.autoClear = true;
-
- /**
- * The canvas the stage will render to. Multiple stages can share a single canvas, but you must disable autoClear for all but the
- * first stage that will be ticked (or they will clear each other's render).
- *
- * When changing the canvas property you must disable the events on the old canvas, and enable events on the
- * new canvas or mouse events will not work as expected. For example:
- *
- * myStage.enableDOMEvents(false);
- * myStage.canvas = anotherCanvas;
- * myStage.enableDOMEvents(true);
- *
- * @property canvas
- * @type HTMLCanvasElement | Object
- **/
- this.canvas = (typeof canvas == "string") ? document.getElementById(canvas) : canvas;
-
- /**
- * The current mouse X position on the canvas. If the mouse leaves the canvas, this will indicate the most recent
- * position over the canvas, and mouseInBounds will be set to false.
- * @property mouseX
- * @type Number
- * @readonly
- **/
- this.mouseX = 0;
-
- /**
- * The current mouse Y position on the canvas. If the mouse leaves the canvas, this will indicate the most recent
- * position over the canvas, and mouseInBounds will be set to false.
- * @property mouseY
- * @type Number
- * @readonly
- **/
- this.mouseY = 0;
-
- /**
- * Specifies the area of the stage to affect when calling update. This can be use to selectively
- * re-draw specific regions of the canvas. If null, the whole canvas area is drawn.
- * @property drawRect
- * @type {Rectangle}
- */
- this.drawRect = null;
-
- /**
- * Indicates whether display objects should be rendered on whole pixels. You can set the
- * {{#crossLink "DisplayObject/snapToPixel"}}{{/crossLink}} property of
- * display objects to false to enable/disable this behaviour on a per instance basis.
- * @property snapToPixelEnabled
- * @type Boolean
- * @default false
- **/
- this.snapToPixelEnabled = false;
-
- /**
- * Indicates whether the mouse is currently within the bounds of the canvas.
- * @property mouseInBounds
- * @type Boolean
- * @default false
- **/
- this.mouseInBounds = false;
-
- /**
- * If true, tick callbacks will be called on all display objects on the stage prior to rendering to the canvas.
- * @property tickOnUpdate
- * @type Boolean
- * @default true
- **/
- this.tickOnUpdate = true;
-
- /**
- * If true, mouse move events will continue to be called when the mouse leaves the target canvas. See
- * {{#crossLink "Stage/mouseInBounds:property"}}{{/crossLink}}, and {{#crossLink "MouseEvent"}}{{/crossLink}}
- * x/y/rawX/rawY.
- * @property mouseMoveOutside
- * @type Boolean
- * @default false
- **/
- this.mouseMoveOutside = false;
-
-
- /**
- * Prevents selection of other elements in the html page if the user clicks and drags, or double clicks on the canvas.
- * This works by calling `preventDefault()` on any mousedown events (or touch equivalent) originating on the canvas.
- * @property preventSelection
- * @type Boolean
- * @default true
- **/
- this.preventSelection = true;
-
- /**
- * The hitArea property is not supported for Stage.
- * @property hitArea
- * @type {DisplayObject}
- * @default null
- */
-
-
- // private properties:
- /**
- * Holds objects with data for each active pointer id. Each object has the following properties:
- * x, y, event, target, overTarget, overX, overY, inBounds, posEvtObj (native event that last updated position)
- * @property _pointerData
- * @type {Object}
- * @private
- */
- this._pointerData = {};
-
- /**
- * Number of active pointers.
- * @property _pointerCount
- * @type {Object}
- * @private
- */
- this._pointerCount = 0;
-
- /**
- * The ID of the primary pointer.
- * @property _primaryPointerID
- * @type {Object}
- * @private
- */
- this._primaryPointerID = null;
-
- /**
- * @property _mouseOverIntervalID
- * @protected
- * @type Number
- **/
- this._mouseOverIntervalID = null;
-
- /**
- * @property _nextStage
- * @protected
- * @type Stage
- **/
- this._nextStage = null;
-
- /**
- * @property _prevStage
- * @protected
- * @type Stage
- **/
- this._prevStage = null;
-
-
- // initialize:
- this.enableDOMEvents(true);
- }
- var p = createjs.extend(Stage, createjs.Container);
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// events:
- /**
- * Dispatched when the user moves the mouse over the canvas.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event stagemousemove
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user presses their left mouse button on the canvas. See the {{#crossLink "MouseEvent"}}{{/crossLink}}
- * class for a listing of event properties.
- * @event stagemousedown
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the user the user presses somewhere on the stage, then releases the mouse button anywhere that the page can detect it (this varies slightly between browsers).
- * You can use {{#crossLink "Stage/mouseInBounds:property"}}{{/crossLink}} to check whether the mouse is currently within the stage bounds.
- * See the {{#crossLink "MouseEvent"}}{{/crossLink}} class for a listing of event properties.
- * @event stagemouseup
- * @since 0.6.0
- */
-
- /**
- * Dispatched when the mouse moves from within the canvas area (mouseInBounds == true) to outside it (mouseInBounds == false).
- * This is currently only dispatched for mouse input (not touch). See the {{#crossLink "MouseEvent"}}{{/crossLink}}
- * class for a listing of event properties.
- * @event mouseleave
- * @since 0.7.0
- */
-
- /**
- * Dispatched when the mouse moves into the canvas area (mouseInBounds == false) from outside it (mouseInBounds == true).
- * This is currently only dispatched for mouse input (not touch). See the {{#crossLink "MouseEvent"}}{{/crossLink}}
- * class for a listing of event properties.
- * @event mouseenter
- * @since 0.7.0
- */
-
- /**
- * Dispatched each update immediately before the tick event is propagated through the display list.
- * You can call preventDefault on the event object to cancel propagating the tick event.
- * @event tickstart
- * @since 0.7.0
- */
-
- /**
- * Dispatched each update immediately after the tick event is propagated through the display list. Does not fire if
- * tickOnUpdate is false. Precedes the "drawstart" event.
- * @event tickend
- * @since 0.7.0
- */
-
- /**
- * Dispatched each update immediately before the canvas is cleared and the display list is drawn to it.
- * You can call preventDefault on the event object to cancel the draw.
- * @event drawstart
- * @since 0.7.0
- */
-
- /**
- * Dispatched each update immediately after the display list is drawn to the canvas and the canvas context is restored.
- * @event drawend
- * @since 0.7.0
- */
-
-
-// getter / setters:
- /**
- * Specifies a target stage that will have mouse / touch interactions relayed to it after this stage handles them.
- * This can be useful in cases where you have multiple layered canvases and want user interactions
- * events to pass through. For example, this would relay mouse events from topStage to bottomStage:
- *
- * topStage.nextStage = bottomStage;
- *
- * To disable relaying, set nextStage to null.
- *
- * MouseOver, MouseOut, RollOver, and RollOut interactions are also passed through using the mouse over settings
- * of the top-most stage, but are only processed if the target stage has mouse over interactions enabled.
- * Considerations when using roll over in relay targets:
- *
The top-most (first) stage must have mouse over interactions enabled (via enableMouseOver)
- *
All stages that wish to participate in mouse over interaction must enable them via enableMouseOver
- *
All relay targets will share the frequency value of the top-most stage
- *
- * To illustrate, in this example the targetStage would process mouse over interactions at 10hz (despite passing
- * 30 as it's desired frequency):
- * topStage.nextStage = targetStage;
- * topStage.enableMouseOver(10);
- * targetStage.enableMouseOver(30);
- *
- * If the target stage's canvas is completely covered by this stage's canvas, you may also want to disable its
- * DOM events using:
- *
- * targetStage.enableDOMEvents(false);
- *
- * @property nextStage
- * @type {Stage}
- **/
- p._get_nextStage = function() {
- return this._nextStage;
- };
- p._set_nextStage = function(value) {
- if (this._nextStage) { this._nextStage._prevStage = null; }
- if (value) { value._prevStage = this; }
- this._nextStage = value;
- };
-
- try {
- Object.defineProperties(p, {
- nextStage: { get: p._get_nextStage, set: p._set_nextStage }
- });
- } catch (e) {} // TODO: use Log
-
-
-// public methods:
- /**
- * Each time the update method is called, the stage will call {{#crossLink "Stage/tick"}}{{/crossLink}}
- * unless {{#crossLink "Stage/tickOnUpdate:property"}}{{/crossLink}} is set to false,
- * and then render the display list to the canvas.
- *
- * @method update
- * @param {Object} [props] Props object to pass to `tick()`. Should usually be a {{#crossLink "Ticker"}}{{/crossLink}} event object, or similar object with a delta property.
- **/
- p.update = function(props) {
- if (!this.canvas) { return; }
- if (this.tickOnUpdate) { this.tick(props); }
- if (this.dispatchEvent("drawstart", false, true) === false) { return; }
- createjs.DisplayObject._snapToPixelEnabled = this.snapToPixelEnabled;
- var r = this.drawRect, ctx = this.canvas.getContext("2d");
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- if (this.autoClear) {
- if (r) { ctx.clearRect(r.x, r.y, r.width, r.height); }
- else { ctx.clearRect(0, 0, this.canvas.width+1, this.canvas.height+1); }
- }
- ctx.save();
- if (this.drawRect) {
- ctx.beginPath();
- ctx.rect(r.x, r.y, r.width, r.height);
- ctx.clip();
- }
- this.updateContext(ctx);
- this.draw(ctx, false);
- ctx.restore();
- this.dispatchEvent("drawend");
- };
-
- /**
- * Propagates a tick event through the display list. This is automatically called by {{#crossLink "Stage/update"}}{{/crossLink}}
- * unless {{#crossLink "Stage/tickOnUpdate:property"}}{{/crossLink}} is set to false.
- *
- * If a props object is passed to `tick()`, then all of its properties will be copied to the event object that is
- * propagated to listeners.
- *
- * Some time-based features in EaselJS (for example {{#crossLink "Sprite/framerate"}}{{/crossLink}} require that
- * a {{#crossLink "Ticker/tick:event"}}{{/crossLink}} event object (or equivalent object with a delta property) be
- * passed as the `props` parameter to `tick()`. For example:
- *
- * Ticker.on("tick", handleTick);
- * function handleTick(evtObj) {
- * // clone the event object from Ticker, and add some custom data to it:
- * var evt = evtObj.clone().set({greeting:"hello", name:"world"});
- *
- * // pass it to stage.update():
- * myStage.update(evt); // subsequently calls tick() with the same param
- * }
- *
- * // ...
- * myDisplayObject.on("tick", handleDisplayObjectTick);
- * function handleDisplayObjectTick(evt) {
- * console.log(evt.delta); // the delta property from the Ticker tick event object
- * console.log(evt.greeting, evt.name); // custom data: "hello world"
- * }
- *
- * @method tick
- * @param {Object} [props] An object with properties that should be copied to the event object. Should usually be a Ticker event object, or similar object with a delta property.
- **/
- p.tick = function(props) {
- if (!this.tickEnabled || this.dispatchEvent("tickstart", false, true) === false) { return; }
- var evtObj = new createjs.Event("tick");
- if (props) {
- for (var n in props) {
- if (props.hasOwnProperty(n)) { evtObj[n] = props[n]; }
- }
- }
- this._tick(evtObj);
- this.dispatchEvent("tickend");
- };
-
- /**
- * Default event handler that calls the Stage {{#crossLink "Stage/update"}}{{/crossLink}} method when a {{#crossLink "DisplayObject/tick:event"}}{{/crossLink}}
- * event is received. This allows you to register a Stage instance as a event listener on {{#crossLink "Ticker"}}{{/crossLink}}
- * directly, using:
- *
- * Ticker.addEventListener("tick", myStage");
- *
- * Note that if you subscribe to ticks using this pattern, then the tick event object will be passed through to
- * display object tick handlers, instead of delta and paused parameters.
- * @property handleEvent
- * @type Function
- **/
- p.handleEvent = function(evt) {
- if (evt.type == "tick") { this.update(evt); }
- };
-
- /**
- * Clears the target canvas. Useful if {{#crossLink "Stage/autoClear:property"}}{{/crossLink}} is set to `false`.
- * @method clear
- **/
- p.clear = function() {
- if (!this.canvas) { return; }
- var ctx = this.canvas.getContext("2d");
- ctx.setTransform(1, 0, 0, 1, 0, 0);
- ctx.clearRect(0, 0, this.canvas.width+1, this.canvas.height+1);
- };
-
- /**
- * Returns a data url that contains a Base64-encoded image of the contents of the stage. The returned data url can
- * be specified as the src value of an image element.
- * @method toDataURL
- * @param {String} [backgroundColor] The background color to be used for the generated image. Any valid CSS color
- * value is allowed. The default value is a transparent background.
- * @param {String} [mimeType="image/png"] The MIME type of the image format to be create. The default is "image/png". If an unknown MIME type
- * is passed in, or if the browser does not support the specified MIME type, the default value will be used.
- * @return {String} a Base64 encoded image.
- **/
- p.toDataURL = function(backgroundColor, mimeType) {
- var data, ctx = this.canvas.getContext('2d'), w = this.canvas.width, h = this.canvas.height;
-
- if (backgroundColor) {
- data = ctx.getImageData(0, 0, w, h);
- var compositeOperation = ctx.globalCompositeOperation;
- ctx.globalCompositeOperation = "destination-over";
-
- ctx.fillStyle = backgroundColor;
- ctx.fillRect(0, 0, w, h);
- }
-
- var dataURL = this.canvas.toDataURL(mimeType||"image/png");
-
- if(backgroundColor) {
- ctx.putImageData(data, 0, 0);
- ctx.globalCompositeOperation = compositeOperation;
- }
-
- return dataURL;
- };
-
- /**
- * Enables or disables (by passing a frequency of 0) mouse over ({{#crossLink "DisplayObject/mouseover:event"}}{{/crossLink}}
- * and {{#crossLink "DisplayObject/mouseout:event"}}{{/crossLink}}) and roll over events ({{#crossLink "DisplayObject/rollover:event"}}{{/crossLink}}
- * and {{#crossLink "DisplayObject/rollout:event"}}{{/crossLink}}) for this stage's display list. These events can
- * be expensive to generate, so they are disabled by default. The frequency of the events can be controlled
- * independently of mouse move events via the optional `frequency` parameter.
- *
- *
Example
- *
- * var stage = new createjs.Stage("canvasId");
- * stage.enableMouseOver(10); // 10 updates per second
- *
- * @method enableMouseOver
- * @param {Number} [frequency=20] Optional param specifying the maximum number of times per second to broadcast
- * mouse over/out events. Set to 0 to disable mouse over events completely. Maximum is 50. A lower frequency is less
- * responsive, but uses less CPU.
- **/
- p.enableMouseOver = function(frequency) {
- if (this._mouseOverIntervalID) {
- clearInterval(this._mouseOverIntervalID);
- this._mouseOverIntervalID = null;
- if (frequency == 0) {
- this._testMouseOver(true);
- }
- }
- if (frequency == null) { frequency = 20; }
- else if (frequency <= 0) { return; }
- var o = this;
- this._mouseOverIntervalID = setInterval(function(){ o._testMouseOver(); }, 1000/Math.min(50,frequency));
- };
-
- /**
- * Enables or disables the event listeners that stage adds to DOM elements (window, document and canvas). It is good
- * practice to disable events when disposing of a Stage instance, otherwise the stage will continue to receive
- * events from the page.
- *
- * When changing the canvas property you must disable the events on the old canvas, and enable events on the
- * new canvas or mouse events will not work as expected. For example:
- *
- * myStage.enableDOMEvents(false);
- * myStage.canvas = anotherCanvas;
- * myStage.enableDOMEvents(true);
- *
- * @method enableDOMEvents
- * @param {Boolean} [enable=true] Indicates whether to enable or disable the events. Default is true.
- **/
- p.enableDOMEvents = function(enable) {
- if (enable == null) { enable = true; }
- var n, o, ls = this._eventListeners;
- if (!enable && ls) {
- for (n in ls) {
- o = ls[n];
- o.t.removeEventListener(n, o.f, false);
- }
- this._eventListeners = null;
- } else if (enable && !ls && this.canvas) {
- var t = window.addEventListener ? window : document;
- var _this = this;
- ls = this._eventListeners = {};
- ls["mouseup"] = {t:t, f:function(e) { _this._handleMouseUp(e)} };
- ls["mousemove"] = {t:t, f:function(e) { _this._handleMouseMove(e)} };
- ls["dblclick"] = {t:this.canvas, f:function(e) { _this._handleDoubleClick(e)} };
- ls["mousedown"] = {t:this.canvas, f:function(e) { _this._handleMouseDown(e)} };
-
- for (n in ls) {
- o = ls[n];
- o.t.addEventListener(n, o.f, false);
- }
- }
- };
-
- /**
- * Stage instances cannot be cloned.
- * @method clone
- **/
- p.clone = function() {
- throw("Stage cannot be cloned.");
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Stage (name="+ this.name +")]";
- };
-
-
-// private methods:
- /**
- * @method _getElementRect
- * @protected
- * @param {HTMLElement} e
- **/
- p._getElementRect = function(e) {
- var bounds;
- try { bounds = e.getBoundingClientRect(); } // this can fail on disconnected DOM elements in IE9
- catch (err) { bounds = {top: e.offsetTop, left: e.offsetLeft, width:e.offsetWidth, height:e.offsetHeight}; }
-
- var offX = (window.pageXOffset || document.scrollLeft || 0) - (document.clientLeft || document.body.clientLeft || 0);
- var offY = (window.pageYOffset || document.scrollTop || 0) - (document.clientTop || document.body.clientTop || 0);
-
- var styles = window.getComputedStyle ? getComputedStyle(e,null) : e.currentStyle; // IE <9 compatibility.
- var padL = parseInt(styles.paddingLeft)+parseInt(styles.borderLeftWidth);
- var padT = parseInt(styles.paddingTop)+parseInt(styles.borderTopWidth);
- var padR = parseInt(styles.paddingRight)+parseInt(styles.borderRightWidth);
- var padB = parseInt(styles.paddingBottom)+parseInt(styles.borderBottomWidth);
-
- // note: in some browsers bounds properties are read only.
- return {
- left: bounds.left+offX+padL,
- right: bounds.right+offX-padR,
- top: bounds.top+offY+padT,
- bottom: bounds.bottom+offY-padB
- }
- };
-
- /**
- * @method _getPointerData
- * @protected
- * @param {Number} id
- **/
- p._getPointerData = function(id) {
- var data = this._pointerData[id];
- if (!data) { data = this._pointerData[id] = {x:0,y:0}; }
- return data;
- };
-
- /**
- * @method _handleMouseMove
- * @protected
- * @param {MouseEvent} e
- **/
- p._handleMouseMove = function(e) {
- if(!e){ e = window.event; }
- this._handlePointerMove(-1, e, e.pageX, e.pageY);
- };
-
- /**
- * @method _handlePointerMove
- * @protected
- * @param {Number} id
- * @param {Event} e
- * @param {Number} pageX
- * @param {Number} pageY
- * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage.
- **/
- p._handlePointerMove = function(id, e, pageX, pageY, owner) {
- if (this._prevStage && owner === undefined) { return; } // redundant listener.
- if (!this.canvas) { return; }
- var nextStage=this._nextStage, o=this._getPointerData(id);
-
- var inBounds = o.inBounds;
- this._updatePointerPosition(id, e, pageX, pageY);
- if (inBounds || o.inBounds || this.mouseMoveOutside) {
- if (id === -1 && o.inBounds == !inBounds) {
- this._dispatchMouseEvent(this, (inBounds ? "mouseleave" : "mouseenter"), false, id, o, e);
- }
-
- this._dispatchMouseEvent(this, "stagemousemove", false, id, o, e);
- this._dispatchMouseEvent(o.target, "pressmove", true, id, o, e);
- }
-
- nextStage&&nextStage._handlePointerMove(id, e, pageX, pageY, null);
- };
-
- /**
- * @method _updatePointerPosition
- * @protected
- * @param {Number} id
- * @param {Event} e
- * @param {Number} pageX
- * @param {Number} pageY
- **/
- p._updatePointerPosition = function(id, e, pageX, pageY) {
- var rect = this._getElementRect(this.canvas);
- pageX -= rect.left;
- pageY -= rect.top;
-
- var w = this.canvas.width;
- var h = this.canvas.height;
- pageX /= (rect.right-rect.left)/w;
- pageY /= (rect.bottom-rect.top)/h;
- var o = this._getPointerData(id);
- if (o.inBounds = (pageX >= 0 && pageY >= 0 && pageX <= w-1 && pageY <= h-1)) {
- o.x = pageX;
- o.y = pageY;
- } else if (this.mouseMoveOutside) {
- o.x = pageX < 0 ? 0 : (pageX > w-1 ? w-1 : pageX);
- o.y = pageY < 0 ? 0 : (pageY > h-1 ? h-1 : pageY);
- }
-
- o.posEvtObj = e;
- o.rawX = pageX;
- o.rawY = pageY;
-
- if (id === this._primaryPointerID || id === -1) {
- this.mouseX = o.x;
- this.mouseY = o.y;
- this.mouseInBounds = o.inBounds;
- }
- };
-
- /**
- * @method _handleMouseUp
- * @protected
- * @param {MouseEvent} e
- **/
- p._handleMouseUp = function(e) {
- this._handlePointerUp(-1, e, false);
- };
-
- /**
- * @method _handlePointerUp
- * @protected
- * @param {Number} id
- * @param {Event} e
- * @param {Boolean} clear
- * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage.
- **/
- p._handlePointerUp = function(id, e, clear, owner) {
- var nextStage = this._nextStage, o = this._getPointerData(id);
- if (this._prevStage && owner === undefined) { return; } // redundant listener.
-
- var target=null, oTarget = o.target;
- if (!owner && (oTarget || nextStage)) { target = this._getObjectsUnderPoint(o.x, o.y, null, true); }
-
- if (o.down) { this._dispatchMouseEvent(this, "stagemouseup", false, id, o, e, target); o.down = false; }
-
- if (target == oTarget) { this._dispatchMouseEvent(oTarget, "click", true, id, o, e); }
- this._dispatchMouseEvent(oTarget, "pressup", true, id, o, e);
-
- if (clear) {
- if (id==this._primaryPointerID) { this._primaryPointerID = null; }
- delete(this._pointerData[id]);
- } else { o.target = null; }
-
- nextStage&&nextStage._handlePointerUp(id, e, clear, owner || target && this);
- };
-
- /**
- * @method _handleMouseDown
- * @protected
- * @param {MouseEvent} e
- **/
- p._handleMouseDown = function(e) {
- this._handlePointerDown(-1, e, e.pageX, e.pageY);
- };
-
- /**
- * @method _handlePointerDown
- * @protected
- * @param {Number} id
- * @param {Event} e
- * @param {Number} pageX
- * @param {Number} pageY
- * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage.
- **/
- p._handlePointerDown = function(id, e, pageX, pageY, owner) {
- if (this.preventSelection) { e.preventDefault(); }
- if (this._primaryPointerID == null || id === -1) { this._primaryPointerID = id; } // mouse always takes over.
-
- if (pageY != null) { this._updatePointerPosition(id, e, pageX, pageY); }
- var target = null, nextStage = this._nextStage, o = this._getPointerData(id);
- if (!owner) { target = o.target = this._getObjectsUnderPoint(o.x, o.y, null, true); }
-
- if (o.inBounds) { this._dispatchMouseEvent(this, "stagemousedown", false, id, o, e, target); o.down = true; }
- this._dispatchMouseEvent(target, "mousedown", true, id, o, e);
-
- nextStage&&nextStage._handlePointerDown(id, e, pageX, pageY, owner || target && this);
- };
-
- /**
- * @method _testMouseOver
- * @param {Boolean} clear If true, clears the mouseover / rollover (ie. no target)
- * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage.
- * @param {Stage} eventTarget The stage that the cursor is actively over.
- * @protected
- **/
- p._testMouseOver = function(clear, owner, eventTarget) {
- if (this._prevStage && owner === undefined) { return; } // redundant listener.
-
- var nextStage = this._nextStage;
- if (!this._mouseOverIntervalID) {
- // not enabled for mouseover, but should still relay the event.
- nextStage&&nextStage._testMouseOver(clear, owner, eventTarget);
- return;
- }
- var o = this._getPointerData(-1);
- // only update if the mouse position has changed. This provides a lot of optimization, but has some trade-offs.
- if (!o || (!clear && this.mouseX == this._mouseOverX && this.mouseY == this._mouseOverY && this.mouseInBounds)) { return; }
-
- var e = o.posEvtObj;
- var isEventTarget = eventTarget || e&&(e.target == this.canvas);
- var target=null, common = -1, cursor="", t, i, l;
-
- if (!owner && (clear || this.mouseInBounds && isEventTarget)) {
- target = this._getObjectsUnderPoint(this.mouseX, this.mouseY, null, true);
- this._mouseOverX = this.mouseX;
- this._mouseOverY = this.mouseY;
- }
-
- var oldList = this._mouseOverTarget||[];
- var oldTarget = oldList[oldList.length-1];
- var list = this._mouseOverTarget = [];
-
- // generate ancestor list and check for cursor:
- t = target;
- while (t) {
- list.unshift(t);
- if (!cursor) { cursor = t.cursor; }
- t = t.parent;
- }
- this.canvas.style.cursor = cursor;
- if (!owner && eventTarget) { eventTarget.canvas.style.cursor = cursor; }
-
- // find common ancestor:
- for (i=0,l=list.length; icommon; i--) {
- this._dispatchMouseEvent(oldList[i], "rollout", false, -1, o, e, target);
- }
-
- for (i=list.length-1; i>common; i--) {
- this._dispatchMouseEvent(list[i], "rollover", false, -1, o, e, oldTarget);
- }
-
- if (oldTarget != target) {
- this._dispatchMouseEvent(target, "mouseover", true, -1, o, e, oldTarget);
- }
-
- nextStage&&nextStage._testMouseOver(clear, owner || target && this, eventTarget || isEventTarget && this);
- };
-
- /**
- * @method _handleDoubleClick
- * @protected
- * @param {MouseEvent} e
- * @param {Stage} owner Indicates that the event has already been captured & handled by the indicated stage.
- **/
- p._handleDoubleClick = function(e, owner) {
- var target=null, nextStage=this._nextStage, o=this._getPointerData(-1);
- if (!owner) {
- target = this._getObjectsUnderPoint(o.x, o.y, null, true);
- this._dispatchMouseEvent(target, "dblclick", true, -1, o, e);
- }
- nextStage&&nextStage._handleDoubleClick(e, owner || target && this);
- };
-
- /**
- * @method _dispatchMouseEvent
- * @protected
- * @param {DisplayObject} target
- * @param {String} type
- * @param {Boolean} bubbles
- * @param {Number} pointerId
- * @param {Object} o
- * @param {MouseEvent} [nativeEvent]
- * @param {DisplayObject} [relatedTarget]
- **/
- p._dispatchMouseEvent = function(target, type, bubbles, pointerId, o, nativeEvent, relatedTarget) {
- // TODO: might be worth either reusing MouseEvent instances, or adding a willTrigger method to avoid GC.
- if (!target || (!bubbles && !target.hasEventListener(type))) { return; }
- /*
- // TODO: account for stage transformations?
- this._mtx = this.getConcatenatedMatrix(this._mtx).invert();
- var pt = this._mtx.transformPoint(o.x, o.y);
- var evt = new createjs.MouseEvent(type, bubbles, false, pt.x, pt.y, nativeEvent, pointerId, pointerId==this._primaryPointerID || pointerId==-1, o.rawX, o.rawY);
- */
- var evt = new createjs.MouseEvent(type, bubbles, false, o.x, o.y, nativeEvent, pointerId, pointerId === this._primaryPointerID || pointerId === -1, o.rawX, o.rawY, relatedTarget);
- target.dispatchEvent(evt);
- };
-
-
- createjs.Stage = createjs.promote(Stage, "Container");
-}());
-
-//##############################################################################
-// Bitmap.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
-
- /**
- * A Bitmap represents an Image, Canvas, or Video in the display list. A Bitmap can be instantiated using an existing
- * HTML element, or a string.
- *
- *
Example
- *
- * var bitmap = new createjs.Bitmap("imagePath.jpg");
- *
- * Notes:
- *
- *
When a string path or image tag that is not yet loaded is used, the stage may need to be redrawn before it
- * will be displayed.
- *
Bitmaps with an SVG source currently will not respect an alpha value other than 0 or 1. To get around this,
- * the Bitmap can be cached.
- *
Bitmaps with an SVG source will taint the canvas with cross-origin data, which prevents interactivity. This
- * happens in all browsers except recent Firefox builds.
- *
Images loaded cross-origin will throw cross-origin security errors when interacted with using a mouse, using
- * methods such as `getObjectUnderPoint`, or using filters, or caching. You can get around this by setting
- * `crossOrigin` flags on your images before passing them to EaselJS, eg: `img.crossOrigin="Anonymous";`
- *
- *
- * @class Bitmap
- * @extends DisplayObject
- * @constructor
- * @param {HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | String} imageOrUri The source object or URI to an image to
- * display. This can be either an Image, Canvas, or Video object, or a string URI to an image file to load and use.
- * If it is a URI, a new Image object will be constructed and assigned to the .image property.
- **/
- function Bitmap(imageOrUri) {
- this.DisplayObject_constructor();
-
-
- // public properties:
- /**
- * The image to render. This can be an Image, a Canvas, or a Video. Not all browsers (especially
- * mobile browsers) support drawing video to a canvas.
- * @property image
- * @type HTMLImageElement | HTMLCanvasElement | HTMLVideoElement
- **/
- if (typeof imageOrUri == "string") {
- this.image = document.createElement("img");
- this.image.src = imageOrUri;
- } else {
- this.image = imageOrUri;
- }
-
- /**
- * Specifies an area of the source image to draw. If omitted, the whole image will be drawn.
- * Note that video sources must have a width / height set to work correctly with `sourceRect`.
- * @property sourceRect
- * @type Rectangle
- * @default null
- */
- this.sourceRect = null;
- }
- var p = createjs.extend(Bitmap, createjs.DisplayObject);
-
-
-// public methods:
- /**
- * Constructor alias for backwards compatibility. This method will be removed in future versions.
- * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}.
- * @method initialize
- * @deprecated in favour of `createjs.promote()`
- **/
- p.initialize = Bitmap; // TODO: deprecated.
-
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var image = this.image;
- var hasContent = this.cacheCanvas || (image && (image.naturalWidth || image.getContext || image.readyState >= 2));
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- * @return {Boolean}
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache) || !this.image) { return true; }
- var img = this.image, rect = this.sourceRect;
- if (rect) {
- // some browsers choke on out of bound values, so we'll fix them:
- var x1 = rect.x, y1 = rect.y, x2 = x1 + rect.width, y2 = y1 + rect.height, x = 0, y = 0, w = img.width, h = img.height;
- if (x1 < 0) { x -= x1; x1 = 0; }
- if (x2 > w) { x2 = w; }
- if (y1 < 0) { y -= y1; y1 = 0; }
- if (y2 > h) { y2 = h; }
- ctx.drawImage(img, x1, y1, x2-x1, y2-y1, x, y, x2-x1, y2-y1);
- } else {
- ctx.drawImage(img, 0, 0);
- }
- return true;
- };
-
- //Note, the doc sections below document using the specified APIs (from DisplayObject) from
- //Bitmap. This is why they have no method implementations.
-
- /**
- * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances.
- * You should not cache Bitmap instances as it can degrade performance.
- *
- * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work.
- * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}}
- * method.
- * @method cache
- **/
-
- /**
- * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances.
- * You should not cache Bitmap instances as it can degrade performance.
- *
- * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work.
- * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}}
- * method.
- * @method updateCache
- **/
-
- /**
- * Because the content of a Bitmap is already in a simple format, cache is unnecessary for Bitmap instances.
- * You should not cache Bitmap instances as it can degrade performance.
- *
- * However: If you want to use a filter on a Bitmap, you MUST cache it, or it will not work.
- * To see the API for caching, please visit the DisplayObject {{#crossLink "DisplayObject/cache"}}{{/crossLink}}
- * method.
- * @method uncache
- **/
-
- /**
- * Docced in superclass.
- */
- p.getBounds = function() {
- var rect = this.DisplayObject_getBounds();
- if (rect) { return rect; }
- var image = this.image, o = this.sourceRect || image;
- var hasContent = (image && (image.naturalWidth || image.getContext || image.readyState >= 2));
- return hasContent ? this._rectangle.setValues(0, 0, o.width, o.height) : null;
- };
-
- /**
- * Returns a clone of the Bitmap instance.
- * @method clone
- * @return {Bitmap} a clone of the Bitmap instance.
- **/
- p.clone = function() {
- var o = new Bitmap(this.image);
- if (this.sourceRect) { o.sourceRect = this.sourceRect.clone(); }
- this._cloneProps(o);
- return o;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Bitmap (name="+ this.name +")]";
- };
-
-
- createjs.Bitmap = createjs.promote(Bitmap, "DisplayObject");
-}());
-
-//##############################################################################
-// Sprite.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Displays a frame or sequence of frames (ie. an animation) from a SpriteSheet instance. A sprite sheet is a series of
- * images (usually animation frames) combined into a single image. For example, an animation consisting of 8 100x100
- * images could be combined into a 400x200 sprite sheet (4 frames across by 2 high). You can display individual frames,
- * play frames as an animation, and even sequence animations together.
- *
- * See the {{#crossLink "SpriteSheet"}}{{/crossLink}} class for more information on setting up frames and animations.
- *
- *
Example
- *
- * var instance = new createjs.Sprite(spriteSheet);
- * instance.gotoAndStop("frameName");
- *
- * Until {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} or {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}} is called,
- * only the first defined frame defined in the sprite sheet will be displayed.
- *
- * @class Sprite
- * @extends DisplayObject
- * @constructor
- * @param {SpriteSheet} spriteSheet The SpriteSheet instance to play back. This includes the source image(s), frame
- * dimensions, and frame data. See {{#crossLink "SpriteSheet"}}{{/crossLink}} for more information.
- * @param {String|Number} [frameOrAnimation] The frame number or animation to play initially.
- **/
- function Sprite(spriteSheet, frameOrAnimation) {
- this.DisplayObject_constructor();
-
-
- // public properties:
- /**
- * The frame index that will be drawn when draw is called. Note that with some {{#crossLink "SpriteSheet"}}{{/crossLink}}
- * definitions, this will advance non-sequentially. This will always be an integer value.
- * @property currentFrame
- * @type {Number}
- * @default 0
- * @readonly
- **/
- this.currentFrame = 0;
-
- /**
- * Returns the name of the currently playing animation.
- * @property currentAnimation
- * @type {String}
- * @final
- * @readonly
- **/
- this.currentAnimation = null;
-
- /**
- * Prevents the animation from advancing each tick automatically. For example, you could create a sprite
- * sheet of icons, set paused to true, and display the appropriate icon by setting currentFrame.
- * @property paused
- * @type {Boolean}
- * @default false
- **/
- this.paused = true;
-
- /**
- * The SpriteSheet instance to play back. This includes the source image, frame dimensions, and frame
- * data. See {{#crossLink "SpriteSheet"}}{{/crossLink}} for more information.
- * @property spriteSheet
- * @type {SpriteSheet}
- * @readonly
- **/
- this.spriteSheet = spriteSheet;
-
- /**
- * Specifies the current frame index within the currently playing animation. When playing normally, this will increase
- * from 0 to n-1, where n is the number of frames in the current animation.
- *
- * This could be a non-integer value if
- * using time-based playback (see {{#crossLink "Sprite/framerate"}}{{/crossLink}}, or if the animation's speed is
- * not an integer.
- * @property currentAnimationFrame
- * @type {Number}
- * @default 0
- **/
- this.currentAnimationFrame = 0;
-
- /**
- * By default Sprite instances advance one frame per tick. Specifying a framerate for the Sprite (or its related
- * SpriteSheet) will cause it to advance based on elapsed time between ticks as appropriate to maintain the target
- * framerate.
- *
- * For example, if a Sprite with a framerate of 10 is placed on a Stage being updated at 40fps, then the Sprite will
- * advance roughly one frame every 4 ticks. This will not be exact, because the time between each tick will
- * vary slightly between frames.
- *
- * This feature is dependent on the tick event object (or an object with an appropriate "delta" property) being
- * passed into {{#crossLink "Stage/update"}}{{/crossLink}}.
- * @property framerate
- * @type {Number}
- * @default 0
- **/
- this.framerate = 0;
-
-
- // private properties:
- /**
- * Current animation object.
- * @property _animation
- * @protected
- * @type {Object}
- * @default null
- **/
- this._animation = null;
-
- /**
- * Current frame index.
- * @property _currentFrame
- * @protected
- * @type {Number}
- * @default null
- **/
- this._currentFrame = null;
-
- /**
- * Skips the next auto advance. Used by gotoAndPlay to avoid immediately jumping to the next frame
- * @property _skipAdvance
- * @protected
- * @type {Boolean}
- * @default false
- **/
- this._skipAdvance = false;
-
-
- if (frameOrAnimation != null) { this.gotoAndPlay(frameOrAnimation); }
- }
- var p = createjs.extend(Sprite, createjs.DisplayObject);
-
- /**
- * Constructor alias for backwards compatibility. This method will be removed in future versions.
- * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}.
- * @method initialize
- * @deprecated in favour of `createjs.promote()`
- **/
- p.initialize = Sprite; // TODO: Deprecated. This is for backwards support of FlashCC spritesheet export.
-
-
-// events:
- /**
- * Dispatched when an animation reaches its ends.
- * @event animationend
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {String} name The name of the animation that just ended.
- * @param {String} next The name of the next animation that will be played, or null. This will be the same as name if the animation is looping.
- * @since 0.6.0
- */
-
- /**
- * Dispatched any time the current frame changes. For example, this could be due to automatic advancement on a tick,
- * or calling gotoAndPlay() or gotoAndStop().
- * @event change
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- */
-
-
-// public methods:
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var hasContent = this.cacheCanvas || this.spriteSheet.complete;
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
- this._normalizeFrame();
- var o = this.spriteSheet.getFrame(this._currentFrame|0);
- if (!o) { return false; }
- var rect = o.rect;
- if (rect.width && rect.height) { ctx.drawImage(o.image, rect.x, rect.y, rect.width, rect.height, -o.regX, -o.regY, rect.width, rect.height); }
- return true;
- };
-
- //Note, the doc sections below document using the specified APIs (from DisplayObject) from
- //Bitmap. This is why they have no method implementations.
-
- /**
- * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances.
- * You should not cache Sprite instances as it can degrade performance.
- * @method cache
- **/
-
- /**
- * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances.
- * You should not cache Sprite instances as it can degrade performance.
- * @method updateCache
- **/
-
- /**
- * Because the content of a Sprite is already in a raster format, cache is unnecessary for Sprite instances.
- * You should not cache Sprite instances as it can degrade performance.
- * @method uncache
- **/
-
- /**
- * Play (unpause) the current animation. The Sprite will be paused if either {{#crossLink "Sprite/stop"}}{{/crossLink}}
- * or {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} is called. Single frame animations will remain
- * unchanged.
- * @method play
- **/
- p.play = function() {
- this.paused = false;
- };
-
- /**
- * Stop playing a running animation. The Sprite will be playing if {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}}
- * is called. Note that calling {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}} or {{#crossLink "Sprite/play"}}{{/crossLink}}
- * will resume playback.
- * @method stop
- **/
- p.stop = function() {
- this.paused = true;
- };
-
- /**
- * Sets paused to false and plays the specified animation name, named frame, or frame number.
- * @method gotoAndPlay
- * @param {String|Number} frameOrAnimation The frame number or animation name that the playhead should move to
- * and begin playing.
- **/
- p.gotoAndPlay = function(frameOrAnimation) {
- this.paused = false;
- this._skipAdvance = true;
- this._goto(frameOrAnimation);
- };
-
- /**
- * Sets paused to true and seeks to the specified animation name, named frame, or frame number.
- * @method gotoAndStop
- * @param {String|Number} frameOrAnimation The frame number or animation name that the playhead should move to
- * and stop.
- **/
- p.gotoAndStop = function(frameOrAnimation) {
- this.paused = true;
- this._goto(frameOrAnimation);
- };
-
- /**
- * Advances the playhead. This occurs automatically each tick by default.
- * @param [time] {Number} The amount of time in ms to advance by. Only applicable if framerate is set on the Sprite
- * or its SpriteSheet.
- * @method advance
- */
- p.advance = function(time) {
- var fps = this.framerate || this.spriteSheet.framerate;
- var t = (fps && time != null) ? time/(1000/fps) : 1;
- this._normalizeFrame(t);
- };
-
- /**
- * Returns a {{#crossLink "Rectangle"}}{{/crossLink}} instance defining the bounds of the current frame relative to
- * the origin. For example, a 90 x 70 frame with regX=50 and regY=40 would return a
- * rectangle with [x=-50, y=-40, width=90, height=70]. This ignores transformations on the display object.
- *
- * Also see the SpriteSheet {{#crossLink "SpriteSheet/getFrameBounds"}}{{/crossLink}} method.
- * @method getBounds
- * @return {Rectangle} A Rectangle instance. Returns null if the frame does not exist, or the image is not fully
- * loaded.
- **/
- p.getBounds = function() {
- // TODO: should this normalizeFrame?
- return this.DisplayObject_getBounds() || this.spriteSheet.getFrameBounds(this.currentFrame, this._rectangle);
- };
-
- /**
- * Returns a clone of the Sprite instance. Note that the same SpriteSheet is shared between cloned
- * instances.
- * @method clone
- * @return {Sprite} a clone of the Sprite instance.
- **/
- p.clone = function() {
- return this._cloneProps(new Sprite(this.spriteSheet));
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Sprite (name="+ this.name +")]";
- };
-
-// private methods:
- /**
- * @method _cloneProps
- * @param {Sprite} o
- * @return {Sprite} o
- * @protected
- **/
- p._cloneProps = function(o) {
- this.DisplayObject__cloneProps(o);
- o.currentFrame = this.currentFrame;
- o.currentAnimation = this.currentAnimation;
- o.paused = this.paused;
- o.currentAnimationFrame = this.currentAnimationFrame;
- o.framerate = this.framerate;
-
- o._animation = this._animation;
- o._currentFrame = this._currentFrame;
- o._skipAdvance = this._skipAdvance;
- return o;
- };
-
- /**
- * Advances the currentFrame if paused is not true. This is called automatically when the {{#crossLink "Stage"}}{{/crossLink}}
- * ticks.
- * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
- * @protected
- * @method _tick
- **/
- p._tick = function(evtObj) {
- if (!this.paused) {
- if (!this._skipAdvance) { this.advance(evtObj&&evtObj.delta); }
- this._skipAdvance = false;
- }
- this.DisplayObject__tick(evtObj);
- };
-
-
- /**
- * Normalizes the current frame, advancing animations and dispatching callbacks as appropriate.
- * @protected
- * @method _normalizeFrame
- **/
- p._normalizeFrame = function(frameDelta) {
- frameDelta = frameDelta || 0;
- var animation = this._animation;
- var paused = this.paused;
- var frame = this._currentFrame;
- var l;
-
- if (animation) {
- var speed = animation.speed || 1;
- var animFrame = this.currentAnimationFrame;
- l = animation.frames.length;
- if (animFrame + frameDelta * speed >= l) {
- var next = animation.next;
- if (this._dispatchAnimationEnd(animation, frame, paused, next, l - 1)) {
- // something changed in the event stack, so we shouldn't make any more changes here.
- return;
- } else if (next) {
- // sequence. Automatically calls _normalizeFrame again with the remaining frames.
- return this._goto(next, frameDelta - (l - animFrame) / speed);
- } else {
- // end.
- this.paused = true;
- animFrame = animation.frames.length - 1;
- }
- } else {
- animFrame += frameDelta * speed;
- }
- this.currentAnimationFrame = animFrame;
- this._currentFrame = animation.frames[animFrame | 0]
- } else {
- frame = (this._currentFrame += frameDelta);
- l = this.spriteSheet.getNumFrames();
- if (frame >= l && l > 0) {
- if (!this._dispatchAnimationEnd(animation, frame, paused, l - 1)) {
- // looped.
- if ((this._currentFrame -= l) >= l) { return this._normalizeFrame(); }
- }
- }
- }
- frame = this._currentFrame | 0;
- if (this.currentFrame != frame) {
- this.currentFrame = frame;
- this.dispatchEvent("change");
- }
- };
-
- /**
- * Dispatches the "animationend" event. Returns true if a handler changed the animation (ex. calling {{#crossLink "Sprite/stop"}}{{/crossLink}},
- * {{#crossLink "Sprite/gotoAndPlay"}}{{/crossLink}}, etc.)
- * @property _dispatchAnimationEnd
- * @private
- * @type {Function}
- **/
- p._dispatchAnimationEnd = function(animation, frame, paused, next, end) {
- var name = animation ? animation.name : null;
- if (this.hasEventListener("animationend")) {
- var evt = new createjs.Event("animationend");
- evt.name = name;
- evt.next = next;
- this.dispatchEvent(evt);
- }
- // did the animation get changed in the event stack?:
- var changed = (this._animation != animation || this._currentFrame != frame);
- // if the animation hasn't changed, but the sprite was paused, then we want to stick to the last frame:
- if (!changed && !paused && this.paused) { this.currentAnimationFrame = end; changed = true; }
- return changed;
- };
-
- /**
- * Moves the playhead to the specified frame number or animation.
- * @method _goto
- * @param {String|Number} frameOrAnimation The frame number or animation that the playhead should move to.
- * @param {Boolean} [frame] The frame of the animation to go to. Defaults to 0.
- * @protected
- **/
- p._goto = function(frameOrAnimation, frame) {
- this.currentAnimationFrame = 0;
- if (isNaN(frameOrAnimation)) {
- var data = this.spriteSheet.getAnimation(frameOrAnimation);
- if (data) {
- this._animation = data;
- this.currentAnimation = frameOrAnimation;
- this._normalizeFrame(frame);
- }
- } else {
- this.currentAnimation = this._animation = null;
- this._currentFrame = frameOrAnimation;
- this._normalizeFrame();
- }
- };
-
-
- createjs.Sprite = createjs.promote(Sprite, "DisplayObject");
-}());
-
-//##############################################################################
-// Shape.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * A Shape allows you to display vector art in the display list. It composites a {{#crossLink "Graphics"}}{{/crossLink}}
- * instance which exposes all of the vector drawing methods. The Graphics instance can be shared between multiple Shape
- * instances to display the same vector graphics with different positions or transforms.
- *
- * If the vector art will not
- * change between draws, you may want to use the {{#crossLink "DisplayObject/cache"}}{{/crossLink}} method to reduce the
- * rendering cost.
- *
- *
Example
- *
- * var graphics = new createjs.Graphics().beginFill("#ff0000").drawRect(0, 0, 100, 100);
- * var shape = new createjs.Shape(graphics);
- *
- * //Alternatively use can also use the graphics property of the Shape class to renderer the same as above.
- * var shape = new createjs.Shape();
- * shape.graphics.beginFill("#ff0000").drawRect(0, 0, 100, 100);
- *
- * @class Shape
- * @extends DisplayObject
- * @constructor
- * @param {Graphics} graphics Optional. The graphics instance to display. If null, a new Graphics instance will be created.
- **/
- function Shape(graphics) {
- this.DisplayObject_constructor();
-
-
- // public properties:
- /**
- * The graphics instance to display.
- * @property graphics
- * @type Graphics
- **/
- this.graphics = graphics ? graphics : new createjs.Graphics();
- }
- var p = createjs.extend(Shape, createjs.DisplayObject);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /**
- * Returns true or false indicating whether the Shape would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the Shape would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var hasContent = this.cacheCanvas || (this.graphics && !this.graphics.isEmpty());
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent);
- };
-
- /**
- * Draws the Shape into the specified context ignoring its visible, alpha, shadow, and transform. Returns true if
- * the draw was handled (useful for overriding functionality).
- *
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} [ignoreCache=false] Indicates whether the draw operation should ignore any current cache. For example,
- * used for drawing the cache (to prevent it from simply drawing an existing cache back into itself).
- * @return {Boolean}
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
- this.graphics.draw(ctx, this);
- return true;
- };
-
- /**
- * Returns a clone of this Shape. Some properties that are specific to this instance's current context are reverted to
- * their defaults (for example .parent).
- * @method clone
- * @param {Boolean} recursive If true, this Shape's {{#crossLink "Graphics"}}{{/crossLink}} instance will also be
- * cloned. If false, the Graphics instance will be shared with the new Shape.
- **/
- p.clone = function(recursive) {
- var g = (recursive && this.graphics) ? this.graphics.clone() : this.graphics;
- return this._cloneProps(new Shape(g));
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Shape (name="+ this.name +")]";
- };
-
-
- createjs.Shape = createjs.promote(Shape, "DisplayObject");
-}());
-
-//##############################################################################
-// Text.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Display one or more lines of dynamic text (not user editable) in the display list. Line wrapping support (using the
- * lineWidth) is very basic, wrapping on spaces and tabs only. Note that as an alternative to Text, you can position HTML
- * text above or below the canvas relative to items in the display list using the {{#crossLink "DisplayObject/localToGlobal"}}{{/crossLink}}
- * method, or using {{#crossLink "DOMElement"}}{{/crossLink}}.
- *
- * Please note that Text does not support HTML text, and can only display one font style at a time. To use
- * multiple font styles, you will need to create multiple text instances, and position them manually.
- *
- *
Example
- *
- * var text = new createjs.Text("Hello World", "20px Arial", "#ff7700");
- * text.x = 100;
- * text.textBaseline = "alphabetic";
- *
- * CreateJS Text supports web fonts (the same rules as Canvas). The font must be loaded and supported by the browser
- * before it can be displayed.
- *
- * Note: Text can be expensive to generate, so cache instances where possible. Be aware that not all
- * browsers will render Text exactly the same.
- * @class Text
- * @extends DisplayObject
- * @constructor
- * @param {String} [text] The text to display.
- * @param {String} [font] The font style to use. Any valid value for the CSS font attribute is acceptable (ex. "bold
- * 36px Arial").
- * @param {String} [color] The color to draw the text in. Any valid value for the CSS color attribute is acceptable (ex.
- * "#F00", "red", or "#FF0000").
- **/
- function Text(text, font, color) {
- this.DisplayObject_constructor();
-
-
- // public properties:
- /**
- * The text to display.
- * @property text
- * @type String
- **/
- this.text = text;
-
- /**
- * The font style to use. Any valid value for the CSS font attribute is acceptable (ex. "bold 36px Arial").
- * @property font
- * @type String
- **/
- this.font = font;
-
- /**
- * The color to draw the text in. Any valid value for the CSS color attribute is acceptable (ex. "#F00"). Default is "#000".
- * It will also accept valid canvas fillStyle values.
- * @property color
- * @type String
- **/
- this.color = color;
-
- /**
- * The horizontal text alignment. Any of "start", "end", "left", "right", and "center". For detailed
- * information view the
- *
- * whatwg spec. Default is "left".
- * @property textAlign
- * @type String
- **/
- this.textAlign = "left";
-
- /**
- * The vertical alignment point on the font. Any of "top", "hanging", "middle", "alphabetic", "ideographic", or
- * "bottom". For detailed information view the
- * whatwg spec. Default is "top".
- * @property textBaseline
- * @type String
- */
- this.textBaseline = "top";
-
- /**
- * The maximum width to draw the text. If maxWidth is specified (not null), the text will be condensed or
- * shrunk to make it fit in this width. For detailed information view the
- *
- * whatwg spec.
- * @property maxWidth
- * @type Number
- */
- this.maxWidth = null;
-
- /**
- * If greater than 0, the text will be drawn as a stroke (outline) of the specified width.
- * @property outline
- * @type Number
- **/
- this.outline = 0;
-
- /**
- * Indicates the line height (vertical distance between baselines) for multi-line text. If null or 0,
- * the value of getMeasuredLineHeight is used.
- * @property lineHeight
- * @type Number
- **/
- this.lineHeight = 0;
-
- /**
- * Indicates the maximum width for a line of text before it is wrapped to multiple lines. If null,
- * the text will not be wrapped.
- * @property lineWidth
- * @type Number
- **/
- this.lineWidth = null;
- }
- var p = createjs.extend(Text, createjs.DisplayObject);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// static properties:
- /**
- * @property _workingContext
- * @type CanvasRenderingContext2D
- * @private
- **/
- var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"));
- if (canvas.getContext) { Text._workingContext = canvas.getContext("2d"); canvas.width = canvas.height = 1; }
-
-
-// constants:
- /**
- * Lookup table for the ratio to offset bounds x calculations based on the textAlign property.
- * @property H_OFFSETS
- * @type Object
- * @protected
- * @static
- **/
- Text.H_OFFSETS = {start: 0, left: 0, center: -0.5, end: -1, right: -1};
-
- /**
- * Lookup table for the ratio to offset bounds y calculations based on the textBaseline property.
- * @property H_OFFSETS
- * @type Object
- * @protected
- * @static
- **/
- Text.V_OFFSETS = {top: 0, hanging: -0.01, middle: -0.4, alphabetic: -0.8, ideographic: -0.85, bottom: -1};
-
-
-// public methods:
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var hasContent = this.cacheCanvas || (this.text != null && this.text !== "");
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0 && hasContent);
- };
-
- /**
- * Draws the Text into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
-
- var col = this.color || "#000";
- if (this.outline) { ctx.strokeStyle = col; ctx.lineWidth = this.outline*1; }
- else { ctx.fillStyle = col; }
-
- this._drawText(this._prepContext(ctx));
- return true;
- };
-
- /**
- * Returns the measured, untransformed width of the text without wrapping. Use getBounds for a more robust value.
- * @method getMeasuredWidth
- * @return {Number} The measured, untransformed width of the text.
- **/
- p.getMeasuredWidth = function() {
- return this._getMeasuredWidth(this.text);
- };
-
- /**
- * Returns an approximate line height of the text, ignoring the lineHeight property. This is based on the measured
- * width of a "M" character multiplied by 1.2, which provides an approximate line height for most fonts.
- * @method getMeasuredLineHeight
- * @return {Number} an approximate line height of the text, ignoring the lineHeight property. This is
- * based on the measured width of a "M" character multiplied by 1.2, which approximates em for most fonts.
- **/
- p.getMeasuredLineHeight = function() {
- return this._getMeasuredWidth("M")*1.2;
- };
-
- /**
- * Returns the approximate height of multi-line text by multiplying the number of lines against either the
- * lineHeight (if specified) or {{#crossLink "Text/getMeasuredLineHeight"}}{{/crossLink}}. Note that
- * this operation requires the text flowing logic to run, which has an associated CPU cost.
- * @method getMeasuredHeight
- * @return {Number} The approximate height of the untransformed multi-line text.
- **/
- p.getMeasuredHeight = function() {
- return this._drawText(null,{}).height;
- };
-
- /**
- * Docced in superclass.
- */
- p.getBounds = function() {
- var rect = this.DisplayObject_getBounds();
- if (rect) { return rect; }
- if (this.text == null || this.text === "") { return null; }
- var o = this._drawText(null, {});
- var w = (this.maxWidth && this.maxWidth < o.width) ? this.maxWidth : o.width;
- var x = w * Text.H_OFFSETS[this.textAlign||"left"];
- var lineHeight = this.lineHeight||this.getMeasuredLineHeight();
- var y = lineHeight * Text.V_OFFSETS[this.textBaseline||"top"];
- return this._rectangle.setValues(x, y, w, o.height);
- };
-
- /**
- * Returns an object with width, height, and lines properties. The width and height are the visual width and height
- * of the drawn text. The lines property contains an array of strings, one for
- * each line of text that will be drawn, accounting for line breaks and wrapping. These strings have trailing
- * whitespace removed.
- * @method getMetrics
- * @return {Object} An object with width, height, and lines properties.
- **/
- p.getMetrics = function() {
- var o = {lines:[]};
- o.lineHeight = this.lineHeight || this.getMeasuredLineHeight();
- o.vOffset = o.lineHeight * Text.V_OFFSETS[this.textBaseline||"top"];
- return this._drawText(null, o, o.lines);
- };
-
- /**
- * Returns a clone of the Text instance.
- * @method clone
- * @return {Text} a clone of the Text instance.
- **/
- p.clone = function() {
- return this._cloneProps(new Text(this.text, this.font, this.color));
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Text (text="+ (this.text.length > 20 ? this.text.substr(0, 17)+"..." : this.text) +")]";
- };
-
-
-// private methods:
- /**
- * @method _cloneProps
- * @param {Text} o
- * @protected
- * @return {Text} o
- **/
- p._cloneProps = function(o) {
- this.DisplayObject__cloneProps(o);
- o.textAlign = this.textAlign;
- o.textBaseline = this.textBaseline;
- o.maxWidth = this.maxWidth;
- o.outline = this.outline;
- o.lineHeight = this.lineHeight;
- o.lineWidth = this.lineWidth;
- return o;
- };
-
- /**
- * @method _getWorkingContext
- * @param {CanvasRenderingContext2D} ctx
- * @return {CanvasRenderingContext2D}
- * @protected
- **/
- p._prepContext = function(ctx) {
- ctx.font = this.font||"10px sans-serif";
- ctx.textAlign = this.textAlign||"left";
- ctx.textBaseline = this.textBaseline||"top";
- return ctx;
- };
-
- /**
- * Draws multiline text.
- * @method _drawText
- * @param {CanvasRenderingContext2D} ctx
- * @param {Object} o
- * @param {Array} lines
- * @return {Object}
- * @protected
- **/
- p._drawText = function(ctx, o, lines) {
- var paint = !!ctx;
- if (!paint) {
- ctx = Text._workingContext;
- ctx.save();
- this._prepContext(ctx);
- }
- var lineHeight = this.lineHeight||this.getMeasuredLineHeight();
-
- var maxW = 0, count = 0;
- var hardLines = String(this.text).split(/(?:\r\n|\r|\n)/);
- for (var i=0, l=hardLines.length; i this.lineWidth) {
- // text wrapping:
- var words = str.split(/(\s)/);
- str = words[0];
- w = ctx.measureText(str).width;
-
- for (var j=1, jl=words.length; j this.lineWidth) {
- if (paint) { this._drawTextLine(ctx, str, count*lineHeight); }
- if (lines) { lines.push(str); }
- if (w > maxW) { maxW = w; }
- str = words[j+1];
- w = ctx.measureText(str).width;
- count++;
- } else {
- str += words[j] + words[j+1];
- w += wordW;
- }
- }
- }
-
- if (paint) { this._drawTextLine(ctx, str, count*lineHeight); }
- if (lines) { lines.push(str); }
- if (o && w == null) { w = ctx.measureText(str).width; }
- if (w > maxW) { maxW = w; }
- count++;
- }
-
- if (o) {
- o.width = maxW;
- o.height = count*lineHeight;
- }
- if (!paint) { ctx.restore(); }
- return o;
- };
-
- /**
- * @method _drawTextLine
- * @param {CanvasRenderingContext2D} ctx
- * @param {String} text
- * @param {Number} y
- * @protected
- **/
- p._drawTextLine = function(ctx, text, y) {
- // Chrome 17 will fail to draw the text if the last param is included but null, so we feed it a large value instead:
- if (this.outline) { ctx.strokeText(text, 0, y, this.maxWidth||0xFFFF); }
- else { ctx.fillText(text, 0, y, this.maxWidth||0xFFFF); }
- };
-
-
- /**
- * @method _getMeasuredWidth
- * @param {String} text
- * @protected
- **/
- p._getMeasuredWidth = function(text) {
- var ctx = Text._workingContext;
- ctx.save();
- var w = this._prepContext(ctx).measureText(text).width;
- ctx.restore();
- return w;
- };
-
-
- createjs.Text = createjs.promote(Text, "DisplayObject");
-}());
-
-//##############################################################################
-// BitmapText.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-
-// constructor:
- /**
- * Displays text using bitmap glyphs defined in a sprite sheet. Multi-line text is supported
- * using new line characters, but automatic wrapping is not supported. See the
- * {{#crossLink "BitmapText/spriteSheet:property"}}{{/crossLink}}
- * property for more information on defining glyphs.
- *
- * Important: BitmapText extends Container, but is not designed to be used as one.
- * As such, methods like addChild and removeChild are disabled.
- * @class BitmapText
- * @extends DisplayObject
- * @param {String} [text=""] The text to display.
- * @param {SpriteSheet} [spriteSheet=null] The spritesheet that defines the character glyphs.
- * @constructor
- **/
- function BitmapText(text, spriteSheet) {
- this.Container_constructor();
-
-
- // public properties:
- /**
- * The text to display.
- * @property text
- * @type String
- * @default ""
- **/
- this.text = text||"";
-
- /**
- * A SpriteSheet instance that defines the glyphs for this bitmap text. Each glyph/character
- * should have a single frame animation defined in the sprite sheet named the same as
- * corresponding character. For example, the following animation definition:
- *
- * "A": {frames: [0]}
- *
- * would indicate that the frame at index 0 of the spritesheet should be drawn for the "A" character. The short form
- * is also acceptable:
- *
- * "A": 0
- *
- * Note that if a character in the text is not found in the sprite sheet, it will also
- * try to use the alternate case (upper or lower).
- *
- * See SpriteSheet for more information on defining sprite sheet data.
- * @property spriteSheet
- * @type SpriteSheet
- * @default null
- **/
- this.spriteSheet = spriteSheet;
-
- /**
- * The height of each line of text. If 0, then it will use a line height calculated
- * by checking for the height of the "1", "T", or "L" character (in that order). If
- * those characters are not defined, it will use the height of the first frame of the
- * sprite sheet.
- * @property lineHeight
- * @type Number
- * @default 0
- **/
- this.lineHeight = 0;
-
- /**
- * This spacing (in pixels) will be added after each character in the output.
- * @property letterSpacing
- * @type Number
- * @default 0
- **/
- this.letterSpacing = 0;
-
- /**
- * If a space character is not defined in the sprite sheet, then empty pixels equal to
- * spaceWidth will be inserted instead. If 0, then it will use a value calculated
- * by checking for the width of the "1", "l", "E", or "A" character (in that order). If
- * those characters are not defined, it will use the width of the first frame of the
- * sprite sheet.
- * @property spaceWidth
- * @type Number
- * @default 0
- **/
- this.spaceWidth = 0;
-
-
- // private properties:
- /**
- * @property _oldProps
- * @type Object
- * @protected
- **/
- this._oldProps = {text:0,spriteSheet:0,lineHeight:0,letterSpacing:0,spaceWidth:0};
- }
- var p = createjs.extend(BitmapText, createjs.Container);
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-// static properties:
- /**
- * BitmapText uses Sprite instances to draw text. To reduce the creation and destruction of instances (and thus garbage collection), it maintains
- * an internal object pool of sprite instances to reuse. Increasing this value can cause more sprites to be
- * retained, slightly increasing memory use, but reducing instantiation.
- * @property maxPoolSize
- * @type Number
- * @static
- * @default 100
- **/
- BitmapText.maxPoolSize = 100;
-
- /**
- * Sprite object pool.
- * @type {Array}
- * @static
- * @private
- */
- BitmapText._spritePool = [];
-
-
-// public methods:
- /**
- * Docced in superclass.
- **/
- p.draw = function(ctx, ignoreCache) {
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return; }
- this._updateText();
- this.Container_draw(ctx, ignoreCache);
- };
-
- /**
- * Docced in superclass.
- **/
- p.getBounds = function() {
- this._updateText();
- return this.Container_getBounds();
- };
-
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- var hasContent = this.cacheCanvas || (this.spriteSheet && this.spriteSheet.complete && this.text);
- return !!(this.visible && this.alpha > 0 && this.scaleX !== 0 && this.scaleY !== 0 && hasContent);
- };
-
- p.clone = function() {
- return this._cloneProps(new BitmapText(this.text, this.spriteSheet));
- };
-
- /**
- * Disabled in BitmapText.
- * @method addChild
- **/
- /**
- * Disabled in BitmapText.
- * @method addChildAt
- **/
- /**
- * Disabled in BitmapText.
- * @method removeChild
- **/
- /**
- * Disabled in BitmapText.
- * @method removeChildAt
- **/
- /**
- * Disabled in BitmapText.
- * @method removeAllChildren
- **/
- p.addChild = p.addChildAt = p.removeChild = p.removeChildAt = p.removeAllChildren = function() {};
-
-
-// private methods:
- /**
- * @method _cloneProps
- * @param {BitmapText} o
- * @return {BitmapText} o
- * @protected
- **/
- p._cloneProps = function(o) {
- this.Container__cloneProps(o);
- o.lineHeight = this.lineHeight;
- o.letterSpacing = this.letterSpacing;
- o.spaceWidth = this.spaceWidth;
- return o;
- };
-
- /**
- * @method _getFrameIndex
- * @param {String} character
- * @param {SpriteSheet} spriteSheet
- * @return {Number}
- * @protected
- **/
- p._getFrameIndex = function(character, spriteSheet) {
- var c, o = spriteSheet.getAnimation(character);
- if (!o) {
- (character != (c = character.toUpperCase())) || (character != (c = character.toLowerCase())) || (c=null);
- if (c) { o = spriteSheet.getAnimation(c); }
- }
- return o && o.frames[0];
- };
-
- /**
- * @method _getFrame
- * @param {String} character
- * @param {SpriteSheet} spriteSheet
- * @return {Object}
- * @protected
- **/
- p._getFrame = function(character, spriteSheet) {
- var index = this._getFrameIndex(character, spriteSheet);
- return index == null ? index : spriteSheet.getFrame(index);
- };
-
- /**
- * @method _getLineHeight
- * @param {SpriteSheet} ss
- * @return {Number}
- * @protected
- **/
- p._getLineHeight = function(ss) {
- var frame = this._getFrame("1",ss) || this._getFrame("T",ss) || this._getFrame("L",ss) || ss.getFrame(0);
- return frame ? frame.rect.height : 1;
- };
- /**
- * @method _getSpaceWidth
- * @param {SpriteSheet} ss
- * @return {Number}
- * @protected
- **/
- p._getSpaceWidth = function(ss) {
- var frame = this._getFrame("1",ss) || this._getFrame("l",ss) || this._getFrame("e",ss) || this._getFrame("a",ss) || ss.getFrame(0);
- return frame ? frame.rect.width : 1;
- };
-
- /**
- * @method _drawText
- * @protected
- **/
- p._updateText = function() {
- var x=0, y=0, o=this._oldProps, change=false, spaceW=this.spaceWidth, lineH=this.lineHeight, ss=this.spriteSheet;
- var pool=BitmapText._spritePool, kids=this.children, childIndex=0, numKids=kids.length, sprite;
-
- for (var n in o) {
- if (o[n] != this[n]) {
- o[n] = this[n];
- change = true;
- }
- }
- if (!change) { return; }
-
- var hasSpace = !!this._getFrame(" ", ss);
- if (!hasSpace && !spaceW) { spaceW = this._getSpaceWidth(ss); }
- if (!lineH) { lineH = this._getLineHeight(ss); }
-
- for(var i=0, l=this.text.length; i childIndex) {
- // faster than removeChild.
- pool.push(sprite = kids.pop());
- sprite.parent = null;
- numKids--;
- }
- if (pool.length > BitmapText.maxPoolSize) { pool.length = BitmapText.maxPoolSize; }
- };
-
-
- createjs.BitmapText = createjs.promote(BitmapText, "Container");
-}());
-
-//##############################################################################
-// MovieClip.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * The MovieClip class associates a TweenJS Timeline with an EaselJS {{#crossLink "Container"}}{{/crossLink}}. It allows
- * you to create objects which encapsulate timeline animations, state changes, and synched actions. Due to the
- * complexities inherent in correctly setting up a MovieClip, it is largely intended for tool output and is not included
- * in the main EaselJS library.
- *
- * Currently MovieClip only works properly if it is tick based (as opposed to time based) though some concessions have
- * been made to support time-based timelines in the future.
- *
- *
Example
- * This example animates two shapes back and forth. The grey shape starts on the left, but we jump to a mid-point in
- * the animation using {{#crossLink "MovieClip/gotoAndPlay"}}{{/crossLink}}.
- *
- * var stage = new createjs.Stage("canvas");
- * createjs.Ticker.addEventListener("tick", stage);
- *
- * var mc = new createjs.MovieClip(null, 0, true, {start:20});
- * stage.addChild(mc);
- *
- * var child1 = new createjs.Shape(
- * new createjs.Graphics().beginFill("#999999")
- * .drawCircle(30,30,30));
- * var child2 = new createjs.Shape(
- * new createjs.Graphics().beginFill("#5a9cfb")
- * .drawCircle(30,30,30));
- *
- * mc.timeline.addTween(
- * createjs.Tween.get(child1)
- * .to({x:0}).to({x:60}, 50).to({x:0}, 50));
- * mc.timeline.addTween(
- * createjs.Tween.get(child2)
- * .to({x:60}).to({x:0}, 50).to({x:60}, 50));
- *
- * mc.gotoAndPlay("start");
- *
- * It is recommended to use tween.to() to animate and set properties (use no duration to have it set
- * immediately), and the tween.wait() method to create delays between animations. Note that using the
- * tween.set() method to affect properties will likely not provide the desired result.
- *
- * @class MovieClip
- * @main MovieClip
- * @extends Container
- * @constructor
- * @param {String} [mode=independent] Initial value for the mode property. One of {{#crossLink "MovieClip/INDEPENDENT:property"}}{{/crossLink}},
- * {{#crossLink "MovieClip/SINGLE_FRAME:property"}}{{/crossLink}}, or {{#crossLink "MovieClip/SYNCHED:property"}}{{/crossLink}}.
- * The default is {{#crossLink "MovieClip/INDEPENDENT:property"}}{{/crossLink}}.
- * @param {Number} [startPosition=0] Initial value for the {{#crossLink "MovieClip/startPosition:property"}}{{/crossLink}}
- * property.
- * @param {Boolean} [loop=true] Initial value for the {{#crossLink "MovieClip/loop:property"}}{{/crossLink}}
- * property. The default is `true`.
- * @param {Object} [labels=null] A hash of labels to pass to the {{#crossLink "MovieClip/timeline:property"}}{{/crossLink}}
- * instance associated with this MovieClip. Labels only need to be passed if they need to be used.
- **/
- function MovieClip(mode, startPosition, loop, labels) {
- this.Container_constructor();
- !MovieClip.inited&&MovieClip.init(); // static init
-
-
- // public properties:
- /**
- * Controls how this MovieClip advances its time. Must be one of 0 (INDEPENDENT), 1 (SINGLE_FRAME), or 2 (SYNCHED).
- * See each constant for a description of the behaviour.
- * @property mode
- * @type String
- * @default null
- **/
- this.mode = mode||MovieClip.INDEPENDENT;
-
- /**
- * Specifies what the first frame to play in this movieclip, or the only frame to display if mode is SINGLE_FRAME.
- * @property startPosition
- * @type Number
- * @default 0
- */
- this.startPosition = startPosition || 0;
-
- /**
- * Indicates whether this MovieClip should loop when it reaches the end of its timeline.
- * @property loop
- * @type Boolean
- * @default true
- */
- this.loop = loop;
-
- /**
- * The current frame of the movieclip.
- * @property currentFrame
- * @type Number
- * @default 0
- * @readonly
- */
- this.currentFrame = 0;
-
- /**
- * The TweenJS Timeline that is associated with this MovieClip. This is created automatically when the MovieClip
- * instance is initialized. Animations are created by adding TweenJS Tween
- * instances to the timeline.
- *
- *
Example
- *
- * var tween = createjs.Tween.get(target).to({x:0}).to({x:100}, 30);
- * var mc = new createjs.MovieClip();
- * mc.timeline.addTween(tween);
- *
- * Elements can be added and removed from the timeline by toggling an "_off" property
- * using the tweenInstance.to() method. Note that using Tween.set is not recommended to
- * create MovieClip animations. The following example will toggle the target off on frame 0, and then back on for
- * frame 1. You can use the "visible" property to achieve the same effect.
- *
- * var tween = createjs.Tween.get(target).to({_off:false})
- * .wait(1).to({_off:true})
- * .wait(1).to({_off:false});
- *
- * @property timeline
- * @type Timeline
- * @default null
- */
- this.timeline = new createjs.Timeline(null, labels, {paused:true, position:startPosition, useTicks:true});
-
- /**
- * If true, the MovieClip's position will not advance when ticked.
- * @property paused
- * @type Boolean
- * @default false
- */
- this.paused = false;
-
- /**
- * If true, actions in this MovieClip's tweens will be run when the playhead advances.
- * @property actionsEnabled
- * @type Boolean
- * @default true
- */
- this.actionsEnabled = true;
-
- /**
- * If true, the MovieClip will automatically be reset to its first frame whenever the timeline adds
- * it back onto the display list. This only applies to MovieClip instances with mode=INDEPENDENT.
- *
- * For example, if you had a character animation with a "body" child MovieClip instance
- * with different costumes on each frame, you could set body.autoReset = false, so that
- * you can manually change the frame it is on, without worrying that it will be reset
- * automatically.
- * @property autoReset
- * @type Boolean
- * @default true
- */
- this.autoReset = true;
-
- /**
- * An array of bounds for each frame in the MovieClip. This is mainly intended for tool output.
- * @property frameBounds
- * @type Array
- * @default null
- */
- this.frameBounds = this.frameBounds||null; // TODO: Deprecated. This is for backwards support of FlashCC
-
- /**
- * By default MovieClip instances advance one frame per tick. Specifying a framerate for the MovieClip
- * will cause it to advance based on elapsed time between ticks as appropriate to maintain the target
- * framerate.
- *
- * For example, if a MovieClip with a framerate of 10 is placed on a Stage being updated at 40fps, then the MovieClip will
- * advance roughly one frame every 4 ticks. This will not be exact, because the time between each tick will
- * vary slightly between frames.
- *
- * This feature is dependent on the tick event object (or an object with an appropriate "delta" property) being
- * passed into {{#crossLink "Stage/update"}}{{/crossLink}}.
- * @property framerate
- * @type {Number}
- * @default null
- **/
- this.framerate = null;
-
-
- // private properties:
- /**
- * @property _synchOffset
- * @type Number
- * @default 0
- * @private
- */
- this._synchOffset = 0;
-
- /**
- * @property _prevPos
- * @type Number
- * @default -1
- * @private
- */
- this._prevPos = -1; // TODO: evaluate using a ._reset Boolean prop instead of -1.
-
- /**
- * @property _prevPosition
- * @type Number
- * @default 0
- * @private
- */
- this._prevPosition = 0;
-
- /**
- * The time remaining from the previous tick, only applicable when .framerate is set.
- * @property _t
- * @type Number
- * @private
- */
- this._t = 0;
-
- /**
- * List of display objects that are actively being managed by the MovieClip.
- * @property _managed
- * @type Object
- * @private
- */
- this._managed = {};
- }
- var p = createjs.extend(MovieClip, createjs.Container);
-
-
-// constants:
- /**
- * The MovieClip will advance independently of its parent, even if its parent is paused.
- * This is the default mode.
- * @property INDEPENDENT
- * @static
- * @type String
- * @default "independent"
- * @readonly
- **/
- MovieClip.INDEPENDENT = "independent";
-
- /**
- * The MovieClip will only display a single frame (as determined by the startPosition property).
- * @property SINGLE_FRAME
- * @static
- * @type String
- * @default "single"
- * @readonly
- **/
- MovieClip.SINGLE_FRAME = "single";
-
- /**
- * The MovieClip will be advanced only when its parent advances and will be synched to the position of
- * the parent MovieClip.
- * @property SYNCHED
- * @static
- * @type String
- * @default "synched"
- * @readonly
- **/
- MovieClip.SYNCHED = "synched";
-
-
-// static properties:
- MovieClip.inited = false;
-
-
-// static methods:
- MovieClip.init = function() {
- if (MovieClip.inited) { return; }
- // plugins introduce some overhead to Tween, so we only install this if an MC is instantiated.
- MovieClipPlugin.install();
- MovieClip.inited = true;
- };
-
-
-// getter / setters:
- /**
- * Use the {{#crossLink "MovieClip/labels:property"}}{{/crossLink}} property instead.
- * @method getLabels
- * @return {Array}
- * @deprecated
- **/
- p.getLabels = function() {
- return this.timeline.getLabels();
- };
-
- /**
- * Use the {{#crossLink "MovieClip/currentLabel:property"}}{{/crossLink}} property instead.
- * @method getCurrentLabel
- * @return {String}
- * @deprecated
- **/
- p.getCurrentLabel = function() {
- this._updateTimeline();
- return this.timeline.getCurrentLabel();
- };
-
- /**
- * Use the {{#crossLink "MovieClip/duration:property"}}{{/crossLink}} property instead.
- * @method getDuration
- * @return {Number}
- * @protected
- **/
- p.getDuration = function() {
- return this.timeline.duration;
- };
-
- /**
- * Returns an array of objects with label and position (aka frame) properties, sorted by position.
- * Shortcut to TweenJS: Timeline.getLabels();
- * @property labels
- * @type {Array}
- * @readonly
- **/
-
- /**
- * Returns the name of the label on or immediately before the current frame. See TweenJS: Timeline.getCurrentLabel()
- * for more information.
- * @property currentLabel
- * @type {String}
- * @readonly
- **/
-
- /**
- * Returns the duration of this MovieClip in seconds or ticks. Identical to {{#crossLink "MovieClip/duration:property"}}{{/crossLink}}
- * and provided for Flash API compatibility.
- * @property totalFrames
- * @type {Number}
- * @readonly
- **/
-
- /**
- * Returns the duration of this MovieClip in seconds or ticks.
- * @property duration
- * @type {Number}
- * @readonly
- **/
- try {
- Object.defineProperties(p, {
- labels: { get: p.getLabels },
- currentLabel: { get: p.getCurrentLabel },
- totalFrames: { get: p.getDuration },
- duration: { get: p.getDuration }
- });
- } catch (e) {}
-
-
-// public methods:
- /**
- * Constructor alias for backwards compatibility. This method will be removed in future versions.
- * Subclasses should be updated to use {{#crossLink "Utility Methods/extends"}}{{/crossLink}}.
- * @method initialize
- * @deprecated in favour of `createjs.promote()`
- **/
- p.initialize = MovieClip; // TODO: Deprecated. This is for backwards support of FlashCC
-
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- **/
- p.isVisible = function() {
- // children are placed in draw, so we can't determine if we have content.
- return !!(this.visible && this.alpha > 0 && this.scaleX != 0 && this.scaleY != 0);
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- **/
- p.draw = function(ctx, ignoreCache) {
- // draw to cache first:
- if (this.DisplayObject_draw(ctx, ignoreCache)) { return true; }
- this._updateTimeline();
- this.Container_draw(ctx, ignoreCache);
- return true;
- };
-
- /**
- * Sets paused to false.
- * @method play
- **/
- p.play = function() {
- this.paused = false;
- };
-
- /**
- * Sets paused to true.
- * @method stop
- **/
- p.stop = function() {
- this.paused = true;
- };
-
- /**
- * Advances this movie clip to the specified position or label and sets paused to false.
- * @method gotoAndPlay
- * @param {String|Number} positionOrLabel The animation name or frame number to go to.
- **/
- p.gotoAndPlay = function(positionOrLabel) {
- this.paused = false;
- this._goto(positionOrLabel);
- };
-
- /**
- * Advances this movie clip to the specified position or label and sets paused to true.
- * @method gotoAndStop
- * @param {String|Number} positionOrLabel The animation or frame name to go to.
- **/
- p.gotoAndStop = function(positionOrLabel) {
- this.paused = true;
- this._goto(positionOrLabel);
- };
-
- /**
- * Advances the playhead. This occurs automatically each tick by default.
- * @param [time] {Number} The amount of time in ms to advance by. Only applicable if framerate is set.
- * @method advance
- */
- p.advance = function(time) {
- // TODO: should we worry at all about clips who change their own modes via frame scripts?
- var independent = MovieClip.INDEPENDENT;
- if (this.mode != independent) { return; }
-
- var o=this, fps = o.framerate;
- while ((o = o.parent) && fps == null) {
- if (o.mode == independent) { fps = o._framerate; }
- }
- this._framerate = fps;
-
- var t = (fps != null && fps != -1 && time != null) ? time/(1000/fps) + this._t : 1;
- var frames = t|0;
- this._t = t-frames; // leftover time
-
- while (!this.paused && frames--) {
- this._prevPosition = (this._prevPos < 0) ? 0 : this._prevPosition+1;
- this._updateTimeline();
- }
- };
-
- /**
- * MovieClip instances cannot be cloned.
- * @method clone
- **/
- p.clone = function() {
- // TODO: add support for this? Need to clone the Timeline & retarget tweens - pretty complex.
- throw("MovieClip cannot be cloned.")
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[MovieClip (name="+ this.name +")]";
- };
-
-
-// private methods:
- /**
- * @method _tick
- * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
- * function.
- * @protected
- **/
- p._tick = function(evtObj) {
- this.advance(evtObj&&evtObj.delta);
- this.Container__tick(evtObj);
- };
-
- /**
- * @method _goto
- * @param {String|Number} positionOrLabel The animation name or frame number to go to.
- * @protected
- **/
- p._goto = function(positionOrLabel) {
- var pos = this.timeline.resolve(positionOrLabel);
- if (pos == null) { return; }
- // prevent _updateTimeline from overwriting the new position because of a reset:
- if (this._prevPos == -1) { this._prevPos = NaN; }
- this._prevPosition = pos;
- this._t = 0;
- this._updateTimeline();
- };
-
- /**
- * @method _reset
- * @private
- **/
- p._reset = function() {
- this._prevPos = -1;
- this._t = this.currentFrame = 0;
- this.paused = false;
- };
-
- /**
- * @method _updateTimeline
- * @protected
- **/
- p._updateTimeline = function() {
- var tl = this.timeline;
- var synched = this.mode != MovieClip.INDEPENDENT;
- tl.loop = (this.loop==null) ? true : this.loop;
-
- var pos = synched ? this.startPosition + (this.mode==MovieClip.SINGLE_FRAME?0:this._synchOffset) : (this._prevPos < 0 ? 0 : this._prevPosition);
- var mode = synched || !this.actionsEnabled ? createjs.Tween.NONE : null;
-
- // pre-assign currentFrame so it is available to frame scripts:
- this.currentFrame = tl._calcPosition(pos);
-
- // update timeline position, ignoring actions if this is a graphic.
- tl.setPosition(pos, mode);
-
- this._prevPosition = tl._prevPosition;
- if (this._prevPos == tl._prevPos) { return; }
- this.currentFrame = this._prevPos = tl._prevPos;
-
- for (var n in this._managed) { this._managed[n] = 1; }
-
- var tweens = tl._tweens;
- for (var i=0, l=tweens.length; i=0; i--) {
- var id = kids[i].id;
- if (this._managed[id] == 1) {
- this.removeChildAt(i);
- delete(this._managed[id]);
- }
- }
- };
-
- /**
- * @method _setState
- * @param {Array} state
- * @param {Number} offset
- * @protected
- **/
- p._setState = function(state, offset) {
- if (!state) { return; }
- for (var i=state.length-1;i>=0;i--) {
- var o = state[i];
- var target = o.t;
- var props = o.p;
- for (var n in props) { target[n] = props[n]; }
- this._addManagedChild(target, offset);
- }
- };
-
- /**
- * Adds a child to the timeline, and sets it up as a managed child.
- * @method _addManagedChild
- * @param {MovieClip} child The child MovieClip to manage
- * @param {Number} offset
- * @private
- **/
- p._addManagedChild = function(child, offset) {
- if (child._off) { return; }
- this.addChildAt(child,0);
-
- if (child instanceof MovieClip) {
- child._synchOffset = offset;
- // TODO: this does not precisely match Flash. Flash loses track of the clip if it is renamed or removed from the timeline, which causes it to reset.
- if (child.mode == MovieClip.INDEPENDENT && child.autoReset && !this._managed[child.id]) { child._reset(); }
- }
- this._managed[child.id] = 2;
- };
-
- /**
- * @method _getBounds
- * @param {Matrix2D} matrix
- * @param {Boolean} ignoreTransform
- * @return {Rectangle}
- * @protected
- **/
- p._getBounds = function(matrix, ignoreTransform) {
- var bounds = this.DisplayObject_getBounds();
- if (!bounds) {
- this._updateTimeline();
- if (this.frameBounds) { bounds = this._rectangle.copy(this.frameBounds[this.currentFrame]); }
- }
- if (bounds) { return this._transformBounds(bounds, matrix, ignoreTransform); }
- return this.Container__getBounds(matrix, ignoreTransform);
- };
-
-
- createjs.MovieClip = createjs.promote(MovieClip, "Container");
-
-
-
-// MovieClipPlugin for TweenJS:
- /**
- * This plugin works with TweenJS to prevent the startPosition
- * property from tweening.
- * @private
- * @class MovieClipPlugin
- * @constructor
- **/
- function MovieClipPlugin() {
- throw("MovieClipPlugin cannot be instantiated.")
- }
-
- /**
- * @method priority
- * @private
- **/
- MovieClipPlugin.priority = 100; // very high priority, should run first
-
- /**
- * @method install
- * @private
- **/
- MovieClipPlugin.install = function() {
- createjs.Tween.installPlugin(MovieClipPlugin, ["startPosition"]);
- };
-
- /**
- * @method init
- * @param {Tween} tween
- * @param {String} prop
- * @param {String|Number|Boolean} value
- * @private
- **/
- MovieClipPlugin.init = function(tween, prop, value) {
- return value;
- };
-
- /**
- * @method step
- * @private
- **/
- MovieClipPlugin.step = function() {
- // unused.
- };
-
- /**
- * @method tween
- * @param {Tween} tween
- * @param {String} prop
- * @param {String | Number | Boolean} value
- * @param {Array} startValues
- * @param {Array} endValues
- * @param {Number} ratio
- * @param {Object} wait
- * @param {Object} end
- * @return {*}
- */
- MovieClipPlugin.tween = function(tween, prop, value, startValues, endValues, ratio, wait, end) {
- if (!(tween.target instanceof MovieClip)) { return value; }
- return (ratio == 1 ? endValues[prop] : startValues[prop]);
- };
-
-}());
-
-//##############################################################################
-// SpriteSheetUtils.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * The SpriteSheetUtils class is a collection of static methods for working with {{#crossLink "SpriteSheet"}}{{/crossLink}}s.
- * A sprite sheet is a series of images (usually animation frames) combined into a single image on a regular grid. For
- * example, an animation consisting of 8 100x100 images could be combined into a 400x200 sprite sheet (4 frames across
- * by 2 high). The SpriteSheetUtils class uses a static interface and should not be instantiated.
- * @class SpriteSheetUtils
- * @static
- **/
- function SpriteSheetUtils() {
- throw "SpriteSheetUtils cannot be instantiated";
- }
-
-
-// private static properties:
- /**
- * @property _workingCanvas
- * @static
- * @type HTMLCanvasElement | Object
- * @protected
- */
- /**
- * @property _workingContext
- * @static
- * @type CanvasRenderingContext2D
- * @protected
- */
- var canvas = (createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"));
- if (canvas.getContext) {
- SpriteSheetUtils._workingCanvas = canvas;
- SpriteSheetUtils._workingContext = canvas.getContext("2d");
- canvas.width = canvas.height = 1;
- }
-
-
-// public static methods:
- /**
- * This is an experimental method, and may be buggy. Please report issues.
- * Extends the existing sprite sheet by flipping the original frames horizontally, vertically, or both,
- * and adding appropriate animation & frame data. The flipped animations will have a suffix added to their names
- * (_h, _v, _hv as appropriate). Make sure the sprite sheet images are fully loaded before using this method.
- *
- * For example:
- * SpriteSheetUtils.addFlippedFrames(mySpriteSheet, true, true);
- * The above would add frames that are flipped horizontally AND frames that are flipped vertically.
- *
- * Note that you can also flip any display object by setting its scaleX or scaleY to a negative value. On some
- * browsers (especially those without hardware accelerated canvas) this can result in slightly degraded performance,
- * which is why addFlippedFrames is available.
- * @method addFlippedFrames
- * @static
- * @param {SpriteSheet} spriteSheet
- * @param {Boolean} horizontal If true, horizontally flipped frames will be added.
- * @param {Boolean} vertical If true, vertically flipped frames will be added.
- * @param {Boolean} both If true, frames that are flipped both horizontally and vertically will be added.
- * @deprecated Modern browsers perform better when flipping via a transform (ex. scaleX=-1) rendering this obsolete.
- **/
- SpriteSheetUtils.addFlippedFrames = function(spriteSheet, horizontal, vertical, both) {
- if (!horizontal && !vertical && !both) { return; }
-
- var count = 0;
- if (horizontal) { SpriteSheetUtils._flip(spriteSheet,++count,true,false); }
- if (vertical) { SpriteSheetUtils._flip(spriteSheet,++count,false,true); }
- if (both) { SpriteSheetUtils._flip(spriteSheet,++count,true,true); }
- };
-
- /**
- * Returns a single frame of the specified sprite sheet as a new PNG image. An example of when this may be useful is
- * to use a spritesheet frame as the source for a bitmap fill.
- *
- * WARNING: In almost all cases it is better to display a single frame using a {{#crossLink "Sprite"}}{{/crossLink}}
- * with a {{#crossLink "Sprite/gotoAndStop"}}{{/crossLink}} call than it is to slice out a frame using this
- * method and display it with a Bitmap instance. You can also crop an image using the {{#crossLink "Bitmap/sourceRect"}}{{/crossLink}}
- * property of {{#crossLink "Bitmap"}}{{/crossLink}}.
- *
- * The extractFrame method may cause cross-domain warnings since it accesses pixels directly on the canvas.
- * @method extractFrame
- * @static
- * @param {SpriteSheet} spriteSheet The SpriteSheet instance to extract a frame from.
- * @param {Number|String} frameOrAnimation The frame number or animation name to extract. If an animation
- * name is specified, only the first frame of the animation will be extracted.
- * @return {HTMLImageElement} a single frame of the specified sprite sheet as a new PNG image.
- */
- SpriteSheetUtils.extractFrame = function(spriteSheet, frameOrAnimation) {
- if (isNaN(frameOrAnimation)) {
- frameOrAnimation = spriteSheet.getAnimation(frameOrAnimation).frames[0];
- }
- var data = spriteSheet.getFrame(frameOrAnimation);
- if (!data) { return null; }
- var r = data.rect;
- var canvas = SpriteSheetUtils._workingCanvas;
- canvas.width = r.width;
- canvas.height = r.height;
- SpriteSheetUtils._workingContext.drawImage(data.image, r.x, r.y, r.width, r.height, 0, 0, r.width, r.height);
- var img = document.createElement("img");
- img.src = canvas.toDataURL("image/png");
- return img;
- };
-
- /**
- * Merges the rgb channels of one image with the alpha channel of another. This can be used to combine a compressed
- * JPEG image containing color data with a PNG32 monochromatic image containing alpha data. With certain types of
- * images (those with detail that lend itself to JPEG compression) this can provide significant file size savings
- * versus a single RGBA PNG32. This method is very fast (generally on the order of 1-2 ms to run).
- * @method mergeAlpha
- * @static
- * @param {HTMLImageElement} rbgImage The image (or canvas) containing the RGB channels to use.
- * @param {HTMLImageElement} alphaImage The image (or canvas) containing the alpha channel to use.
- * @param {HTMLCanvasElement} canvas Optional. If specified, this canvas will be used and returned. If not, a new canvas will be created.
- * @return {HTMLCanvasElement} A canvas with the combined image data. This can be used as a source for Bitmap or SpriteSheet.
- * @deprecated Tools such as ImageAlpha generally provide better results. This will be moved to sandbox in the future.
- */
- SpriteSheetUtils.mergeAlpha = function(rgbImage, alphaImage, canvas) {
- if (!canvas) { canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas"); }
- canvas.width = Math.max(alphaImage.width, rgbImage.width);
- canvas.height = Math.max(alphaImage.height, rgbImage.height);
- var ctx = canvas.getContext("2d");
- ctx.save();
- ctx.drawImage(rgbImage,0,0);
- ctx.globalCompositeOperation = "destination-in";
- ctx.drawImage(alphaImage,0,0);
- ctx.restore();
- return canvas;
- };
-
-
-// private static methods:
- SpriteSheetUtils._flip = function(spriteSheet, count, h, v) {
- var imgs = spriteSheet._images;
- var canvas = SpriteSheetUtils._workingCanvas;
- var ctx = SpriteSheetUtils._workingContext;
- var il = imgs.length/count;
- for (var i=0;iREMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// constants:
- SpriteSheetBuilder.ERR_DIMENSIONS = "frame dimensions exceed max spritesheet dimensions";
- SpriteSheetBuilder.ERR_RUNNING = "a build is already running";
-
-// events:
- /**
- * Dispatched when a build completes.
- * @event complete
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.6.0
- */
-
- /**
- * Dispatched when an asynchronous build has progress.
- * @event progress
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {Number} progress The current progress value (0-1).
- * @since 0.6.0
- */
-
-
-// public methods:
- /**
- * Adds a frame to the {{#crossLink "SpriteSheet"}}{{/crossLink}}. Note that the frame will not be drawn until you
- * call {{#crossLink "SpriteSheetBuilder/build"}}{{/crossLink}} method. The optional setup params allow you to have
- * a function run immediately before the draw occurs. For example, this allows you to add a single source multiple
- * times, but manipulate it or its children to change it to generate different frames.
- *
- * Note that the source's transformations (x, y, scale, rotate, alpha) will be ignored, except for regX/Y. To apply
- * transforms to a source object and have them captured in the SpriteSheet, simply place it into a {{#crossLink "Container"}}{{/crossLink}}
- * and pass in the Container as the source.
- * @method addFrame
- * @param {DisplayObject} source The source {{#crossLink "DisplayObject"}}{{/crossLink}} to draw as the frame.
- * @param {Rectangle} [sourceRect] A {{#crossLink "Rectangle"}}{{/crossLink}} defining the portion of the
- * source to draw to the frame. If not specified, it will look for a `getBounds` method, bounds property, or
- * `nominalBounds` property on the source to use. If one is not found, the frame will be skipped.
- * @param {Number} [scale=1] Optional. The scale to draw this frame at. Default is 1.
- * @param {Function} [setupFunction] A function to call immediately before drawing this frame. It will be called with two parameters: the source, and setupData.
- * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter.
- * @return {Number} The index of the frame that was just added, or null if a sourceRect could not be determined.
- **/
- p.addFrame = function(source, sourceRect, scale, setupFunction, setupData) {
- if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; }
- var rect = sourceRect||source.bounds||source.nominalBounds;
- if (!rect&&source.getBounds) { rect = source.getBounds(); }
- if (!rect) { return null; }
- scale = scale||1;
- return this._frames.push({source:source, sourceRect:rect, scale:scale, funct:setupFunction, data:setupData, index:this._frames.length, height:rect.height*scale})-1;
- };
-
- /**
- * Adds an animation that will be included in the created {{#crossLink "SpriteSheet"}}{{/crossLink}}.
- * @method addAnimation
- * @param {String} name The name for the animation.
- * @param {Array} frames An array of frame indexes that comprise the animation. Ex. [3,6,5] would describe an animation
- * that played frame indexes 3, 6, and 5 in that order.
- * @param {String} [next] Specifies the name of the animation to continue to after this animation ends. You can
- * also pass false to have the animation stop when it ends. By default it will loop to the start of the same animation.
- * @param {Number} [speed] Specifies a frame advance speed for this animation. For example, a value of 0.5 would
- * cause the animation to advance every second tick. Note that earlier versions used `frequency` instead, which had
- * the opposite effect.
- **/
- p.addAnimation = function(name, frames, next, speed) {
- if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; }
- this._animations[name] = {frames:frames, next:next, speed:speed};
- };
-
- /**
- * This will take a {{#crossLink "MovieClip"}}{{/crossLink}} instance, and add its frames and labels to this
- * builder. Labels will be added as an animation running from the label index to the next label. For example, if
- * there is a label named "foo" at frame 0 and a label named "bar" at frame 10, in a MovieClip with 15 frames, it
- * will add an animation named "foo" that runs from frame index 0 to 9, and an animation named "bar" that runs from
- * frame index 10 to 14.
- *
- * Note that this will iterate through the full MovieClip with {{#crossLink "MovieClip/actionsEnabled:property"}}{{/crossLink}}
- * set to `false`, ending on the last frame.
- * @method addMovieClip
- * @param {MovieClip} source The source MovieClip instance to add to the SpriteSheet.
- * @param {Rectangle} [sourceRect] A {{#crossLink "Rectangle"}}{{/crossLink}} defining the portion of the source to
- * draw to the frame. If not specified, it will look for a {{#crossLink "DisplayObject/getBounds"}}{{/crossLink}}
- * method, `frameBounds` Array, `bounds` property, or `nominalBounds` property on the source to use. If one is not
- * found, the MovieClip will be skipped.
- * @param {Number} [scale=1] The scale to draw the movie clip at.
- * @param {Function} [setupFunction] A function to call immediately before drawing each frame. It will be called
- * with three parameters: the source, setupData, and the frame index.
- * @param {Object} [setupData] Arbitrary setup data to pass to setupFunction as the second parameter.
- * @param {Function} [labelFunction] This method will be called for each MovieClip label that is added with four
- * parameters: the label name, the source MovieClip instance, the starting frame index (in the movieclip timeline)
- * and the end index. It must return a new name for the label/animation, or `false` to exclude the label.
- **/
- p.addMovieClip = function(source, sourceRect, scale, setupFunction, setupData, labelFunction) {
- if (this._data) { throw SpriteSheetBuilder.ERR_RUNNING; }
- var rects = source.frameBounds;
- var rect = sourceRect||source.bounds||source.nominalBounds;
- if (!rect&&source.getBounds) { rect = source.getBounds(); }
- if (!rect && !rects) { return; }
-
- var i, l, baseFrameIndex = this._frames.length;
- var duration = source.timeline.duration;
- for (i=0; i this.maxHeight) { throw SpriteSheetBuilder.ERR_DIMENSIONS; }
- var y=0, x=0;
- var img = 0;
- while (frames.length) {
- var o = this._fillRow(frames, y, img, dataFrames, pad);
- if (o.w > x) { x = o.w; }
- y += o.h;
- if (!o.h || !frames.length) {
- var canvas = createjs.createCanvas?createjs.createCanvas():document.createElement("canvas");
- canvas.width = this._getSize(x,this.maxWidth);
- canvas.height = this._getSize(y,this.maxHeight);
- this._data.images[img] = canvas;
- if (!o.h) {
- x=y=0;
- img++;
- }
- }
- }
- };
-
- /**
- * @method _setupMovieClipFrame
- * @protected
- * @return {Number} The width & height of the row.
- **/
- p._setupMovieClipFrame = function(source, data) {
- var ae = source.actionsEnabled;
- source.actionsEnabled = false;
- source.gotoAndStop(data.i);
- source.actionsEnabled = ae;
- data.f&&data.f(source, data.d, data.i);
- };
-
- /**
- * @method _getSize
- * @protected
- * @return {Number} The width & height of the row.
- **/
- p._getSize = function(size,max) {
- var pow = 4;
- while (Math.pow(2,++pow) < size){}
- return Math.min(max,Math.pow(2,pow));
- };
-
- /**
- * @method _fillRow
- * @param {Array} frames
- * @param {Number} y
- * @param {HTMLImageElement} img
- * @param {Object} dataFrames
- * @param {Number} pad
- * @protected
- * @return {Number} The width & height of the row.
- **/
- p._fillRow = function(frames, y, img, dataFrames, pad) {
- var w = this.maxWidth;
- var maxH = this.maxHeight;
- y += pad;
- var h = maxH-y;
- var x = pad;
- var height = 0;
- for (var i=frames.length-1; i>=0; i--) {
- var frame = frames[i];
- var sc = this._scale*frame.scale;
- var rect = frame.sourceRect;
- var source = frame.source;
- var rx = Math.floor(sc*rect.x-pad);
- var ry = Math.floor(sc*rect.y-pad);
- var rh = Math.ceil(sc*rect.height+pad*2);
- var rw = Math.ceil(sc*rect.width+pad*2);
- if (rw > w) { throw SpriteSheetBuilder.ERR_DIMENSIONS; }
- if (rh > h || x+rw > w) { continue; }
- frame.img = img;
- frame.rect = new createjs.Rectangle(x,y,rw,rh);
- height = height || rh;
- frames.splice(i,1);
- dataFrames[frame.index] = [x,y,rw,rh,img,Math.round(-rx+sc*source.regX-pad),Math.round(-ry+sc*source.regY-pad)];
- x += rw;
- }
- return {w:x, h:height};
- };
-
- /**
- * @method _endBuild
- * @protected
- **/
- p._endBuild = function() {
- this.spriteSheet = new createjs.SpriteSheet(this._data);
- this._data = null;
- this.progress = 1;
- this.dispatchEvent("complete");
- };
-
- /**
- * @method _run
- * @protected
- **/
- p._run = function() {
- var ts = Math.max(0.01, Math.min(0.99, this.timeSlice||0.3))*50;
- var t = (new Date()).getTime()+ts;
- var complete = false;
- while (t > (new Date()).getTime()) {
- if (!this._drawNext()) { complete = true; break; }
- }
- if (complete) {
- this._endBuild();
- } else {
- var _this = this;
- this._timerID = setTimeout(function() { _this._run(); }, 50-ts);
- }
- var p = this.progress = this._index/this._frames.length;
- if (this.hasEventListener("progress")) {
- var evt = new createjs.Event("progress");
- evt.progress = p;
- this.dispatchEvent(evt);
- }
- };
-
- /**
- * @method _drawNext
- * @protected
- * @return Boolean Returns false if this is the last draw.
- **/
- p._drawNext = function() {
- var frame = this._frames[this._index];
- var sc = frame.scale*this._scale;
- var rect = frame.rect;
- var sourceRect = frame.sourceRect;
- var canvas = this._data.images[frame.img];
- var ctx = canvas.getContext("2d");
- frame.funct&&frame.funct(frame.source, frame.data);
- ctx.save();
- ctx.beginPath();
- ctx.rect(rect.x, rect.y, rect.width, rect.height);
- ctx.clip();
- ctx.translate(Math.ceil(rect.x-sourceRect.x*sc), Math.ceil(rect.y-sourceRect.y*sc));
- ctx.scale(sc,sc);
- frame.source.draw(ctx); // display object will draw itself.
- ctx.restore();
- return (++this._index) < this._frames.length;
- };
-
-
- createjs.SpriteSheetBuilder = createjs.promote(SpriteSheetBuilder, "EventDispatcher");
-}());
-
-//##############################################################################
-// DOMElement.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * This class is still experimental, and more advanced use is likely to be buggy. Please report bugs.
- *
- * A DOMElement allows you to associate a HTMLElement with the display list. It will be transformed
- * within the DOM as though it is child of the {{#crossLink "Container"}}{{/crossLink}} it is added to. However, it is
- * not rendered to canvas, and as such will retain whatever z-index it has relative to the canvas (ie. it will be
- * drawn in front of or behind the canvas).
- *
- * The position of a DOMElement is relative to their parent node in the DOM. It is recommended that
- * the DOM Object be added to a div that also contains the canvas so that they share the same position
- * on the page.
- *
- * DOMElement is useful for positioning HTML elements over top of canvas content, and for elements
- * that you want to display outside the bounds of the canvas. For example, a tooltip with rich HTML
- * content.
- *
- *
Mouse Interaction
- *
- * DOMElement instances are not full EaselJS display objects, and do not participate in EaselJS mouse
- * events or support methods like hitTest. To get mouse events from a DOMElement, you must instead add handlers to
- * the htmlElement (note, this does not support EventDispatcher)
- *
- * var domElement = new createjs.DOMElement(htmlElement);
- * domElement.htmlElement.onclick = function() {
- * console.log("clicked");
- * }
- *
- * @class DOMElement
- * @extends DisplayObject
- * @constructor
- * @param {HTMLElement} htmlElement A reference or id for the DOM element to manage.
- */
- function DOMElement(htmlElement) {
- this.DisplayObject_constructor();
-
- if (typeof(htmlElement)=="string") { htmlElement = document.getElementById(htmlElement); }
- this.mouseEnabled = false;
-
- var style = htmlElement.style;
- style.position = "absolute";
- style.transformOrigin = style.WebkitTransformOrigin = style.msTransformOrigin = style.MozTransformOrigin = style.OTransformOrigin = "0% 0%";
-
-
- // public properties:
- /**
- * The DOM object to manage.
- * @property htmlElement
- * @type HTMLElement
- */
- this.htmlElement = htmlElement;
-
-
- // private properties:
- /**
- * @property _oldMtx
- * @type Matrix2D
- * @protected
- */
- this._oldProps = null;
- }
- var p = createjs.extend(DOMElement, createjs.DisplayObject);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /**
- * Returns true or false indicating whether the display object would be visible if drawn to a canvas.
- * This does not account for whether it would be visible within the boundaries of the stage.
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method isVisible
- * @return {Boolean} Boolean indicating whether the display object would be visible if drawn to a canvas
- */
- p.isVisible = function() {
- return this.htmlElement != null;
- };
-
- /**
- * Draws the display object into the specified context ignoring its visible, alpha, shadow, and transform.
- * Returns true if the draw was handled (useful for overriding functionality).
- * NOTE: This method is mainly for internal use, though it may be useful for advanced uses.
- * @method draw
- * @param {CanvasRenderingContext2D} ctx The canvas 2D context object to draw into.
- * @param {Boolean} ignoreCache Indicates whether the draw operation should ignore any current cache.
- * For example, used for drawing the cache (to prevent it from simply drawing an existing cache back
- * into itself).
- * @return {Boolean}
- */
- p.draw = function(ctx, ignoreCache) {
- // this relies on the _tick method because draw isn't called if the parent is not visible.
- // the actual update happens in _handleDrawEnd
- return true;
- };
-
- /**
- * Not applicable to DOMElement.
- * @method cache
- */
- p.cache = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method uncache
- */
- p.uncache = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method updateCache
- */
- p.updateCache = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method hitTest
- */
- p.hitTest = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method localToGlobal
- */
- p.localToGlobal = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method globalToLocal
- */
- p.globalToLocal = function() {};
-
- /**
- * Not applicable to DOMElement.
- * @method localToLocal
- */
- p.localToLocal = function() {};
-
- /**
- * DOMElement cannot be cloned. Throws an error.
- * @method clone
- */
- p.clone = function() {
- throw("DOMElement cannot be cloned.")
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- */
- p.toString = function() {
- return "[DOMElement (name="+ this.name +")]";
- };
-
- /**
- * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances
- * are not full EaselJS display objects and do not participate in EaselJS mouse events.
- * @event click
- */
-
- /**
- * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances
- * are not full EaselJS display objects and do not participate in EaselJS mouse events.
- * @event dblClick
- */
-
- /**
- * Interaction events should be added to `htmlElement`, and not the DOMElement instance, since DOMElement instances
- * are not full EaselJS display objects and do not participate in EaselJS mouse events.
- * @event mousedown
- */
-
- /**
- * The HTMLElement can listen for the mouseover event, not the DOMElement instance.
- * Since DOMElement instances are not full EaselJS display objects and do not participate in EaselJS mouse events.
- * @event mouseover
- */
-
- /**
- * Not applicable to DOMElement.
- * @event tick
- */
-
-
-// private methods:
- /**
- * @method _tick
- * @param {Object} evtObj An event object that will be dispatched to all tick listeners. This object is reused between dispatchers to reduce construction & GC costs.
- * function.
- * @protected
- */
- p._tick = function(evtObj) {
- var stage = this.getStage();
- stage&&stage.on("drawend", this._handleDrawEnd, this, true);
- this.DisplayObject__tick(evtObj);
- };
-
- /**
- * @method _handleDrawEnd
- * @param {Event} evt
- * @protected
- */
- p._handleDrawEnd = function(evt) {
- var o = this.htmlElement;
- if (!o) { return; }
- var style = o.style;
-
- var props = this.getConcatenatedDisplayProps(this._props), mtx = props.matrix;
-
- var visibility = props.visible ? "visible" : "hidden";
- if (visibility != style.visibility) { style.visibility = visibility; }
- if (!props.visible) { return; }
-
- var oldProps = this._oldProps, oldMtx = oldProps&&oldProps.matrix;
- var n = 10000; // precision
-
- if (!oldMtx || !oldMtx.equals(mtx)) {
- var str = "matrix(" + (mtx.a*n|0)/n +","+ (mtx.b*n|0)/n +","+ (mtx.c*n|0)/n +","+ (mtx.d*n|0)/n +","+ (mtx.tx+0.5|0);
- style.transform = style.WebkitTransform = style.OTransform = style.msTransform = str +","+ (mtx.ty+0.5|0) +")";
- style.MozTransform = str +"px,"+ (mtx.ty+0.5|0) +"px)";
- if (!oldProps) { oldProps = this._oldProps = new createjs.DisplayProps(true, NaN); }
- oldProps.matrix.copy(mtx);
- }
-
- if (oldProps.alpha != props.alpha) {
- style.opacity = ""+(props.alpha*n|0)/n;
- oldProps.alpha = props.alpha;
- }
- };
-
-
- createjs.DOMElement = createjs.promote(DOMElement, "DisplayObject");
-}());
-
-//##############################################################################
-// Filter.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Base class that all filters should inherit from. Filters need to be applied to objects that have been cached using
- * the {{#crossLink "DisplayObject/cache"}}{{/crossLink}} method. If an object changes, please cache it again, or use
- * {{#crossLink "DisplayObject/updateCache"}}{{/crossLink}}. Note that the filters must be applied before caching.
- *
- *
Example
- *
- * myInstance.filters = [
- * new createjs.ColorFilter(0, 0, 0, 1, 255, 0, 0),
- * new createjs.BlurFilter(5, 5, 10)
- * ];
- * myInstance.cache(0,0, 100, 100);
- *
- * Note that each filter can implement a {{#crossLink "Filter/getBounds"}}{{/crossLink}} method, which returns the
- * margins that need to be applied in order to fully display the filter. For example, the {{#crossLink "BlurFilter"}}{{/crossLink}}
- * will cause an object to feather outwards, resulting in a margin around the shape.
- *
- *
EaselJS Filters
- * EaselJS comes with a number of pre-built filters:
- *
{{#crossLink "AlphaMapFilter"}}{{/crossLink}} : Map a greyscale image to the alpha channel of a display object
- *
{{#crossLink "AlphaMaskFilter"}}{{/crossLink}}: Map an image's alpha channel to the alpha channel of a display object
- *
{{#crossLink "BlurFilter"}}{{/crossLink}}: Apply vertical and horizontal blur to a display object
- *
{{#crossLink "ColorFilter"}}{{/crossLink}}: Color transform a display object
- *
{{#crossLink "ColorMatrixFilter"}}{{/crossLink}}: Transform an image using a {{#crossLink "ColorMatrix"}}{{/crossLink}}
- *
- *
- * @class Filter
- * @constructor
- **/
- function Filter() {}
- var p = Filter.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// public methods:
- /**
- * Provides padding values for this filter. That is, how much the filter will extend the visual bounds of an object it is applied to.
- * @method getBounds
- * @param {Rectangle} [rect] If specified, the provided Rectangle instance will be expanded by the padding amounts and returned.
- * @return {Rectangle} If a `rect` param was provided, it is returned. If not, either a new rectangle with the padding values, or null if no padding is required for this filter.
- **/
- p.getBounds = function(rect) {
- return rect;
- };
-
- /**
- * Applies the filter to the specified context.
- * @method applyFilter
- * @param {CanvasRenderingContext2D} ctx The 2D context to use as the source.
- * @param {Number} x The x position to use for the source rect.
- * @param {Number} y The y position to use for the source rect.
- * @param {Number} width The width to use for the source rect.
- * @param {Number} height The height to use for the source rect.
- * @param {CanvasRenderingContext2D} [targetCtx] The 2D context to draw the result to. Defaults to the context passed to ctx.
- * @param {Number} [targetX] The x position to draw the result to. Defaults to the value passed to x.
- * @param {Number} [targetY] The y position to draw the result to. Defaults to the value passed to y.
- * @return {Boolean} If the filter was applied successfully.
- **/
- p.applyFilter = function(ctx, x, y, width, height, targetCtx, targetX, targetY) {
- // this is the default behaviour because most filters access pixel data. It is overridden when not needed.
- targetCtx = targetCtx || ctx;
- if (targetX == null) { targetX = x; }
- if (targetY == null) { targetY = y; }
- try {
- var imageData = ctx.getImageData(x, y, width, height);
- } catch (e) {
- return false;
- }
- if (this._applyFilter(imageData)) {
- targetCtx.putImageData(imageData, targetX, targetY);
- return true;
- }
- return false;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Filter]";
- };
-
- /**
- * Returns a clone of this Filter instance.
- * @method clone
- * @return {Filter} A clone of the current Filter instance.
- **/
- p.clone = function() {
- return new Filter();
- };
-
-// private methods:
- /**
- * @method _applyFilter
- * @param {ImageData} imageData Target ImageData instance.
- * @return {Boolean}
- **/
- p._applyFilter = function(imageData) { return true; };
-
-
- createjs.Filter = Filter;
-}());
-
-//##############################################################################
-// BlurFilter.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Applies a box blur to DisplayObjects. Note that this filter is fairly CPU intensive, particularly if the quality is
- * set higher than 1.
- *
- *
Example
- * This example creates a red circle, and then applies a 5 pixel blur to it. It uses the {{#crossLink "Filter/getBounds"}}{{/crossLink}}
- * method to account for the spread that the blur causes.
- *
- * var shape = new createjs.Shape().set({x:100,y:100});
- * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);
- *
- * var blurFilter = new createjs.BlurFilter(5, 5, 1);
- * shape.filters = [blurFilter];
- * var bounds = blurFilter.getBounds();
- *
- * shape.cache(-50+bounds.x, -50+bounds.y, 100+bounds.width, 100+bounds.height);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters.
- * @class BlurFilter
- * @extends Filter
- * @constructor
- * @param {Number} [blurX=0] The horizontal blur radius in pixels.
- * @param {Number} [blurY=0] The vertical blur radius in pixels.
- * @param {Number} [quality=1] The number of blur iterations.
- **/
- function BlurFilter( blurX, blurY, quality) {
- if ( isNaN(blurX) || blurX < 0 ) blurX = 0;
- if ( isNaN(blurY) || blurY < 0 ) blurY = 0;
- if ( isNaN(quality) || quality < 1 ) quality = 1;
-
-
- // public properties:
- /**
- * Horizontal blur radius in pixels
- * @property blurX
- * @default 0
- * @type Number
- **/
- this.blurX = blurX | 0;
-
- /**
- * Vertical blur radius in pixels
- * @property blurY
- * @default 0
- * @type Number
- **/
- this.blurY = blurY | 0;
-
- /**
- * Number of blur iterations. For example, a value of 1 will produce a rough blur. A value of 2 will produce a
- * smoother blur, but take twice as long to run.
- * @property quality
- * @default 1
- * @type Number
- **/
- this.quality = quality | 0;
- }
- var p = createjs.extend(BlurFilter, createjs.Filter);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// constants:
- /**
- * Array of multiply values for blur calculations.
- * @property MUL_TABLE
- * @type Array
- * @protected
- * @static
- **/
- BlurFilter.MUL_TABLE = [1, 171, 205, 293, 57, 373, 79, 137, 241, 27, 391, 357, 41, 19, 283, 265, 497, 469, 443, 421, 25, 191, 365, 349, 335, 161, 155, 149, 9, 278, 269, 261, 505, 245, 475, 231, 449, 437, 213, 415, 405, 395, 193, 377, 369, 361, 353, 345, 169, 331, 325, 319, 313, 307, 301, 37, 145, 285, 281, 69, 271, 267, 263, 259, 509, 501, 493, 243, 479, 118, 465, 459, 113, 446, 55, 435, 429, 423, 209, 413, 51, 403, 199, 393, 97, 3, 379, 375, 371, 367, 363, 359, 355, 351, 347, 43, 85, 337, 333, 165, 327, 323, 5, 317, 157, 311, 77, 305, 303, 75, 297, 294, 73, 289, 287, 71, 141, 279, 277, 275, 68, 135, 67, 133, 33, 262, 260, 129, 511, 507, 503, 499, 495, 491, 61, 121, 481, 477, 237, 235, 467, 232, 115, 457, 227, 451, 7, 445, 221, 439, 218, 433, 215, 427, 425, 211, 419, 417, 207, 411, 409, 203, 202, 401, 399, 396, 197, 49, 389, 387, 385, 383, 95, 189, 47, 187, 93, 185, 23, 183, 91, 181, 45, 179, 89, 177, 11, 175, 87, 173, 345, 343, 341, 339, 337, 21, 167, 83, 331, 329, 327, 163, 81, 323, 321, 319, 159, 79, 315, 313, 39, 155, 309, 307, 153, 305, 303, 151, 75, 299, 149, 37, 295, 147, 73, 291, 145, 289, 287, 143, 285, 71, 141, 281, 35, 279, 139, 69, 275, 137, 273, 17, 271, 135, 269, 267, 133, 265, 33, 263, 131, 261, 130, 259, 129, 257, 1];
-
- /**
- * Array of shift values for blur calculations.
- * @property SHG_TABLE
- * @type Array
- * @protected
- * @static
- **/
- BlurFilter.SHG_TABLE = [0, 9, 10, 11, 9, 12, 10, 11, 12, 9, 13, 13, 10, 9, 13, 13, 14, 14, 14, 14, 10, 13, 14, 14, 14, 13, 13, 13, 9, 14, 14, 14, 15, 14, 15, 14, 15, 15, 14, 15, 15, 15, 14, 15, 15, 15, 15, 15, 14, 15, 15, 15, 15, 15, 15, 12, 14, 15, 15, 13, 15, 15, 15, 15, 16, 16, 16, 15, 16, 14, 16, 16, 14, 16, 13, 16, 16, 16, 15, 16, 13, 16, 15, 16, 14, 9, 16, 16, 16, 16, 16, 16, 16, 16, 16, 13, 14, 16, 16, 15, 16, 16, 10, 16, 15, 16, 14, 16, 16, 14, 16, 16, 14, 16, 16, 14, 15, 16, 16, 16, 14, 15, 14, 15, 13, 16, 16, 15, 17, 17, 17, 17, 17, 17, 14, 15, 17, 17, 16, 16, 17, 16, 15, 17, 16, 17, 11, 17, 16, 17, 16, 17, 16, 17, 17, 16, 17, 17, 16, 17, 17, 16, 16, 17, 17, 17, 16, 14, 17, 17, 17, 17, 15, 16, 14, 16, 15, 16, 13, 16, 15, 16, 14, 16, 15, 16, 12, 16, 15, 16, 17, 17, 17, 17, 17, 13, 16, 15, 17, 17, 17, 16, 15, 17, 17, 17, 16, 15, 17, 17, 14, 16, 17, 17, 16, 17, 17, 16, 15, 17, 16, 14, 17, 16, 15, 17, 16, 17, 17, 16, 17, 15, 16, 17, 14, 17, 16, 15, 17, 16, 17, 13, 17, 16, 17, 17, 16, 17, 14, 17, 16, 17, 16, 17, 16, 17, 9];
-
-// public methods:
- /** docced in super class **/
- p.getBounds = function (rect) {
- var x = this.blurX|0, y = this.blurY| 0;
- if (x <= 0 && y <= 0) { return rect; }
- var q = Math.pow(this.quality, 0.2);
- return (rect || new createjs.Rectangle()).pad(x*q+1,y*q+1,x*q+1,y*q+1);
- };
-
- /** docced in super class **/
- p.clone = function() {
- return new BlurFilter(this.blurX, this.blurY, this.quality);
- };
-
- /** docced in super class **/
- p.toString = function() {
- return "[BlurFilter]";
- };
-
-
-// private methods:
-
- /** docced in super class **/
- p._applyFilter = function (imageData) {
-
- var radiusX = this.blurX >> 1;
- if (isNaN(radiusX) || radiusX < 0) return false;
- var radiusY = this.blurY >> 1;
- if (isNaN(radiusY) || radiusY < 0) return false;
- if (radiusX == 0 && radiusY == 0) return false;
-
- var iterations = this.quality;
- if (isNaN(iterations) || iterations < 1) iterations = 1;
- iterations |= 0;
- if (iterations > 3) iterations = 3;
- if (iterations < 1) iterations = 1;
-
- var px = imageData.data;
- var x=0, y=0, i=0, p=0, yp=0, yi=0, yw=0, r=0, g=0, b=0, a=0, pr=0, pg=0, pb=0, pa=0;
-
- var divx = (radiusX + radiusX + 1) | 0;
- var divy = (radiusY + radiusY + 1) | 0;
- var w = imageData.width | 0;
- var h = imageData.height | 0;
-
- var w1 = (w - 1) | 0;
- var h1 = (h - 1) | 0;
- var rxp1 = (radiusX + 1) | 0;
- var ryp1 = (radiusY + 1) | 0;
-
- var ssx = {r:0,b:0,g:0,a:0};
- var sx = ssx;
- for ( i = 1; i < divx; i++ )
- {
- sx = sx.n = {r:0,b:0,g:0,a:0};
- }
- sx.n = ssx;
-
- var ssy = {r:0,b:0,g:0,a:0};
- var sy = ssy;
- for ( i = 1; i < divy; i++ )
- {
- sy = sy.n = {r:0,b:0,g:0,a:0};
- }
- sy.n = ssy;
-
- var si = null;
-
-
- var mtx = BlurFilter.MUL_TABLE[radiusX] | 0;
- var stx = BlurFilter.SHG_TABLE[radiusX] | 0;
- var mty = BlurFilter.MUL_TABLE[radiusY] | 0;
- var sty = BlurFilter.SHG_TABLE[radiusY] | 0;
-
- while (iterations-- > 0) {
-
- yw = yi = 0;
- var ms = mtx;
- var ss = stx;
- for (y = h; --y > -1;) {
- r = rxp1 * (pr = px[(yi) | 0]);
- g = rxp1 * (pg = px[(yi + 1) | 0]);
- b = rxp1 * (pb = px[(yi + 2) | 0]);
- a = rxp1 * (pa = px[(yi + 3) | 0]);
-
- sx = ssx;
-
- for( i = rxp1; --i > -1; )
- {
- sx.r = pr;
- sx.g = pg;
- sx.b = pb;
- sx.a = pa;
- sx = sx.n;
- }
-
- for( i = 1; i < rxp1; i++ )
- {
- p = (yi + ((w1 < i ? w1 : i) << 2)) | 0;
- r += ( sx.r = px[p]);
- g += ( sx.g = px[p+1]);
- b += ( sx.b = px[p+2]);
- a += ( sx.a = px[p+3]);
-
- sx = sx.n;
- }
-
- si = ssx;
- for ( x = 0; x < w; x++ )
- {
- px[yi++] = (r * ms) >>> ss;
- px[yi++] = (g * ms) >>> ss;
- px[yi++] = (b * ms) >>> ss;
- px[yi++] = (a * ms) >>> ss;
-
- p = ((yw + ((p = x + radiusX + 1) < w1 ? p : w1)) << 2);
-
- r -= si.r - ( si.r = px[p]);
- g -= si.g - ( si.g = px[p+1]);
- b -= si.b - ( si.b = px[p+2]);
- a -= si.a - ( si.a = px[p+3]);
-
- si = si.n;
-
- }
- yw += w;
- }
-
- ms = mty;
- ss = sty;
- for (x = 0; x < w; x++) {
- yi = (x << 2) | 0;
-
- r = (ryp1 * (pr = px[yi])) | 0;
- g = (ryp1 * (pg = px[(yi + 1) | 0])) | 0;
- b = (ryp1 * (pb = px[(yi + 2) | 0])) | 0;
- a = (ryp1 * (pa = px[(yi + 3) | 0])) | 0;
-
- sy = ssy;
- for( i = 0; i < ryp1; i++ )
- {
- sy.r = pr;
- sy.g = pg;
- sy.b = pb;
- sy.a = pa;
- sy = sy.n;
- }
-
- yp = w;
-
- for( i = 1; i <= radiusY; i++ )
- {
- yi = ( yp + x ) << 2;
-
- r += ( sy.r = px[yi]);
- g += ( sy.g = px[yi+1]);
- b += ( sy.b = px[yi+2]);
- a += ( sy.a = px[yi+3]);
-
- sy = sy.n;
-
- if( i < h1 )
- {
- yp += w;
- }
- }
-
- yi = x;
- si = ssy;
- if ( iterations > 0 )
- {
- for ( y = 0; y < h; y++ )
- {
- p = yi << 2;
- px[p+3] = pa =(a * ms) >>> ss;
- if ( pa > 0 )
- {
- px[p] = ((r * ms) >>> ss );
- px[p+1] = ((g * ms) >>> ss );
- px[p+2] = ((b * ms) >>> ss );
- } else {
- px[p] = px[p+1] = px[p+2] = 0
- }
-
- p = ( x + (( ( p = y + ryp1) < h1 ? p : h1 ) * w )) << 2;
-
- r -= si.r - ( si.r = px[p]);
- g -= si.g - ( si.g = px[p+1]);
- b -= si.b - ( si.b = px[p+2]);
- a -= si.a - ( si.a = px[p+3]);
-
- si = si.n;
-
- yi += w;
- }
- } else {
- for ( y = 0; y < h; y++ )
- {
- p = yi << 2;
- px[p+3] = pa =(a * ms) >>> ss;
- if ( pa > 0 )
- {
- pa = 255 / pa;
- px[p] = ((r * ms) >>> ss ) * pa;
- px[p+1] = ((g * ms) >>> ss ) * pa;
- px[p+2] = ((b * ms) >>> ss ) * pa;
- } else {
- px[p] = px[p+1] = px[p+2] = 0
- }
-
- p = ( x + (( ( p = y + ryp1) < h1 ? p : h1 ) * w )) << 2;
-
- r -= si.r - ( si.r = px[p]);
- g -= si.g - ( si.g = px[p+1]);
- b -= si.b - ( si.b = px[p+2]);
- a -= si.a - ( si.a = px[p+3]);
-
- si = si.n;
-
- yi += w;
- }
- }
- }
-
- }
- return true;
- };
-
- createjs.BlurFilter = createjs.promote(BlurFilter, "Filter");
-}());
-
-//##############################################################################
-// AlphaMapFilter.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-
-// constructor:
- /**
- * Applies a greyscale alpha map image (or canvas) to the target, such that the alpha channel of the result will
- * be copied from the red channel of the map, and the RGB channels will be copied from the target.
- *
- * Generally, it is recommended that you use {{#crossLink "AlphaMaskFilter"}}{{/crossLink}}, because it has much
- * better performance.
- *
- *
Example
- * This example draws a red->blue box, caches it, and then uses the cache canvas as an alpha map on a 100x100 image.
- *
- * var box = new createjs.Shape();
- * box.graphics.beginLinearGradientFill(["#ff0000", "#0000ff"], [0, 1], 0, 0, 0, 100)
- * box.graphics.drawRect(0, 0, 100, 100);
- * box.cache(0, 0, 100, 100);
- *
- * var bmp = new createjs.Bitmap("path/to/image.jpg");
- * bmp.filters = [
- * new createjs.AlphaMapFilter(box.cacheCanvas)
- * ];
- * bmp.cache(0, 0, 100, 100);
- * stage.addChild(bmp);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for more information on applying filters.
- * @class AlphaMapFilter
- * @extends Filter
- * @constructor
- * @param {HTMLImageElement|HTMLCanvasElement} alphaMap The greyscale image (or canvas) to use as the alpha value for the
- * result. This should be exactly the same dimensions as the target.
- **/
- function AlphaMapFilter(alphaMap) {
-
-
- // public properties:
- /**
- * The greyscale image (or canvas) to use as the alpha value for the result. This should be exactly the same
- * dimensions as the target.
- * @property alphaMap
- * @type HTMLImageElement|HTMLCanvasElement
- **/
- this.alphaMap = alphaMap;
-
-
- // private properties:
- /**
- * @property _alphaMap
- * @protected
- * @type HTMLImageElement|HTMLCanvasElement
- **/
- this._alphaMap = null;
-
- /**
- * @property _mapData
- * @protected
- * @type Uint8ClampedArray
- **/
- this._mapData = null;
- }
- var p = createjs.extend(AlphaMapFilter, createjs.Filter);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /** docced in super class **/
- p.clone = function () {
- var o = new AlphaMapFilter(this.alphaMap);
- o._alphaMap = this._alphaMap;
- o._mapData = this._mapData;
- return o;
- };
-
- /** docced in super class **/
- p.toString = function () {
- return "[AlphaMapFilter]";
- };
-
-
-// private methods:
- /** docced in super class **/
- p._applyFilter = function (imageData) {
- if (!this.alphaMap) { return true; }
- if (!this._prepAlphaMap()) { return false; }
-
- // TODO: update to support scenarios where the target has different dimensions.
- var data = imageData.data;
- var map = this._mapData;
- for(var i=0, l=data.length; iIMPORTANT NOTE: This filter currently does not support the targetCtx, or targetX/Y parameters correctly.
- *
- *
Example
- * This example draws a gradient box, then caches it and uses the "cacheCanvas" as the alpha mask on a 100x100 image.
- *
- * var box = new createjs.Shape();
- * box.graphics.beginLinearGradientFill(["#000000", "rgba(0, 0, 0, 0)"], [0, 1], 0, 0, 100, 100)
- * box.graphics.drawRect(0, 0, 100, 100);
- * box.cache(0, 0, 100, 100);
- *
- * var bmp = new createjs.Bitmap("path/to/image.jpg");
- * bmp.filters = [
- * new createjs.AlphaMaskFilter(box.cacheCanvas)
- * ];
- * bmp.cache(0, 0, 100, 100);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for more information on applying filters.
- * @class AlphaMaskFilter
- * @extends Filter
- * @constructor
- * @param {HTMLImageElement|HTMLCanvasElement} mask
- **/
- function AlphaMaskFilter(mask) {
-
-
- // public properties:
- /**
- * The image (or canvas) to use as the mask.
- * @property mask
- * @type HTMLImageElement|HTMLCanvasElement
- **/
- this.mask = mask;
- }
- var p = createjs.extend(AlphaMaskFilter, createjs.Filter);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /**
- * Applies the filter to the specified context.
- *
- * IMPORTANT NOTE: This filter currently does not support the targetCtx, or targetX/Y parameters
- * correctly.
- * @method applyFilter
- * @param {CanvasRenderingContext2D} ctx The 2D context to use as the source.
- * @param {Number} x The x position to use for the source rect.
- * @param {Number} y The y position to use for the source rect.
- * @param {Number} width The width to use for the source rect.
- * @param {Number} height The height to use for the source rect.
- * @param {CanvasRenderingContext2D} [targetCtx] NOT SUPPORTED IN THIS FILTER. The 2D context to draw the result to. Defaults to the context passed to ctx.
- * @param {Number} [targetX] NOT SUPPORTED IN THIS FILTER. The x position to draw the result to. Defaults to the value passed to x.
- * @param {Number} [targetY] NOT SUPPORTED IN THIS FILTER. The y position to draw the result to. Defaults to the value passed to y.
- * @return {Boolean} If the filter was applied successfully.
- **/
- p.applyFilter = function (ctx, x, y, width, height, targetCtx, targetX, targetY) {
- if (!this.mask) { return true; }
- targetCtx = targetCtx || ctx;
- if (targetX == null) { targetX = x; }
- if (targetY == null) { targetY = y; }
-
- targetCtx.save();
- if (ctx != targetCtx) {
- // TODO: support targetCtx and targetX/Y
- // clearRect, then draw the ctx in?
- return false;
- }
-
- targetCtx.globalCompositeOperation = "destination-in";
- targetCtx.drawImage(this.mask, targetX, targetY);
- targetCtx.restore();
- return true;
- };
-
- /** docced in super class **/
- p.clone = function () {
- return new AlphaMaskFilter(this.mask);
- };
-
- /** docced in super class **/
- p.toString = function () {
- return "[AlphaMaskFilter]";
- };
-
-
- createjs.AlphaMaskFilter = createjs.promote(AlphaMaskFilter, "Filter");
-}());
-
-//##############################################################################
-// ColorFilter.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Applies a color transform to DisplayObjects.
- *
- *
Example
- * This example draws a red circle, and then transforms it to Blue. This is accomplished by multiplying all the channels
- * to 0 (except alpha, which is set to 1), and then adding 255 to the blue channel.
- *
- * var shape = new createjs.Shape().set({x:100,y:100});
- * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);
- *
- * shape.filters = [
- * new createjs.ColorFilter(0,0,0,1, 0,0,255,0)
- * ];
- * shape.cache(-50, -50, 100, 100);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters.
- * @class ColorFilter
- * @param {Number} [redMultiplier=1] The amount to multiply against the red channel. This is a range between 0 and 1.
- * @param {Number} [greenMultiplier=1] The amount to multiply against the green channel. This is a range between 0 and 1.
- * @param {Number} [blueMultiplier=1] The amount to multiply against the blue channel. This is a range between 0 and 1.
- * @param {Number} [alphaMultiplier=1] The amount to multiply against the alpha channel. This is a range between 0 and 1.
- * @param {Number} [redOffset=0] The amount to add to the red channel after it has been multiplied. This is a range
- * between -255 and 255.
- * @param {Number} [greenOffset=0] The amount to add to the green channel after it has been multiplied. This is a range
- * between -255 and 255.
- * @param {Number} [blueOffset=0] The amount to add to the blue channel after it has been multiplied. This is a range
- * between -255 and 255.
- * @param {Number} [alphaOffset=0] The amount to add to the alpha channel after it has been multiplied. This is a range
- * between -255 and 255.
- * @constructor
- * @extends Filter
- **/
- function ColorFilter(redMultiplier, greenMultiplier, blueMultiplier, alphaMultiplier, redOffset, greenOffset, blueOffset, alphaOffset) {
-
-
- // public properties:
- /**
- * Red channel multiplier.
- * @property redMultiplier
- * @type Number
- **/
- this.redMultiplier = redMultiplier != null ? redMultiplier : 1;
-
- /**
- * Green channel multiplier.
- * @property greenMultiplier
- * @type Number
- **/
- this.greenMultiplier = greenMultiplier != null ? greenMultiplier : 1;
-
- /**
- * Blue channel multiplier.
- * @property blueMultiplier
- * @type Number
- **/
- this.blueMultiplier = blueMultiplier != null ? blueMultiplier : 1;
-
- /**
- * Alpha channel multiplier.
- * @property alphaMultiplier
- * @type Number
- **/
- this.alphaMultiplier = alphaMultiplier != null ? alphaMultiplier : 1;
-
- /**
- * Red channel offset (added to value).
- * @property redOffset
- * @type Number
- **/
- this.redOffset = redOffset || 0;
-
- /**
- * Green channel offset (added to value).
- * @property greenOffset
- * @type Number
- **/
- this.greenOffset = greenOffset || 0;
-
- /**
- * Blue channel offset (added to value).
- * @property blueOffset
- * @type Number
- **/
- this.blueOffset = blueOffset || 0;
-
- /**
- * Alpha channel offset (added to value).
- * @property alphaOffset
- * @type Number
- **/
- this.alphaOffset = alphaOffset || 0;
- }
- var p = createjs.extend(ColorFilter, createjs.Filter);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /** docced in super class **/
- p.toString = function() {
- return "[ColorFilter]";
- };
-
- /** docced in super class **/
- p.clone = function() {
- return new ColorFilter(this.redMultiplier, this.greenMultiplier, this.blueMultiplier, this.alphaMultiplier, this.redOffset, this.greenOffset, this.blueOffset, this.alphaOffset);
- };
-
-
-// private methods:
- /** docced in super class **/
- p._applyFilter = function(imageData) {
- var data = imageData.data;
- var l = data.length;
- for (var i=0; iExample
- *
- * myColorMatrix.adjustHue(20).adjustBrightness(50);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for an example of how to apply filters, or {{#crossLink "ColorMatrixFilter"}}{{/crossLink}}
- * for an example of how to use ColorMatrix to change a DisplayObject's color.
- * @class ColorMatrix
- * @param {Number} brightness
- * @param {Number} contrast
- * @param {Number} saturation
- * @param {Number} hue
- * @constructor
- **/
- function ColorMatrix(brightness, contrast, saturation, hue) {
- this.setColor(brightness, contrast, saturation, hue);
- }
- var p = ColorMatrix.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// constants:
- /**
- * Array of delta values for contrast calculations.
- * @property DELTA_INDEX
- * @type Array
- * @protected
- * @static
- **/
- ColorMatrix.DELTA_INDEX = [
- 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
- 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
- 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
- 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
- 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
- 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
- 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
- 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
- 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
- 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
- 10.0
- ];
-
- /**
- * Identity matrix values.
- * @property IDENTITY_MATRIX
- * @type Array
- * @protected
- * @static
- **/
- ColorMatrix.IDENTITY_MATRIX = [
- 1,0,0,0,0,
- 0,1,0,0,0,
- 0,0,1,0,0,
- 0,0,0,1,0,
- 0,0,0,0,1
- ];
-
- /**
- * The constant length of a color matrix.
- * @property LENGTH
- * @type Number
- * @protected
- * @static
- **/
- ColorMatrix.LENGTH = ColorMatrix.IDENTITY_MATRIX.length;
-
-
-// public methods:
- /**
- * Resets the instance with the specified values.
- * @method setColor
- * @param {Number} brightness
- * @param {Number} contrast
- * @param {Number} saturation
- * @param {Number} hue
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.setColor = function(brightness,contrast,saturation,hue) {
- return this.reset().adjustColor(brightness,contrast,saturation,hue);
- };
-
- /**
- * Resets the matrix to identity values.
- * @method reset
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.reset = function() {
- return this.copy(ColorMatrix.IDENTITY_MATRIX);
- };
-
- /**
- * Shortcut method to adjust brightness, contrast, saturation and hue.
- * Equivalent to calling adjustHue(hue), adjustContrast(contrast),
- * adjustBrightness(brightness), adjustSaturation(saturation), in that order.
- * @method adjustColor
- * @param {Number} brightness
- * @param {Number} contrast
- * @param {Number} saturation
- * @param {Number} hue
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.adjustColor = function(brightness,contrast,saturation,hue) {
- this.adjustHue(hue);
- this.adjustContrast(contrast);
- this.adjustBrightness(brightness);
- return this.adjustSaturation(saturation);
- };
-
- /**
- * Adjusts the brightness of pixel color by adding the specified value to the red, green and blue channels.
- * Positive values will make the image brighter, negative values will make it darker.
- * @method adjustBrightness
- * @param {Number} value A value between -255 & 255 that will be added to the RGB channels.
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.adjustBrightness = function(value) {
- if (value == 0 || isNaN(value)) { return this; }
- value = this._cleanValue(value,255);
- this._multiplyMatrix([
- 1,0,0,0,value,
- 0,1,0,0,value,
- 0,0,1,0,value,
- 0,0,0,1,0,
- 0,0,0,0,1
- ]);
- return this;
- };
-
- /**
- * Adjusts the contrast of pixel color.
- * Positive values will increase contrast, negative values will decrease contrast.
- * @method adjustContrast
- * @param {Number} value A value between -100 & 100.
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.adjustContrast = function(value) {
- if (value == 0 || isNaN(value)) { return this; }
- value = this._cleanValue(value,100);
- var x;
- if (value<0) {
- x = 127+value/100*127;
- } else {
- x = value%1;
- if (x == 0) {
- x = ColorMatrix.DELTA_INDEX[value];
- } else {
- x = ColorMatrix.DELTA_INDEX[(value<<0)]*(1-x)+ColorMatrix.DELTA_INDEX[(value<<0)+1]*x; // use linear interpolation for more granularity.
- }
- x = x*127+127;
- }
- this._multiplyMatrix([
- x/127,0,0,0,0.5*(127-x),
- 0,x/127,0,0,0.5*(127-x),
- 0,0,x/127,0,0.5*(127-x),
- 0,0,0,1,0,
- 0,0,0,0,1
- ]);
- return this;
- };
-
- /**
- * Adjusts the color saturation of the pixel.
- * Positive values will increase saturation, negative values will decrease saturation (trend towards greyscale).
- * @method adjustSaturation
- * @param {Number} value A value between -100 & 100.
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.adjustSaturation = function(value) {
- if (value == 0 || isNaN(value)) { return this; }
- value = this._cleanValue(value,100);
- var x = 1+((value > 0) ? 3*value/100 : value/100);
- var lumR = 0.3086;
- var lumG = 0.6094;
- var lumB = 0.0820;
- this._multiplyMatrix([
- lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0,
- lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0,
- lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0,
- 0,0,0,1,0,
- 0,0,0,0,1
- ]);
- return this;
- };
-
-
- /**
- * Adjusts the hue of the pixel color.
- * @method adjustHue
- * @param {Number} value A value between -180 & 180.
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.adjustHue = function(value) {
- if (value == 0 || isNaN(value)) { return this; }
- value = this._cleanValue(value,180)/180*Math.PI;
- var cosVal = Math.cos(value);
- var sinVal = Math.sin(value);
- var lumR = 0.213;
- var lumG = 0.715;
- var lumB = 0.072;
- this._multiplyMatrix([
- lumR+cosVal*(1-lumR)+sinVal*(-lumR),lumG+cosVal*(-lumG)+sinVal*(-lumG),lumB+cosVal*(-lumB)+sinVal*(1-lumB),0,0,
- lumR+cosVal*(-lumR)+sinVal*(0.143),lumG+cosVal*(1-lumG)+sinVal*(0.140),lumB+cosVal*(-lumB)+sinVal*(-0.283),0,0,
- lumR+cosVal*(-lumR)+sinVal*(-(1-lumR)),lumG+cosVal*(-lumG)+sinVal*(lumG),lumB+cosVal*(1-lumB)+sinVal*(lumB),0,0,
- 0,0,0,1,0,
- 0,0,0,0,1
- ]);
- return this;
- };
-
- /**
- * Concatenates (multiplies) the specified matrix with this one.
- * @method concat
- * @param {Array} matrix An array or ColorMatrix instance.
- * @return {ColorMatrix} The ColorMatrix instance the method is called on (useful for chaining calls.)
- * @chainable
- **/
- p.concat = function(matrix) {
- matrix = this._fixMatrix(matrix);
- if (matrix.length != ColorMatrix.LENGTH) { return this; }
- this._multiplyMatrix(matrix);
- return this;
- };
-
- /**
- * Returns a clone of this ColorMatrix.
- * @method clone
- * @return {ColorMatrix} A clone of this ColorMatrix.
- **/
- p.clone = function() {
- return (new ColorMatrix()).copy(this);
- };
-
- /**
- * Return a length 25 (5x5) array instance containing this matrix's values.
- * @method toArray
- * @return {Array} An array holding this matrix's values.
- **/
- p.toArray = function() {
- var arr = [];
- for (var i= 0, l=ColorMatrix.LENGTH; i ColorMatrix.LENGTH) {
- matrix = matrix.slice(0,ColorMatrix.LENGTH);
- }
- return matrix;
- };
-
-
- createjs.ColorMatrix = ColorMatrix;
-}());
-
-//##############################################################################
-// ColorMatrixFilter.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * Allows you to carry out complex color operations such as modifying saturation, brightness, or inverting. See the
- * {{#crossLink "ColorMatrix"}}{{/crossLink}} for more information on changing colors. For an easier color transform,
- * consider the {{#crossLink "ColorFilter"}}{{/crossLink}}.
- *
- *
Example
- * This example creates a red circle, inverts its hue, and then saturates it to brighten it up.
- *
- * var shape = new createjs.Shape().set({x:100,y:100});
- * shape.graphics.beginFill("#ff0000").drawCircle(0,0,50);
- *
- * var matrix = new createjs.ColorMatrix().adjustHue(180).adjustSaturation(100);
- * shape.filters = [
- * new createjs.ColorMatrixFilter(matrix)
- * ];
- *
- * shape.cache(-50, -50, 100, 100);
- *
- * See {{#crossLink "Filter"}}{{/crossLink}} for an more information on applying filters.
- * @class ColorMatrixFilter
- * @constructor
- * @extends Filter
- * @param {Array | ColorMatrix} matrix A 4x5 matrix describing the color operation to perform. See also the {{#crossLink "ColorMatrix"}}{{/crossLink}}
- * class.
- **/
- function ColorMatrixFilter(matrix) {
-
-
- // public properties:
- /**
- * A 4x5 matrix describing the color operation to perform. See also the {{#crossLink "ColorMatrix"}}{{/crossLink}}
- * @property matrix
- * @type Array | ColorMatrix
- **/
- this.matrix = matrix;
- }
- var p = createjs.extend(ColorMatrixFilter, createjs.Filter);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// public methods:
- /** docced in super class **/
- p.toString = function() {
- return "[ColorMatrixFilter]";
- };
-
- /** docced in super class **/
- p.clone = function() {
- return new ColorMatrixFilter(this.matrix);
- };
-
-// private methods:
- /** docced in super class **/
- p._applyFilter = function(imageData) {
- var data = imageData.data;
- var l = data.length;
- var r,g,b,a;
- var mtx = this.matrix;
- var m0 = mtx[0], m1 = mtx[1], m2 = mtx[2], m3 = mtx[3], m4 = mtx[4];
- var m5 = mtx[5], m6 = mtx[6], m7 = mtx[7], m8 = mtx[8], m9 = mtx[9];
- var m10 = mtx[10], m11 = mtx[11], m12 = mtx[12], m13 = mtx[13], m14 = mtx[14];
- var m15 = mtx[15], m16 = mtx[16], m17 = mtx[17], m18 = mtx[18], m19 = mtx[19];
-
- for (var i=0; iExample
- *
- * var stage = new createjs.Stage("canvasId");
- * createjs.Touch.enable(stage);
- *
- * Note: It is important to disable Touch on a stage that you are no longer using:
- *
- * createjs.Touch.disable(stage);
- *
- * @class Touch
- * @static
- **/
- function Touch() {
- throw "Touch cannot be instantiated";
- }
-
-
-// public static methods:
- /**
- * Returns `true` if touch is supported in the current browser.
- * @method isSupported
- * @return {Boolean} Indicates whether touch is supported in the current browser.
- * @static
- **/
- Touch.isSupported = function() {
- return !!(('ontouchstart' in window) // iOS & Android
- || (window.navigator['msPointerEnabled'] && window.navigator['msMaxTouchPoints'] > 0) // IE10
- || (window.navigator['pointerEnabled'] && window.navigator['maxTouchPoints'] > 0)); // IE11+
- };
-
- /**
- * Enables touch interaction for the specified EaselJS {{#crossLink "Stage"}}{{/crossLink}}. Currently supports iOS
- * (and compatible browsers, such as modern Android browsers), and IE10/11. Supports both single touch and
- * multi-touch modes. Extends the EaselJS {{#crossLink "MouseEvent"}}{{/crossLink}} model, but without support for
- * double click or over/out events. See the MouseEvent {{#crossLink "MouseEvent/pointerId:property"}}{{/crossLink}}
- * for more information.
- * @method enable
- * @param {Stage} stage The {{#crossLink "Stage"}}{{/crossLink}} to enable touch on.
- * @param {Boolean} [singleTouch=false] If `true`, only a single touch will be active at a time.
- * @param {Boolean} [allowDefault=false] If `true`, then default gesture actions (ex. scrolling, zooming) will be
- * allowed when the user is interacting with the target canvas.
- * @return {Boolean} Returns `true` if touch was successfully enabled on the target stage.
- * @static
- **/
- Touch.enable = function(stage, singleTouch, allowDefault) {
- if (!stage || !stage.canvas || !Touch.isSupported()) { return false; }
- if (stage.__touch) { return true; }
-
- // inject required properties on stage:
- stage.__touch = {pointers:{}, multitouch:!singleTouch, preventDefault:!allowDefault, count:0};
-
- // note that in the future we may need to disable the standard mouse event model before adding
- // these to prevent duplicate calls. It doesn't seem to be an issue with iOS devices though.
- if ('ontouchstart' in window) { Touch._IOS_enable(stage); }
- else if (window.navigator['msPointerEnabled'] || window.navigator["pointerEnabled"]) { Touch._IE_enable(stage); }
- return true;
- };
-
- /**
- * Removes all listeners that were set up when calling `Touch.enable()` on a stage.
- * @method disable
- * @param {Stage} stage The {{#crossLink "Stage"}}{{/crossLink}} to disable touch on.
- * @static
- **/
- Touch.disable = function(stage) {
- if (!stage) { return; }
- if ('ontouchstart' in window) { Touch._IOS_disable(stage); }
- else if (window.navigator['msPointerEnabled'] || window.navigator["pointerEnabled"]) { Touch._IE_disable(stage); }
-
- delete stage.__touch;
- };
-
-
-// Private static methods:
- /**
- * @method _IOS_enable
- * @protected
- * @param {Stage} stage
- * @static
- **/
- Touch._IOS_enable = function(stage) {
- var canvas = stage.canvas;
- var f = stage.__touch.f = function(e) { Touch._IOS_handleEvent(stage,e); };
- canvas.addEventListener("touchstart", f, false);
- canvas.addEventListener("touchmove", f, false);
- canvas.addEventListener("touchend", f, false);
- canvas.addEventListener("touchcancel", f, false);
- };
-
- /**
- * @method _IOS_disable
- * @protected
- * @param {Stage} stage
- * @static
- **/
- Touch._IOS_disable = function(stage) {
- var canvas = stage.canvas;
- if (!canvas) { return; }
- var f = stage.__touch.f;
- canvas.removeEventListener("touchstart", f, false);
- canvas.removeEventListener("touchmove", f, false);
- canvas.removeEventListener("touchend", f, false);
- canvas.removeEventListener("touchcancel", f, false);
- };
-
- /**
- * @method _IOS_handleEvent
- * @param {Stage} stage
- * @param {Object} e The event to handle
- * @protected
- * @static
- **/
- Touch._IOS_handleEvent = function(stage, e) {
- if (!stage) { return; }
- if (stage.__touch.preventDefault) { e.preventDefault&&e.preventDefault(); }
- var touches = e.changedTouches;
- var type = e.type;
- for (var i= 0,l=touches.length; iExample
- *
- * myObject.addEventListener("change", createjs.proxy(myMethod, scope));
- *
- * @class Utility Methods
- * @main Utility Methods
- */
-
-(function() {
- "use strict";
-
- /**
- * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a
- * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the
- * method gets called in the correct scope.
- *
- * Additional arguments can be passed that will be applied to the function when it is called.
- *
- *
Example
- *
- * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2));
- *
- * function myHandler(arg1, arg2) {
- * // This gets called when myObject.myCallback is executed.
- * }
- *
- * @method proxy
- * @param {Function} method The function to call
- * @param {Object} scope The scope to call the method name on
- * @param {mixed} [arg] * Arguments that are appended to the callback for additional params.
- * @public
- * @static
- */
- createjs.proxy = function (method, scope) {
- var aArgs = Array.prototype.slice.call(arguments, 2);
- return function () {
- return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs));
- };
- }
-
-}());
-
-//##############################################################################
-// indexOf.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of
- * that value. Returns -1 if value is not found.
- *
- * var i = createjs.indexOf(myArray, myElementToFind);
- *
- * @method indexOf
- * @param {Array} array Array to search for searchElement
- * @param searchElement Element to find in array.
- * @return {Number} The first index of searchElement in array.
- */
-createjs.indexOf = function (array, searchElement){
- "use strict";
-
- for (var i = 0,l=array.length; i < l; i++) {
- if (searchElement === array[i]) {
- return i;
- }
- }
- return -1;
-};
-
-//##############################################################################
-// Event.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-// constructor:
- /**
- * Contains properties and methods shared by all events for use with
- * {{#crossLink "EventDispatcher"}}{{/crossLink}}.
- *
- * Note that Event objects are often reused, so you should never
- * rely on an event object's state outside of the call stack it was received in.
- * @class Event
- * @param {String} type The event type.
- * @param {Boolean} bubbles Indicates whether the event will bubble through the display list.
- * @param {Boolean} cancelable Indicates whether the default behaviour of this event can be cancelled.
- * @constructor
- **/
- function Event(type, bubbles, cancelable) {
-
-
- // public properties:
- /**
- * The type of event.
- * @property type
- * @type String
- **/
- this.type = type;
-
- /**
- * The object that generated an event.
- * @property target
- * @type Object
- * @default null
- * @readonly
- */
- this.target = null;
-
- /**
- * The current target that a bubbling event is being dispatched from. For non-bubbling events, this will
- * always be the same as target. For example, if childObj.parent = parentObj, and a bubbling event
- * is generated from childObj, then a listener on parentObj would receive the event with
- * target=childObj (the original target) and currentTarget=parentObj (where the listener was added).
- * @property currentTarget
- * @type Object
- * @default null
- * @readonly
- */
- this.currentTarget = null;
-
- /**
- * For bubbling events, this indicates the current event phase:
- *
capture phase: starting from the top parent to the target
- *
at target phase: currently being dispatched from the target
- *
bubbling phase: from the target to the top parent
- *
- * @property eventPhase
- * @type Number
- * @default 0
- * @readonly
- */
- this.eventPhase = 0;
-
- /**
- * Indicates whether the event will bubble through the display list.
- * @property bubbles
- * @type Boolean
- * @default false
- * @readonly
- */
- this.bubbles = !!bubbles;
-
- /**
- * Indicates whether the default behaviour of this event can be cancelled via
- * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor.
- * @property cancelable
- * @type Boolean
- * @default false
- * @readonly
- */
- this.cancelable = !!cancelable;
-
- /**
- * The epoch time at which this event was created.
- * @property timeStamp
- * @type Number
- * @default 0
- * @readonly
- */
- this.timeStamp = (new Date()).getTime();
-
- /**
- * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
- * on this event.
- * @property defaultPrevented
- * @type Boolean
- * @default false
- * @readonly
- */
- this.defaultPrevented = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or
- * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event.
- * @property propagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.propagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
- * on this event.
- * @property immediatePropagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.immediatePropagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
- * @property removed
- * @type Boolean
- * @default false
- * @readonly
- */
- this.removed = false;
- }
- var p = Event.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-// public methods:
- /**
- * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable.
- * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will
- * cancel the default behaviour associated with the event.
- * @method preventDefault
- **/
- p.preventDefault = function() {
- this.defaultPrevented = this.cancelable&&true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopPropagation
- **/
- p.stopPropagation = function() {
- this.propagationStopped = true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and
- * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopImmediatePropagation
- **/
- p.stopImmediatePropagation = function() {
- this.immediatePropagationStopped = this.propagationStopped = true;
- };
-
- /**
- * Causes the active listener to be removed via removeEventListener();
- *
- * myBtn.addEventListener("click", function(evt) {
- * // do stuff...
- * evt.remove(); // removes this listener.
- * });
- *
- * @method remove
- **/
- p.remove = function() {
- this.removed = true;
- };
-
- /**
- * Returns a clone of the Event instance.
- * @method clone
- * @return {Event} a clone of the Event instance.
- **/
- p.clone = function() {
- return new Event(this.type, this.bubbles, this.cancelable);
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the instance.
- * @return {Event} Returns the instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Event (type="+this.type+")]";
- };
-
- createjs.Event = Event;
-}());
-
-//##############################################################################
-// ErrorEvent.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
- /**
- * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details.
- * @class ErrorEvent
- * @param {String} [title] The error title
- * @param {String} [message] The error description
- * @param {Object} [data] Additional error data
- * @constructor
- */
- function ErrorEvent(title, message, data) {
- this.Event_constructor("error");
-
- /**
- * The short error title, which indicates the type of error that occurred.
- * @property title
- * @type String
- */
- this.title = title;
-
- /**
- * The verbose error message, containing details about the error.
- * @property message
- * @type String
- */
- this.message = message;
-
- /**
- * Additional data attached to an error.
- * @property data
- * @type {Object}
- */
- this.data = data;
- }
-
- var p = createjs.extend(ErrorEvent, createjs.Event);
-
- p.clone = function() {
- return new createjs.ErrorEvent(this.title, this.message, this.data);
- };
-
- createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event");
-
-}());
-
-//##############################################################################
-// EventDispatcher.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * EventDispatcher provides methods for managing queues of event listeners and dispatching events.
- *
- * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the
- * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method.
- *
- * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the
- * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports
- * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent.
- *
- * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier
- * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The
- * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to
- * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}.
- *
- * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}}
- * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also
- * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener.
- *
- *
Example
- * Add EventDispatcher capabilities to the "MyClass" class.
- *
- * EventDispatcher.initialize(MyClass.prototype);
- *
- * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}).
- *
- * instance.addEventListener("eventName", handlerMethod);
- * function handlerMethod(event) {
- * console.log(event.target + " Was Clicked");
- * }
- *
- * Maintaining proper scope
- * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}}
- * method to subscribe to events simplifies this.
- *
- * instance.addEventListener("click", function(event) {
- * console.log(instance == this); // false, scope is ambiguous.
- * });
- *
- * instance.on("click", function(event) {
- * console.log(instance == this); // true, "on" uses dispatcher scope by default.
- * });
- *
- * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage
- * scope.
- *
- * Browser support
- * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model
- * requires modern browsers (IE9+).
- *
- *
- * @class EventDispatcher
- * @constructor
- **/
- function EventDispatcher() {
-
-
- // private properties:
- /**
- * @protected
- * @property _listeners
- * @type Object
- **/
- this._listeners = null;
-
- /**
- * @protected
- * @property _captureListeners
- * @type Object
- **/
- this._captureListeners = null;
- }
- var p = EventDispatcher.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// static public methods:
- /**
- * Static initializer to mix EventDispatcher methods into a target object or prototype.
- *
- * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class
- * EventDispatcher.initialize(myObject); // add to a specific instance
- *
- * @method initialize
- * @static
- * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a
- * prototype.
- **/
- EventDispatcher.initialize = function(target) {
- target.addEventListener = p.addEventListener;
- target.on = p.on;
- target.removeEventListener = target.off = p.removeEventListener;
- target.removeAllEventListeners = p.removeAllEventListeners;
- target.hasEventListener = p.hasEventListener;
- target.dispatchEvent = p.dispatchEvent;
- target._dispatchEvent = p._dispatchEvent;
- target.willTrigger = p.willTrigger;
- };
-
-
-// public methods:
- /**
- * Adds the specified event listener. Note that adding multiple listeners to the same function will result in
- * multiple callbacks getting fired.
- *
- *
Example
- *
- * displayObject.addEventListener("click", handleClick);
- * function handleClick(event) {
- * // Click happened.
- * }
- *
- * @method addEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function | Object} Returns the listener for chaining or assignment.
- **/
- p.addEventListener = function(type, listener, useCapture) {
- var listeners;
- if (useCapture) {
- listeners = this._captureListeners = this._captureListeners||{};
- } else {
- listeners = this._listeners = this._listeners||{};
- }
- var arr = listeners[type];
- if (arr) { this.removeEventListener(type, listener, useCapture); }
- arr = listeners[type]; // remove may have deleted the array
- if (!arr) { listeners[type] = [listener]; }
- else { arr.push(listener); }
- return listener;
- };
-
- /**
- * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener
- * only run once, associate arbitrary data with the listener, and remove the listener.
- *
- * This method works by creating an anonymous wrapper function and subscribing it with addEventListener.
- * The wrapper function is returned for use with `removeEventListener` (or `off`).
- *
- * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use
- * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls
- * to `on` with the same params will create multiple listeners.
- *
- *
Example
- *
- * var listener = myBtn.on("click", handleClick, null, false, {count:3});
- * function handleClick(evt, data) {
- * data.count -= 1;
- * console.log(this == myBtn); // true - scope defaults to the dispatcher
- * if (data.count == 0) {
- * alert("clicked 3 times!");
- * myBtn.off("click", listener);
- * // alternately: evt.remove();
- * }
- * }
- *
- * @method on
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent).
- * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered.
- * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called.
- * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener.
- **/
- p.on = function(type, listener, scope, once, data, useCapture) {
- if (listener.handleEvent) {
- scope = scope||listener;
- listener = listener.handleEvent;
- }
- scope = scope||this;
- return this.addEventListener(type, function(evt) {
- listener.call(scope, evt, data);
- once&&evt.remove();
- }, useCapture);
- };
-
- /**
- * Removes the specified event listener.
- *
- * Important Note: that you must pass the exact function reference used when the event was added. If a proxy
- * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or
- * closure will not work.
- *
- *
Example
- *
- * displayObject.removeEventListener("click", handleClick);
- *
- * @method removeEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.removeEventListener = function(type, listener, useCapture) {
- var listeners = useCapture ? this._captureListeners : this._listeners;
- if (!listeners) { return; }
- var arr = listeners[type];
- if (!arr) { return; }
- for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See
- * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example.
- *
- * @method off
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.off = p.removeEventListener;
-
- /**
- * Removes all listeners for the specified type, or all listeners of all types.
- *
- *
Example
- *
- * // Remove all listeners
- * displayObject.removeAllEventListeners();
- *
- * // Remove all click listeners
- * displayObject.removeAllEventListeners("click");
- *
- * @method removeAllEventListeners
- * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed.
- **/
- p.removeAllEventListeners = function(type) {
- if (!type) { this._listeners = this._captureListeners = null; }
- else {
- if (this._listeners) { delete(this._listeners[type]); }
- if (this._captureListeners) { delete(this._captureListeners[type]); }
- }
- };
-
- /**
- * Dispatches the specified event to all listeners.
- *
- *
Example
- *
- * // Use a string event
- * this.dispatchEvent("complete");
- *
- * // Use an Event instance
- * var event = new createjs.Event("progress");
- * this.dispatchEvent(event);
- *
- * @method dispatchEvent
- * @param {Object | String | Event} eventObj An object with a "type" property, or a string type.
- * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used,
- * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can
- * be used to avoid event object instantiation for non-bubbling events that may not have any listeners.
- * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj.
- * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj.
- * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise.
- **/
- p.dispatchEvent = function(eventObj, bubbles, cancelable) {
- if (typeof eventObj == "string") {
- // skip everything if there's no listeners and it doesn't bubble:
- var listeners = this._listeners;
- if (!bubbles && (!listeners || !listeners[eventObj])) { return true; }
- eventObj = new createjs.Event(eventObj, bubbles, cancelable);
- } else if (eventObj.target && eventObj.clone) {
- // redispatching an active event object, so clone it:
- eventObj = eventObj.clone();
- }
-
- // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent
- try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events
-
- if (!eventObj.bubbles || !this.parent) {
- this._dispatchEvent(eventObj, 2);
- } else {
- var top=this, list=[top];
- while (top.parent) { list.push(top = top.parent); }
- var i, l=list.length;
-
- // capture & atTarget
- for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) {
- list[i]._dispatchEvent(eventObj, 1+(i==0));
- }
- // bubbling
- for (i=1; i= 10.53.
- isExtended = isExtended.getUTCFullYear() == -109252 && isExtended.getUTCMonth() === 0 && isExtended.getUTCDate() === 1 &&
- // Safari < 2.0.2 stores the internal millisecond time value correctly,
- // but clips the values returned by the date methods to the range of
- // signed 32-bit integers ([-2 ** 31, 2 ** 31 - 1]).
- isExtended.getUTCHours() == 10 && isExtended.getUTCMinutes() == 37 && isExtended.getUTCSeconds() == 6 && isExtended.getUTCMilliseconds() == 708;
- } catch (exception) {}
-
- // Internal: Determines whether the native `JSON.stringify` and `parse`
- // implementations are spec-compliant. Based on work by Ken Snyder.
- function has(name) {
- if (has[name] !== undef) {
- // Return cached feature test result.
- return has[name];
- }
- var isSupported;
- if (name == "bug-string-char-index") {
- // IE <= 7 doesn't support accessing string characters using square
- // bracket notation. IE 8 only supports this for primitives.
- isSupported = "a"[0] != "a";
- } else if (name == "json") {
- // Indicates whether both `JSON.stringify` and `JSON.parse` are
- // supported.
- isSupported = has("json-stringify") && has("json-parse");
- } else {
- var value, serialized = '{"a":[1,true,false,null,"\\u0000\\b\\n\\f\\r\\t"]}';
- // Test `JSON.stringify`.
- if (name == "json-stringify") {
- var stringify = exports.stringify, stringifySupported = typeof stringify == "function" && isExtended;
- if (stringifySupported) {
- // A test function object with a custom `toJSON` method.
- (value = function () {
- return 1;
- }).toJSON = value;
- try {
- stringifySupported =
- // Firefox 3.1b1 and b2 serialize string, number, and boolean
- // primitives as object literals.
- stringify(0) === "0" &&
- // FF 3.1b1, b2, and JSON 2 serialize wrapped primitives as object
- // literals.
- stringify(new Number()) === "0" &&
- stringify(new String()) == '""' &&
- // FF 3.1b1, 2 throw an error if the value is `null`, `undefined`, or
- // does not define a canonical JSON representation (this applies to
- // objects with `toJSON` properties as well, *unless* they are nested
- // within an object or array).
- stringify(getClass) === undef &&
- // IE 8 serializes `undefined` as `"undefined"`. Safari <= 5.1.7 and
- // FF 3.1b3 pass this test.
- stringify(undef) === undef &&
- // Safari <= 5.1.7 and FF 3.1b3 throw `Error`s and `TypeError`s,
- // respectively, if the value is omitted entirely.
- stringify() === undef &&
- // FF 3.1b1, 2 throw an error if the given value is not a number,
- // string, array, object, Boolean, or `null` literal. This applies to
- // objects with custom `toJSON` methods as well, unless they are nested
- // inside object or array literals. YUI 3.0.0b1 ignores custom `toJSON`
- // methods entirely.
- stringify(value) === "1" &&
- stringify([value]) == "[1]" &&
- // Prototype <= 1.6.1 serializes `[undefined]` as `"[]"` instead of
- // `"[null]"`.
- stringify([undef]) == "[null]" &&
- // YUI 3.0.0b1 fails to serialize `null` literals.
- stringify(null) == "null" &&
- // FF 3.1b1, 2 halts serialization if an array contains a function:
- // `[1, true, getClass, 1]` serializes as "[1,true,],". FF 3.1b3
- // elides non-JSON values from objects and arrays, unless they
- // define custom `toJSON` methods.
- stringify([undef, getClass, null]) == "[null,null,null]" &&
- // Simple serialization test. FF 3.1b1 uses Unicode escape sequences
- // where character escape codes are expected (e.g., `\b` => `\u0008`).
- stringify({ "a": [value, true, false, null, "\x00\b\n\f\r\t"] }) == serialized &&
- // FF 3.1b1 and b2 ignore the `filter` and `width` arguments.
- stringify(null, value) === "1" &&
- stringify([1, 2], null, 1) == "[\n 1,\n 2\n]" &&
- // JSON 2, Prototype <= 1.7, and older WebKit builds incorrectly
- // serialize extended years.
- stringify(new Date(-8.64e15)) == '"-271821-04-20T00:00:00.000Z"' &&
- // The milliseconds are optional in ES 5, but required in 5.1.
- stringify(new Date(8.64e15)) == '"+275760-09-13T00:00:00.000Z"' &&
- // Firefox <= 11.0 incorrectly serializes years prior to 0 as negative
- // four-digit years instead of six-digit years. Credits: @Yaffle.
- stringify(new Date(-621987552e5)) == '"-000001-01-01T00:00:00.000Z"' &&
- // Safari <= 5.1.5 and Opera >= 10.53 incorrectly serialize millisecond
- // values less than 1000. Credits: @Yaffle.
- stringify(new Date(-1)) == '"1969-12-31T23:59:59.999Z"';
- } catch (exception) {
- stringifySupported = false;
- }
- }
- isSupported = stringifySupported;
- }
- // Test `JSON.parse`.
- if (name == "json-parse") {
- var parse = exports.parse;
- if (typeof parse == "function") {
- try {
- // FF 3.1b1, b2 will throw an exception if a bare literal is provided.
- // Conforming implementations should also coerce the initial argument to
- // a string prior to parsing.
- if (parse("0") === 0 && !parse(false)) {
- // Simple parsing test.
- value = parse(serialized);
- var parseSupported = value["a"].length == 5 && value["a"][0] === 1;
- if (parseSupported) {
- try {
- // Safari <= 5.1.2 and FF 3.1b1 allow unescaped tabs in strings.
- parseSupported = !parse('"\t"');
- } catch (exception) {}
- if (parseSupported) {
- try {
- // FF 4.0 and 4.0.1 allow leading `+` signs and leading
- // decimal points. FF 4.0, 4.0.1, and IE 9-10 also allow
- // certain octal literals.
- parseSupported = parse("01") !== 1;
- } catch (exception) {}
- }
- if (parseSupported) {
- try {
- // FF 4.0, 4.0.1, and Rhino 1.7R3-R4 allow trailing decimal
- // points. These environments, along with FF 3.1b1 and 2,
- // also allow trailing commas in JSON objects and arrays.
- parseSupported = parse("1.") !== 1;
- } catch (exception) {}
- }
- }
- }
- } catch (exception) {
- parseSupported = false;
- }
- }
- isSupported = parseSupported;
- }
- }
- return has[name] = !!isSupported;
- }
-
- if (!has("json")) {
- // Common `[[Class]]` name aliases.
- var functionClass = "[object Function]",
- dateClass = "[object Date]",
- numberClass = "[object Number]",
- stringClass = "[object String]",
- arrayClass = "[object Array]",
- booleanClass = "[object Boolean]";
-
- // Detect incomplete support for accessing string characters by index.
- var charIndexBuggy = has("bug-string-char-index");
-
- // Define additional utility methods if the `Date` methods are buggy.
- if (!isExtended) {
- var floor = Math.floor;
- // A mapping between the months of the year and the number of days between
- // January 1st and the first of the respective month.
- var Months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334];
- // Internal: Calculates the number of days between the Unix epoch and the
- // first day of the given month.
- var getDay = function (year, month) {
- return Months[month] + 365 * (year - 1970) + floor((year - 1969 + (month = +(month > 1))) / 4) - floor((year - 1901 + month) / 100) + floor((year - 1601 + month) / 400);
- };
- }
-
- // Internal: Determines if a property is a direct property of the given
- // object. Delegates to the native `Object#hasOwnProperty` method.
- if (!(isProperty = objectProto.hasOwnProperty)) {
- isProperty = function (property) {
- var members = {}, constructor;
- if ((members.__proto__ = null, members.__proto__ = {
- // The *proto* property cannot be set multiple times in recent
- // versions of Firefox and SeaMonkey.
- "toString": 1
- }, members).toString != getClass) {
- // Safari <= 2.0.3 doesn't implement `Object#hasOwnProperty`, but
- // supports the mutable *proto* property.
- isProperty = function (property) {
- // Capture and break the object's prototype chain (see section 8.6.2
- // of the ES 5.1 spec). The parenthesized expression prevents an
- // unsafe transformation by the Closure Compiler.
- var original = this.__proto__, result = property in (this.__proto__ = null, this);
- // Restore the original prototype chain.
- this.__proto__ = original;
- return result;
- };
- } else {
- // Capture a reference to the top-level `Object` constructor.
- constructor = members.constructor;
- // Use the `constructor` property to simulate `Object#hasOwnProperty` in
- // other environments.
- isProperty = function (property) {
- var parent = (this.constructor || constructor).prototype;
- return property in this && !(property in parent && this[property] === parent[property]);
- };
- }
- members = null;
- return isProperty.call(this, property);
- };
- }
-
- // Internal: Normalizes the `for...in` iteration algorithm across
- // environments. Each enumerated key is yielded to a `callback` function.
- forEach = function (object, callback) {
- var size = 0, Properties, members, property;
-
- // Tests for bugs in the current environment's `for...in` algorithm. The
- // `valueOf` property inherits the non-enumerable flag from
- // `Object.prototype` in older versions of IE, Netscape, and Mozilla.
- (Properties = function () {
- this.valueOf = 0;
- }).prototype.valueOf = 0;
-
- // Iterate over a new instance of the `Properties` class.
- members = new Properties();
- for (property in members) {
- // Ignore all properties inherited from `Object.prototype`.
- if (isProperty.call(members, property)) {
- size++;
- }
- }
- Properties = members = null;
-
- // Normalize the iteration algorithm.
- if (!size) {
- // A list of non-enumerable properties inherited from `Object.prototype`.
- members = ["valueOf", "toString", "toLocaleString", "propertyIsEnumerable", "isPrototypeOf", "hasOwnProperty", "constructor"];
- // IE <= 8, Mozilla 1.0, and Netscape 6.2 ignore shadowed non-enumerable
- // properties.
- forEach = function (object, callback) {
- var isFunction = getClass.call(object) == functionClass, property, length;
- var hasProperty = !isFunction && typeof object.constructor != "function" && objectTypes[typeof object.hasOwnProperty] && object.hasOwnProperty || isProperty;
- for (property in object) {
- // Gecko <= 1.0 enumerates the `prototype` property of functions under
- // certain conditions; IE does not.
- if (!(isFunction && property == "prototype") && hasProperty.call(object, property)) {
- callback(property);
- }
- }
- // Manually invoke the callback for each non-enumerable property.
- for (length = members.length; property = members[--length]; hasProperty.call(object, property) && callback(property));
- };
- } else if (size == 2) {
- // Safari <= 2.0.4 enumerates shadowed properties twice.
- forEach = function (object, callback) {
- // Create a set of iterated properties.
- var members = {}, isFunction = getClass.call(object) == functionClass, property;
- for (property in object) {
- // Store each property name to prevent double enumeration. The
- // `prototype` property of functions is not enumerated due to cross-
- // environment inconsistencies.
- if (!(isFunction && property == "prototype") && !isProperty.call(members, property) && (members[property] = 1) && isProperty.call(object, property)) {
- callback(property);
- }
- }
- };
- } else {
- // No bugs detected; use the standard `for...in` algorithm.
- forEach = function (object, callback) {
- var isFunction = getClass.call(object) == functionClass, property, isConstructor;
- for (property in object) {
- if (!(isFunction && property == "prototype") && isProperty.call(object, property) && !(isConstructor = property === "constructor")) {
- callback(property);
- }
- }
- // Manually invoke the callback for the `constructor` property due to
- // cross-environment inconsistencies.
- if (isConstructor || isProperty.call(object, (property = "constructor"))) {
- callback(property);
- }
- };
- }
- return forEach(object, callback);
- };
-
- // Public: Serializes a JavaScript `value` as a JSON string. The optional
- // `filter` argument may specify either a function that alters how object and
- // array members are serialized, or an array of strings and numbers that
- // indicates which properties should be serialized. The optional `width`
- // argument may be either a string or number that specifies the indentation
- // level of the output.
- if (!has("json-stringify")) {
- // Internal: A map of control characters and their escaped equivalents.
- var Escapes = {
- 92: "\\\\",
- 34: '\\"',
- 8: "\\b",
- 12: "\\f",
- 10: "\\n",
- 13: "\\r",
- 9: "\\t"
- };
-
- // Internal: Converts `value` into a zero-padded string such that its
- // length is at least equal to `width`. The `width` must be <= 6.
- var leadingZeroes = "000000";
- var toPaddedString = function (width, value) {
- // The `|| 0` expression is necessary to work around a bug in
- // Opera <= 7.54u2 where `0 == -0`, but `String(-0) !== "0"`.
- return (leadingZeroes + (value || 0)).slice(-width);
- };
-
- // Internal: Double-quotes a string `value`, replacing all ASCII control
- // characters (characters with code unit values between 0 and 31) with
- // their escaped equivalents. This is an implementation of the
- // `Quote(value)` operation defined in ES 5.1 section 15.12.3.
- var unicodePrefix = "\\u00";
- var quote = function (value) {
- var result = '"', index = 0, length = value.length, useCharIndex = !charIndexBuggy || length > 10;
- var symbols = useCharIndex && (charIndexBuggy ? value.split("") : value);
- for (; index < length; index++) {
- var charCode = value.charCodeAt(index);
- // If the character is a control character, append its Unicode or
- // shorthand escape sequence; otherwise, append the character as-is.
- switch (charCode) {
- case 8: case 9: case 10: case 12: case 13: case 34: case 92:
- result += Escapes[charCode];
- break;
- default:
- if (charCode < 32) {
- result += unicodePrefix + toPaddedString(2, charCode.toString(16));
- break;
- }
- result += useCharIndex ? symbols[index] : value.charAt(index);
- }
- }
- return result + '"';
- };
-
- // Internal: Recursively serializes an object. Implements the
- // `Str(key, holder)`, `JO(value)`, and `JA(value)` operations.
- var serialize = function (property, object, callback, properties, whitespace, indentation, stack) {
- var value, className, year, month, date, time, hours, minutes, seconds, milliseconds, results, element, index, length, prefix, result;
- try {
- // Necessary for host object support.
- value = object[property];
- } catch (exception) {}
- if (typeof value == "object" && value) {
- className = getClass.call(value);
- if (className == dateClass && !isProperty.call(value, "toJSON")) {
- if (value > -1 / 0 && value < 1 / 0) {
- // Dates are serialized according to the `Date#toJSON` method
- // specified in ES 5.1 section 15.9.5.44. See section 15.9.1.15
- // for the ISO 8601 date time string format.
- if (getDay) {
- // Manually compute the year, month, date, hours, minutes,
- // seconds, and milliseconds if the `getUTC*` methods are
- // buggy. Adapted from @Yaffle's `date-shim` project.
- date = floor(value / 864e5);
- for (year = floor(date / 365.2425) + 1970 - 1; getDay(year + 1, 0) <= date; year++);
- for (month = floor((date - getDay(year, 0)) / 30.42); getDay(year, month + 1) <= date; month++);
- date = 1 + date - getDay(year, month);
- // The `time` value specifies the time within the day (see ES
- // 5.1 section 15.9.1.2). The formula `(A % B + B) % B` is used
- // to compute `A modulo B`, as the `%` operator does not
- // correspond to the `modulo` operation for negative numbers.
- time = (value % 864e5 + 864e5) % 864e5;
- // The hours, minutes, seconds, and milliseconds are obtained by
- // decomposing the time within the day. See section 15.9.1.10.
- hours = floor(time / 36e5) % 24;
- minutes = floor(time / 6e4) % 60;
- seconds = floor(time / 1e3) % 60;
- milliseconds = time % 1e3;
- } else {
- year = value.getUTCFullYear();
- month = value.getUTCMonth();
- date = value.getUTCDate();
- hours = value.getUTCHours();
- minutes = value.getUTCMinutes();
- seconds = value.getUTCSeconds();
- milliseconds = value.getUTCMilliseconds();
- }
- // Serialize extended years correctly.
- value = (year <= 0 || year >= 1e4 ? (year < 0 ? "-" : "+") + toPaddedString(6, year < 0 ? -year : year) : toPaddedString(4, year)) +
- "-" + toPaddedString(2, month + 1) + "-" + toPaddedString(2, date) +
- // Months, dates, hours, minutes, and seconds should have two
- // digits; milliseconds should have three.
- "T" + toPaddedString(2, hours) + ":" + toPaddedString(2, minutes) + ":" + toPaddedString(2, seconds) +
- // Milliseconds are optional in ES 5.0, but required in 5.1.
- "." + toPaddedString(3, milliseconds) + "Z";
- } else {
- value = null;
- }
- } else if (typeof value.toJSON == "function" && ((className != numberClass && className != stringClass && className != arrayClass) || isProperty.call(value, "toJSON"))) {
- // Prototype <= 1.6.1 adds non-standard `toJSON` methods to the
- // `Number`, `String`, `Date`, and `Array` prototypes. JSON 3
- // ignores all `toJSON` methods on these objects unless they are
- // defined directly on an instance.
- value = value.toJSON(property);
- }
- }
- if (callback) {
- // If a replacement function was provided, call it to obtain the value
- // for serialization.
- value = callback.call(object, property, value);
- }
- if (value === null) {
- return "null";
- }
- className = getClass.call(value);
- if (className == booleanClass) {
- // Booleans are represented literally.
- return "" + value;
- } else if (className == numberClass) {
- // JSON numbers must be finite. `Infinity` and `NaN` are serialized as
- // `"null"`.
- return value > -1 / 0 && value < 1 / 0 ? "" + value : "null";
- } else if (className == stringClass) {
- // Strings are double-quoted and escaped.
- return quote("" + value);
- }
- // Recursively serialize objects and arrays.
- if (typeof value == "object") {
- // Check for cyclic structures. This is a linear search; performance
- // is inversely proportional to the number of unique nested objects.
- for (length = stack.length; length--;) {
- if (stack[length] === value) {
- // Cyclic structures cannot be serialized by `JSON.stringify`.
- throw TypeError();
- }
- }
- // Add the object to the stack of traversed objects.
- stack.push(value);
- results = [];
- // Save the current indentation level and indent one additional level.
- prefix = indentation;
- indentation += whitespace;
- if (className == arrayClass) {
- // Recursively serialize array elements.
- for (index = 0, length = value.length; index < length; index++) {
- element = serialize(index, value, callback, properties, whitespace, indentation, stack);
- results.push(element === undef ? "null" : element);
- }
- result = results.length ? (whitespace ? "[\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "]" : ("[" + results.join(",") + "]")) : "[]";
- } else {
- // Recursively serialize object members. Members are selected from
- // either a user-specified list of property names, or the object
- // itself.
- forEach(properties || value, function (property) {
- var element = serialize(property, value, callback, properties, whitespace, indentation, stack);
- if (element !== undef) {
- // According to ES 5.1 section 15.12.3: "If `gap` {whitespace}
- // is not the empty string, let `member` {quote(property) + ":"}
- // be the concatenation of `member` and the `space` character."
- // The "`space` character" refers to the literal space
- // character, not the `space` {width} argument provided to
- // `JSON.stringify`.
- results.push(quote(property) + ":" + (whitespace ? " " : "") + element);
- }
- });
- result = results.length ? (whitespace ? "{\n" + indentation + results.join(",\n" + indentation) + "\n" + prefix + "}" : ("{" + results.join(",") + "}")) : "{}";
- }
- // Remove the object from the traversed object stack.
- stack.pop();
- return result;
- }
- };
-
- // Public: `JSON.stringify`. See ES 5.1 section 15.12.3.
- exports.stringify = function (source, filter, width) {
- var whitespace, callback, properties, className;
- if (objectTypes[typeof filter] && filter) {
- if ((className = getClass.call(filter)) == functionClass) {
- callback = filter;
- } else if (className == arrayClass) {
- // Convert the property names array into a makeshift set.
- properties = {};
- for (var index = 0, length = filter.length, value; index < length; value = filter[index++], ((className = getClass.call(value)), className == stringClass || className == numberClass) && (properties[value] = 1));
- }
- }
- if (width) {
- if ((className = getClass.call(width)) == numberClass) {
- // Convert the `width` to an integer and create a string containing
- // `width` number of space characters.
- if ((width -= width % 1) > 0) {
- for (whitespace = "", width > 10 && (width = 10); whitespace.length < width; whitespace += " ");
- }
- } else if (className == stringClass) {
- whitespace = width.length <= 10 ? width : width.slice(0, 10);
- }
- }
- // Opera <= 7.54u2 discards the values associated with empty string keys
- // (`""`) only if they are used directly within an object member list
- // (e.g., `!("" in { "": 1})`).
- return serialize("", (value = {}, value[""] = source, value), callback, properties, whitespace, "", []);
- };
- }
-
- // Public: Parses a JSON source string.
- if (!has("json-parse")) {
- var fromCharCode = String.fromCharCode;
-
- // Internal: A map of escaped control characters and their unescaped
- // equivalents.
- var Unescapes = {
- 92: "\\",
- 34: '"',
- 47: "/",
- 98: "\b",
- 116: "\t",
- 110: "\n",
- 102: "\f",
- 114: "\r"
- };
-
- // Internal: Stores the parser state.
- var Index, Source;
-
- // Internal: Resets the parser state and throws a `SyntaxError`.
- var abort = function () {
- Index = Source = null;
- throw SyntaxError();
- };
-
- // Internal: Returns the next token, or `"$"` if the parser has reached
- // the end of the source string. A token may be a string, number, `null`
- // literal, or Boolean literal.
- var lex = function () {
- var source = Source, length = source.length, value, begin, position, isSigned, charCode;
- while (Index < length) {
- charCode = source.charCodeAt(Index);
- switch (charCode) {
- case 9: case 10: case 13: case 32:
- // Skip whitespace tokens, including tabs, carriage returns, line
- // feeds, and space characters.
- Index++;
- break;
- case 123: case 125: case 91: case 93: case 58: case 44:
- // Parse a punctuator token (`{`, `}`, `[`, `]`, `:`, or `,`) at
- // the current position.
- value = charIndexBuggy ? source.charAt(Index) : source[Index];
- Index++;
- return value;
- case 34:
- // `"` delimits a JSON string; advance to the next character and
- // begin parsing the string. String tokens are prefixed with the
- // sentinel `@` character to distinguish them from punctuators and
- // end-of-string tokens.
- for (value = "@", Index++; Index < length;) {
- charCode = source.charCodeAt(Index);
- if (charCode < 32) {
- // Unescaped ASCII control characters (those with a code unit
- // less than the space character) are not permitted.
- abort();
- } else if (charCode == 92) {
- // A reverse solidus (`\`) marks the beginning of an escaped
- // control character (including `"`, `\`, and `/`) or Unicode
- // escape sequence.
- charCode = source.charCodeAt(++Index);
- switch (charCode) {
- case 92: case 34: case 47: case 98: case 116: case 110: case 102: case 114:
- // Revive escaped control characters.
- value += Unescapes[charCode];
- Index++;
- break;
- case 117:
- // `\u` marks the beginning of a Unicode escape sequence.
- // Advance to the first character and validate the
- // four-digit code point.
- begin = ++Index;
- for (position = Index + 4; Index < position; Index++) {
- charCode = source.charCodeAt(Index);
- // A valid sequence comprises four hexdigits (case-
- // insensitive) that form a single hexadecimal value.
- if (!(charCode >= 48 && charCode <= 57 || charCode >= 97 && charCode <= 102 || charCode >= 65 && charCode <= 70)) {
- // Invalid Unicode escape sequence.
- abort();
- }
- }
- // Revive the escaped character.
- value += fromCharCode("0x" + source.slice(begin, Index));
- break;
- default:
- // Invalid escape sequence.
- abort();
- }
- } else {
- if (charCode == 34) {
- // An unescaped double-quote character marks the end of the
- // string.
- break;
- }
- charCode = source.charCodeAt(Index);
- begin = Index;
- // Optimize for the common case where a string is valid.
- while (charCode >= 32 && charCode != 92 && charCode != 34) {
- charCode = source.charCodeAt(++Index);
- }
- // Append the string as-is.
- value += source.slice(begin, Index);
- }
- }
- if (source.charCodeAt(Index) == 34) {
- // Advance to the next character and return the revived string.
- Index++;
- return value;
- }
- // Unterminated string.
- abort();
- default:
- // Parse numbers and literals.
- begin = Index;
- // Advance past the negative sign, if one is specified.
- if (charCode == 45) {
- isSigned = true;
- charCode = source.charCodeAt(++Index);
- }
- // Parse an integer or floating-point value.
- if (charCode >= 48 && charCode <= 57) {
- // Leading zeroes are interpreted as octal literals.
- if (charCode == 48 && ((charCode = source.charCodeAt(Index + 1)), charCode >= 48 && charCode <= 57)) {
- // Illegal octal literal.
- abort();
- }
- isSigned = false;
- // Parse the integer component.
- for (; Index < length && ((charCode = source.charCodeAt(Index)), charCode >= 48 && charCode <= 57); Index++);
- // Floats cannot contain a leading decimal point; however, this
- // case is already accounted for by the parser.
- if (source.charCodeAt(Index) == 46) {
- position = ++Index;
- // Parse the decimal component.
- for (; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
- if (position == Index) {
- // Illegal trailing decimal.
- abort();
- }
- Index = position;
- }
- // Parse exponents. The `e` denoting the exponent is
- // case-insensitive.
- charCode = source.charCodeAt(Index);
- if (charCode == 101 || charCode == 69) {
- charCode = source.charCodeAt(++Index);
- // Skip past the sign following the exponent, if one is
- // specified.
- if (charCode == 43 || charCode == 45) {
- Index++;
- }
- // Parse the exponential component.
- for (position = Index; position < length && ((charCode = source.charCodeAt(position)), charCode >= 48 && charCode <= 57); position++);
- if (position == Index) {
- // Illegal empty exponent.
- abort();
- }
- Index = position;
- }
- // Coerce the parsed value to a JavaScript number.
- return +source.slice(begin, Index);
- }
- // A negative sign may only precede numbers.
- if (isSigned) {
- abort();
- }
- // `true`, `false`, and `null` literals.
- if (source.slice(Index, Index + 4) == "true") {
- Index += 4;
- return true;
- } else if (source.slice(Index, Index + 5) == "false") {
- Index += 5;
- return false;
- } else if (source.slice(Index, Index + 4) == "null") {
- Index += 4;
- return null;
- }
- // Unrecognized token.
- abort();
- }
- }
- // Return the sentinel `$` character if the parser has reached the end
- // of the source string.
- return "$";
- };
-
- // Internal: Parses a JSON `value` token.
- var get = function (value) {
- var results, hasMembers;
- if (value == "$") {
- // Unexpected end of input.
- abort();
- }
- if (typeof value == "string") {
- if ((charIndexBuggy ? value.charAt(0) : value[0]) == "@") {
- // Remove the sentinel `@` character.
- return value.slice(1);
- }
- // Parse object and array literals.
- if (value == "[") {
- // Parses a JSON array, returning a new JavaScript array.
- results = [];
- for (;; hasMembers || (hasMembers = true)) {
- value = lex();
- // A closing square bracket marks the end of the array literal.
- if (value == "]") {
- break;
- }
- // If the array literal contains elements, the current token
- // should be a comma separating the previous element from the
- // next.
- if (hasMembers) {
- if (value == ",") {
- value = lex();
- if (value == "]") {
- // Unexpected trailing `,` in array literal.
- abort();
- }
- } else {
- // A `,` must separate each array element.
- abort();
- }
- }
- // Elisions and leading commas are not permitted.
- if (value == ",") {
- abort();
- }
- results.push(get(value));
- }
- return results;
- } else if (value == "{") {
- // Parses a JSON object, returning a new JavaScript object.
- results = {};
- for (;; hasMembers || (hasMembers = true)) {
- value = lex();
- // A closing curly brace marks the end of the object literal.
- if (value == "}") {
- break;
- }
- // If the object literal contains members, the current token
- // should be a comma separator.
- if (hasMembers) {
- if (value == ",") {
- value = lex();
- if (value == "}") {
- // Unexpected trailing `,` in object literal.
- abort();
- }
- } else {
- // A `,` must separate each object member.
- abort();
- }
- }
- // Leading commas are not permitted, object property names must be
- // double-quoted strings, and a `:` must separate each property
- // name and value.
- if (value == "," || typeof value != "string" || (charIndexBuggy ? value.charAt(0) : value[0]) != "@" || lex() != ":") {
- abort();
- }
- results[value.slice(1)] = get(lex());
- }
- return results;
- }
- // Unexpected token encountered.
- abort();
- }
- return value;
- };
-
- // Internal: Updates a traversed object member.
- var update = function (source, property, callback) {
- var element = walk(source, property, callback);
- if (element === undef) {
- delete source[property];
- } else {
- source[property] = element;
- }
- };
-
- // Internal: Recursively traverses a parsed JSON object, invoking the
- // `callback` function for each value. This is an implementation of the
- // `Walk(holder, name)` operation defined in ES 5.1 section 15.12.2.
- var walk = function (source, property, callback) {
- var value = source[property], length;
- if (typeof value == "object" && value) {
- // `forEach` can't be used to traverse an array in Opera <= 8.54
- // because its `Object#hasOwnProperty` implementation returns `false`
- // for array indices (e.g., `![1, 2, 3].hasOwnProperty("0")`).
- if (getClass.call(value) == arrayClass) {
- for (length = value.length; length--;) {
- update(value, length, callback);
- }
- } else {
- forEach(value, function (property) {
- update(value, property, callback);
- });
- }
- }
- return callback.call(source, property, value);
- };
-
- // Public: `JSON.parse`. See ES 5.1 section 15.12.2.
- exports.parse = function (source, callback) {
- var result, value;
- Index = 0;
- Source = "" + source;
- result = get(lex());
- // If a JSON string contains multiple tokens, it is invalid.
- if (lex() != "$") {
- abort();
- }
- // Reset the parser state.
- Index = Source = null;
- return callback && getClass.call(callback) == functionClass ? walk((value = {}, value[""] = result, value), "", callback) : result;
- };
- }
- }
-
- exports["runInContext"] = runInContext;
- return exports;
- }
-
- if (freeExports && !isLoader) {
- // Export for CommonJS environments.
- runInContext(root, freeExports);
- } else {
- // Export for web browsers and JavaScript engines.
- var nativeJSON = root.JSON,
- previousJSON = root["JSON3"],
- isRestored = false;
-
- var JSON3 = runInContext(root, (root["JSON3"] = {
- // Public: Restores the original value of the global `JSON` object and
- // returns a reference to the `JSON3` object.
- "noConflict": function () {
- if (!isRestored) {
- isRestored = true;
- root.JSON = nativeJSON;
- root["JSON3"] = previousJSON;
- nativeJSON = previousJSON = null;
- }
- return JSON3;
- }
- }));
-
- root.JSON = {
- "parse": JSON3.parse,
- "stringify": JSON3.stringify
- };
- }
-
- // Export for asynchronous module loaders.
- if (isLoader) {
- define(function () {
- return JSON3;
- });
- }
-}).call(this);
-
-//##############################################################################
-// DomUtils.js
-//##############################################################################
-
-(function () {
-
- /**
- * A few utilities for interacting with the dom.
- * @class DomUtils
- */
- var s = {};
-
- s.appendToHead = function (el) {
- s.getHead().appendChild(el)
- }
-
- s.getHead = function () {
- return document.head || document.getElementsByTagName("head")[0];
- }
-
- s.getBody = function () {
- return document.body || document.getElementsByTagName("body")[0];
- }
-
- createjs.DomUtils = s;
-
-}());
-
-//##############################################################################
-// DataUtils.js
-//##############################################################################
-
-(function () {
-
- /**
- * A few data utilities for formatting different data types.
- * @class DataUtils
- */
- var s = {};
-
- // static methods
- /**
- * Parse XML using the DOM. This is required when preloading XML or SVG.
- * @method parseXML
- * @param {String} text The raw text or XML that is loaded by XHR.
- * @param {String} type The mime type of the XML. Use "text/xml" for XML, and "image/svg+xml" for SVG parsing.
- * @return {XML} An XML document
- * @static
- */
- s.parseXML = function (text, type) {
- var xml = null;
- // CocoonJS does not support XML parsing with either method.
-
- // Most browsers will use DOMParser
- // IE fails on certain SVG files, so we have a fallback below.
- try {
- if (window.DOMParser) {
- var parser = new DOMParser();
- xml = parser.parseFromString(text, type);
- }
- } catch (e) {
- }
-
- // Fallback for IE support.
- if (!xml) {
- try {
- xml = new ActiveXObject("Microsoft.XMLDOM");
- xml.async = false;
- xml.loadXML(text);
- } catch (e) {
- xml = null;
- }
- }
-
- return xml;
- };
-
- /**
- * Parse a string into an Object.
- * @method parseJSON
- * @param {String} value The loaded JSON string
- * @returns {Object} A JavaScript object.
- */
- s.parseJSON = function (value) {
- if (value == null) {
- return null;
- }
-
- try {
- return JSON.parse(value);
- } catch (e) {
- // TODO; Handle this with a custom error?
- throw e;
- }
- };
-
- createjs.DataUtils = s;
-
-}());
-
-//##############################################################################
-// LoadItem.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead,
- * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A
- * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the
- * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}}
- * @class LoadItem
- * @constructor
- * @since 0.6.0
- */
- function LoadItem() {
- /**
- * The source of the file that is being loaded. This property is required. The source can either be a
- * string (recommended), or an HTML tag.
- * This can also be an object, but in that case it has to include a type and be handled by a plugin.
- * @property src
- * @type {String}
- * @default null
- */
- this.src = null;
-
- /**
- * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also
- * be set manually. This is helpful in cases where a file does not have an extension.
- * @property type
- * @type {String}
- * @default null
- */
- this.type = null;
-
- /**
- * A string identifier which can be used to reference the loaded object. If none is provided, this will be
- * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}.
- * @property id
- * @type {String}
- * @default null
- */
- this.id = null;
-
- /**
- * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest
- * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has
- * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this
- * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in
- * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`.
- * @property maintainOrder
- * @type {Boolean}
- * @default false
- */
- this.maintainOrder = false;
-
- /**
- * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded.
- * @property callback
- * @type {String}
- * @default null
- */
- this.callback = null;
-
- /**
- * An arbitrary data object, which is included with the loaded object.
- * @property data
- * @type {Object}
- * @default null
- */
- this.data = null;
-
- /**
- * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or
- * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as
- * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}.
- * @property method
- * @type {String}
- * @default get
- */
- this.method = createjs.LoadItem.GET;
-
- /**
- * An object hash of name/value pairs to send to the server.
- * @property values
- * @type {Object}
- * @default null
- */
- this.values = null;
-
- /**
- * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default
- * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the
- * default headers by including them in your headers object.
- * @property headers
- * @type {Object}
- * @default null
- */
- this.headers = null;
-
- /**
- * Enable credentials for XHR requests.
- * @property withCredentials
- * @type {Boolean}
- * @default false
- */
- this.withCredentials = false;
-
- /**
- * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text
- * based files (json, xml, text, css, js).
- * @property mimeType
- * @type {String}
- * @default null
- */
- this.mimeType = null;
-
- /**
- * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain.
- * @property crossOrigin
- * @type {boolean}
- * @default Anonymous
- */
- this.crossOrigin = null;
-
- /**
- * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
- * (level one) loading, as XHR (level 2) provides its own timeout event.
- * @property loadTimeout
- * @type {Number}
- * @default 8000 (8 seconds)
- */
- this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
- };
-
- var p = LoadItem.prototype = {};
- var s = LoadItem;
-
- /**
- * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
- * (level one) loading, as XHR (level 2) provides its own timeout event.
- * @property LOAD_TIMEOUT_DEFAULT
- * @type {number}
- * @static
- */
- s.LOAD_TIMEOUT_DEFAULT = 8000;
-
- /**
- * Create a LoadItem.
- *
- *
String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
- *
LoadItem instances are returned as-is
- *
Objects are returned with any needed properties added
- *
- * @method create
- * @param {LoadItem|String|Object} value The load item value
- * @returns {LoadItem|Object}
- * @static
- */
- s.create = function (value) {
- if (typeof value == "string") {
- var item = new LoadItem();
- item.src = value;
- return item;
- } else if (value instanceof s) {
- return value;
- } else if (value instanceof Object && value.src) {
- if (value.loadTimeout == null) {
- value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
- }
- return value;
- } else {
- throw new Error("Type not recognized.");
- }
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- *
Example
- *
- * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true});
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the LoadItem instance.
- * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.)
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- createjs.LoadItem = s;
-
-}());
-
-//##############################################################################
-// RequestUtils.js
-//##############################################################################
-
-(function () {
-
- /**
- * Utilities that assist with parsing load items, and determining file types, etc.
- * @class RequestUtils
- */
- var s = {};
-
- /**
- * The Regular Expression used to test file URLS for an absolute path.
- * @property ABSOLUTE_PATH
- * @type {RegExp}
- * @static
- */
- s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i;
-
- /**
- * The Regular Expression used to test file URLS for a relative path.
- * @property RELATIVE_PATH
- * @type {RegExp}
- * @static
- */
- s.RELATIVE_PATT = (/^[./]*?\//i);
-
- /**
- * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string
- * removed.
- * @property EXTENSION_PATT
- * @type {RegExp}
- * @static
- */
- s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i;
-
- /**
- * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know:
- *
- *
If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or
- * `//networkPath`)
- *
If the path is relative. Relative paths start with `../` or `/path` (or similar)
- *
The file extension. This is determined by the filename with an extension. Query strings are dropped, and
- * the file path is expected to follow the format `name.ext`.
- *
- * @method parseURI
- * @param {String} path
- * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension`
- * property, which is the lowercase extension.
- * @static
- */
- s.parseURI = function (path) {
- var info = {absolute: false, relative: false};
- if (path == null) { return info; }
-
- // Drop the query string
- var queryIndex = path.indexOf("?");
- if (queryIndex > -1) {
- path = path.substr(0, queryIndex);
- }
-
- // Absolute
- var match;
- if (s.ABSOLUTE_PATT.test(path)) {
- info.absolute = true;
-
- // Relative
- } else if (s.RELATIVE_PATT.test(path)) {
- info.relative = true;
- }
-
- // Extension
- if (match = path.match(s.EXTENSION_PATT)) {
- info.extension = match[1].toLowerCase();
- }
- return info;
- };
-
- /**
- * Formats an object into a query string for either a POST or GET request.
- * @method formatQueryString
- * @param {Object} data The data to convert to a query string.
- * @param {Array} [query] Existing name/value pairs to append on to this query.
- * @static
- */
- s.formatQueryString = function (data, query) {
- if (data == null) {
- throw new Error('You must specify data.');
- }
- var params = [];
- for (var n in data) {
- params.push(n + '=' + escape(data[n]));
- }
- if (query) {
- params = params.concat(query);
- }
- return params.join('&');
- };
-
- /**
- * A utility method that builds a file path using a source and a data object, and formats it into a new path.
- * @method buildPath
- * @param {String} src The source path to add values to.
- * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the
- * path will be preserved.
- * @returns {string} A formatted string that contains the path and the supplied parameters.
- * @static
- */
- s.buildPath = function (src, data) {
- if (data == null) {
- return src;
- }
-
- var query = [];
- var idx = src.indexOf('?');
-
- if (idx != -1) {
- var q = src.slice(idx + 1);
- query = query.concat(q.split('&'));
- }
-
- if (idx != -1) {
- return src.slice(0, idx) + '?' + this.formatQueryString(data, query);
- } else {
- return src + '?' + this.formatQueryString(data, query);
- }
- };
-
- /**
- * @method isCrossDomain
- * @param {LoadItem|Object} item A load item with a `src` property.
- * @return {Boolean} If the load item is loading from a different domain than the current location.
- * @static
- */
- s.isCrossDomain = function (item) {
- var target = document.createElement("a");
- target.href = item.src;
-
- var host = document.createElement("a");
- host.href = location.href;
-
- var crossdomain = (target.hostname != "") &&
- (target.port != host.port ||
- target.protocol != host.protocol ||
- target.hostname != host.hostname);
- return crossdomain;
- };
-
- /**
- * @method isLocal
- * @param {LoadItem|Object} item A load item with a `src` property
- * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as
- * well.
- * @static
- */
- s.isLocal = function (item) {
- var target = document.createElement("a");
- target.href = item.src;
- return target.hostname == "" && target.protocol == "file:";
- };
-
- /**
- * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked
- * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play
- * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get
- * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on
- * {{#crossLink "AbstractLoader"}}{{/crossLink}}.
- * @method isBinary
- * @param {String} type The item type.
- * @return {Boolean} If the specified type is binary.
- * @static
- */
- s.isBinary = function (type) {
- switch (type) {
- case createjs.AbstractLoader.IMAGE:
- case createjs.AbstractLoader.BINARY:
- return true;
- default:
- return false;
- }
- };
-
- /**
- * Check if item is a valid HTMLImageElement
- * @method isImageTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isImageTag = function(item) {
- return item instanceof HTMLImageElement;
- };
-
- /**
- * Check if item is a valid HTMLAudioElement
- * @method isAudioTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isAudioTag = function(item) {
- if (window.HTMLAudioElement) {
- return item instanceof HTMLAudioElement;
- } else {
- return false;
- }
- };
-
- /**
- * Check if item is a valid HTMLVideoElement
- * @method isVideoTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isVideoTag = function(item) {
- if (window.HTMLVideoElement) {
- return item instanceof HTMLVideoElement;
- } else {
- return false;
- }
- };
-
- /**
- * Determine if a specific type is a text-based asset, and should be loaded as UTF-8.
- * @method isText
- * @param {String} type The item type.
- * @return {Boolean} If the specified type is text.
- * @static
- */
- s.isText = function (type) {
- switch (type) {
- case createjs.AbstractLoader.TEXT:
- case createjs.AbstractLoader.JSON:
- case createjs.AbstractLoader.MANIFEST:
- case createjs.AbstractLoader.XML:
- case createjs.AbstractLoader.CSS:
- case createjs.AbstractLoader.SVG:
- case createjs.AbstractLoader.JAVASCRIPT:
- case createjs.AbstractLoader.SPRITESHEET:
- return true;
- default:
- return false;
- }
- };
-
- /**
- * Determine the type of the object using common extensions. Note that the type can be passed in with the load item
- * if it is an unusual extension.
- * @method getTypeByExtension
- * @param {String} extension The file extension to use to determine the load type.
- * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if
- * the type can not be determined by the extension.
- * @static
- */
- s.getTypeByExtension = function (extension) {
- if (extension == null) {
- return createjs.AbstractLoader.TEXT;
- }
-
- switch (extension.toLowerCase()) {
- case "jpeg":
- case "jpg":
- case "gif":
- case "png":
- case "webp":
- case "bmp":
- return createjs.AbstractLoader.IMAGE;
- case "ogg":
- case "mp3":
- case "webm":
- return createjs.AbstractLoader.SOUND;
- case "mp4":
- case "webm":
- case "ts":
- return createjs.AbstractLoader.VIDEO;
- case "json":
- return createjs.AbstractLoader.JSON;
- case "xml":
- return createjs.AbstractLoader.XML;
- case "css":
- return createjs.AbstractLoader.CSS;
- case "js":
- return createjs.AbstractLoader.JAVASCRIPT;
- case 'svg':
- return createjs.AbstractLoader.SVG;
- default:
- return createjs.AbstractLoader.TEXT;
- }
- };
-
- createjs.RequestUtils = s;
-
-}());
-
-//##############################################################################
-// AbstractLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-// constructor
- /**
- * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class,
- * including the {{#crossLink "LoadQueue"}}{{/crossLink}}.
- * @class AbstractLoader
- * @param {LoadItem|object|string} loadItem The item to be loaded.
- * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a
- * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the
- * other, so this is a suggested directive.
- * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class,
- * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc.
- * @extends EventDispatcher
- */
- function AbstractLoader(loadItem, preferXHR, type) {
- this.EventDispatcher_constructor();
-
- // public properties
- /**
- * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches
- * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}.
- * @property loaded
- * @type {Boolean}
- * @default false
- */
- this.loaded = false;
-
- /**
- * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property
- * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}}
- * instead.
- * @property canceled
- * @type {Boolean}
- * @default false
- * @readonly
- */
- this.canceled = false;
-
- /**
- * The current load progress (percentage) for this item. This will be a number between 0 and 1.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.loadFile("largeImage.png");
- * queue.on("progress", function() {
- * console.log("Progress:", queue.progress, event.progress);
- * });
- *
- * @property progress
- * @type {Number}
- * @default 0
- */
- this.progress = 0;
-
- /**
- * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of
- * supported types.
- * @property type
- * @type {String}
- */
- this.type = type;
-
- /**
- * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader
- * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property
- * can be overridden to provide custom formatting.
- *
- * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be
- * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks
- * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is
- * called in the current scope, as well as the success and error callbacks.
- *
- *
Example asynchronous resultFormatter
- *
- * function _formatResult(loader) {
- * return function(success, error) {
- * if (errorCondition) { error(errorDetailEvent); }
- * success(result);
- * }
- * }
- * @property resultFormatter
- * @type {Function}
- * @default null
- */
- this.resultFormatter = null;
-
- // protected properties
- /**
- * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}},
- * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}.
- * @property _item
- * @type {LoadItem|Object}
- * @private
- */
- if (loadItem) {
- this._item = createjs.LoadItem.create(loadItem);
- } else {
- this._item = null;
- }
-
- /**
- * Whether the loader will try and load content using XHR (true) or HTML tags (false).
- * @property _preferXHR
- * @type {Boolean}
- * @private
- */
- this._preferXHR = preferXHR;
-
- /**
- * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For
- * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}.
- * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method.
- * @property _result
- * @type {Object|String}
- * @private
- */
- this._result = null;
-
- /**
- * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}}
- * method, and passing `true`.
- * @property _rawResult
- * @type {Object|String}
- * @private
- */
- this._rawResult = null;
-
- /**
- * A list of items that loaders load behind the scenes. This does not include the main item the loader is
- * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and
- * {{#crossLink "ManifestLoader"}}{{/crossLink}}.
- * @property _loadItems
- * @type {null}
- * @protected
- */
- this._loadedItems = null;
-
- /**
- * The attribute the items loaded using tags use for the source.
- * @type {string}
- * @default null
- * @private
- */
- this._tagSrcAttribute = null;
-
- /**
- * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc.
- * @property _tag
- * @type {Object}
- * @private
- */
- this._tag = null;
- };
-
- var p = createjs.extend(AbstractLoader, createjs.EventDispatcher);
- var s = AbstractLoader;
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
- /**
- * Defines a POST request, use for a method value when loading data.
- * @property POST
- * @type {string}
- * @default post
- * @static
- */
- s.POST = "POST";
-
- /**
- * Defines a GET request, use for a method value when loading data.
- * @property GET
- * @type {string}
- * @default get
- * @static
- */
- s.GET = "GET";
-
- /**
- * The preload type for generic binary types. Note that images are loaded as binary files when using XHR.
- * @property BINARY
- * @type {String}
- * @default binary
- * @static
- * @since 0.6.0
- */
- s.BINARY = "binary";
-
- /**
- * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a
- * <style> tag when loaded with tags.
- * @property CSS
- * @type {String}
- * @default css
- * @static
- * @since 0.6.0
- */
- s.CSS = "css";
-
- /**
- * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag.
- * @property IMAGE
- * @type {String}
- * @default image
- * @static
- * @since 0.6.0
- */
- s.IMAGE = "image";
-
- /**
- * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a
- * <script> tag.
- *
- * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into
- * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier,
- * only tag-loaded scripts are injected.
- * @property JAVASCRIPT
- * @type {String}
- * @default javascript
- * @static
- * @since 0.6.0
- */
- s.JAVASCRIPT = "javascript";
-
- /**
- * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a
- * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP,
- * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON
- * must contain a matching wrapper function.
- * @property JSON
- * @type {String}
- * @default json
- * @static
- * @since 0.6.0
- */
- s.JSON = "json";
-
- /**
- * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a
- * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON.
- * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}}
- * property is set to.
- * @property JSONP
- * @type {String}
- * @default jsonp
- * @static
- * @since 0.6.0
- */
- s.JSONP = "jsonp";
-
- /**
- * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded
- * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an
- * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
- * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead,
- * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to.
- * @property MANIFEST
- * @type {String}
- * @default manifest
- * @static
- * @since 0.6.0
- */
- s.MANIFEST = "manifest";
-
- /**
- * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an
- * <audio> tag.
- * @property SOUND
- * @type {String}
- * @default sound
- * @static
- * @since 0.6.0
- */
- s.SOUND = "sound";
-
- /**
- * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an
- * <video> tag.
- * @property VIDEO
- * @type {String}
- * @default video
- * @static
- * @since 0.6.0
- */
- s.VIDEO = "video";
-
- /**
- * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths.
- * @property SPRITESHEET
- * @type {String}
- * @default spritesheet
- * @static
- * @since 0.6.0
- */
- s.SPRITESHEET = "spritesheet";
-
- /**
- * The preload type for SVG files.
- * @property SVG
- * @type {String}
- * @default svg
- * @static
- * @since 0.6.0
- */
- s.SVG = "svg";
-
- /**
- * The preload type for text files, which is also the default file type if the type can not be determined. Text is
- * loaded as raw text.
- * @property TEXT
- * @type {String}
- * @default text
- * @static
- * @since 0.6.0
- */
- s.TEXT = "text";
-
- /**
- * The preload type for xml files. XML is loaded into an XML document.
- * @property XML
- * @type {String}
- * @default xml
- * @static
- * @since 0.6.0
- */
- s.XML = "xml";
-
-// Events
- /**
- * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to
- * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}.
- * @event progress
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts.
- * @event loadstart
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.3.1
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded.
- * @event complete
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was
- * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was
- * just a regular {{#crossLink "Event"}}{{/crossLink}}.
- * @event error
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error.
- * This enables loaders to maintain internal queues, and surface file load errors.
- * @event fileerror
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The even type ("fileerror")
- * @param {LoadItem|object} The item that encountered the error
- * @since 0.6.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables
- * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s
- * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a
- * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event.
- * @event fileload
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type ("fileload")
- * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the
- * object will contain that value as a `src` property.
- * @param {Object} result The HTML tag or parsed result of the loaded item.
- * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted
- * to a usable object.
- * @since 0.6.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load.
- * This allows updates to the loader for specific loading needs, such as binary or XHR image loading.
- * @event initialize
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type ("initialize")
- * @param {AbstractLoader} loader The loader that has been initialized.
- */
-
-
- /**
- * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was
- * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or
- * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will
- * be a {{#crossLink "LoadItem"}}{{/crossLink}}.
- * @method getItem
- * @return {Object} The manifest item that this loader is responsible for loading.
- * @since 0.6.0
- */
- p.getItem = function () {
- return this._item;
- };
-
- /**
- * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}}
- * event is dispatched.
- * @method getResult
- * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded
- * data (if it exists).
- * @return {Object}
- * @since 0.6.0
- */
- p.getResult = function (raw) {
- return raw ? this._rawResult : this._result;
- };
-
- /**
- * Return the `tag` this object creates or uses for loading.
- * @method getTag
- * @return {Object} The tag instance
- * @since 0.6.0
- */
- p.getTag = function () {
- return this._tag;
- };
-
- /**
- * Set the `tag` this item uses for loading.
- * @method setTag
- * @param {Object} tag The tag instance
- * @since 0.6.0
- */
- p.setTag = function(tag) {
- this._tag = tag;
- };
-
- /**
- * Begin loading the item. This method is required when using a loader by itself.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.on("complete", handleComplete);
- * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet
- * queue.load();
- *
- * @method load
- */
- p.load = function () {
- this._createRequest();
-
- this._request.on("complete", this, this);
- this._request.on("progress", this, this);
- this._request.on("loadStart", this, this);
- this._request.on("abort", this, this);
- this._request.on("timeout", this, this);
- this._request.on("error", this, this);
-
- var evt = new createjs.Event("initialize");
- evt.loader = this._request;
- this.dispatchEvent(evt);
-
- this._request.load();
- };
-
- /**
- * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in
- * the background), but events will not longer be dispatched.
- * @method cancel
- */
- p.cancel = function () {
- this.canceled = true;
- this.destroy();
- };
-
- /**
- * Clean up the loader.
- * @method destroy
- */
- p.destroy = function() {
- if (this._request) {
- this._request.removeAllEventListeners();
- this._request.destroy();
- }
-
- this._request = null;
-
- this._item = null;
- this._rawResult = null;
- this._result = null;
-
- this._loadItems = null;
-
- this.removeAllEventListeners();
- };
-
- /**
- * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}}
- * to expose items it loads internally.
- * @method getLoadedItems
- * @return {Array} A list of the items loaded by the loader.
- * @since 0.6.0
- */
- p.getLoadedItems = function () {
- return this._loadedItems;
- };
-
-
- // Private methods
- /**
- * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or
- * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}.
- * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}},
- * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood.
- * @method _createRequest
- * @protected
- */
- p._createRequest = function() {
- if (!this._preferXHR) {
- this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
- } else {
- this._request = new createjs.XHRRequest(this._item);
- }
- };
-
- /**
- * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented
- * by loaders that require tag loading.
- * @method _createTag
- * @param {String} src The tag source
- * @return {HTMLElement} The tag that was created
- * @protected
- */
- p._createTag = function(src) { return null; };
-
- /**
- * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}}
- * event for details on the event payload.
- * @method _sendLoadStart
- * @protected
- */
- p._sendLoadStart = function () {
- if (this._isCanceled()) { return; }
- this.dispatchEvent("loadstart");
- };
-
- /**
- * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}.
- * @method _sendProgress
- * @param {Number | Object} value The progress of the loaded item, or an object containing loaded
- * and total properties.
- * @protected
- */
- p._sendProgress = function (value) {
- if (this._isCanceled()) { return; }
- var event = null;
- if (typeof(value) == "number") {
- this.progress = value;
- event = new createjs.ProgressEvent(this.progress);
- } else {
- event = value;
- this.progress = value.loaded / value.total;
- event.progress = this.progress;
- if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
- }
- this.hasEventListener("progress") && this.dispatchEvent(event);
- };
-
- /**
- * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event
- * @method _sendComplete
- * @protected
- */
- p._sendComplete = function () {
- if (this._isCanceled()) { return; }
-
- this.loaded = true;
-
- var event = new createjs.Event("complete");
- event.rawResult = this._rawResult;
-
- if (this._result != null) {
- event.result = this._result;
- }
-
- this.dispatchEvent(event);
- };
-
- /**
- * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}
- * event for details on the event payload.
- * @method _sendError
- * @param {ErrorEvent} event The event object containing specific error properties.
- * @protected
- */
- p._sendError = function (event) {
- if (this._isCanceled() || !this.hasEventListener("error")) { return; }
- if (event == null) {
- event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error
- }
- this.dispatchEvent(event);
- };
-
- /**
- * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events
- * do not cause issues after the queue has been cleaned up.
- * @method _isCanceled
- * @return {Boolean} If the loader has been canceled.
- * @protected
- */
- p._isCanceled = function () {
- if (window.createjs == null || this.canceled) {
- return true;
- }
- return false;
- };
-
- /**
- * A custom result formatter function, which is called just before a request dispatches its complete event. Most
- * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The
- * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`.
- * @property resultFormatter
- * @type Function
- * @return {Object} The formatted result
- * @since 0.6.0
- */
- p.resultFormatter = null;
-
- /**
- * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but
- * this method can be overridden for custom behaviours.
- * @method handleEvent
- * @param {Event} event The event that the internal request dispatches.
- * @protected
- * @since 0.6.0
- */
- p.handleEvent = function (event) {
- switch (event.type) {
- case "complete":
- this._rawResult = event.target._response;
- var result = this.resultFormatter && this.resultFormatter(this);
- if (result instanceof Function) {
- result.call(this,
- createjs.proxy(this._resultFormatSuccess, this),
- createjs.proxy(this._resultFormatFailed, this)
- );
- } else {
- this._result = result || this._rawResult;
- this._sendComplete();
- }
- break;
- case "progress":
- this._sendProgress(event);
- break;
- case "error":
- this._sendError(event);
- break;
- case "loadstart":
- this._sendLoadStart();
- break;
- case "abort":
- case "timeout":
- if (!this._isCanceled()) {
- this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR"));
- }
- break;
- }
- };
-
- /**
- * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
- * functions.
- * @method _resultFormatSuccess
- * @param {Object} result The formatted result
- * @private
- */
- p._resultFormatSuccess = function (result) {
- this._result = result;
- this._sendComplete();
- };
-
- /**
- * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
- * functions.
- * @method _resultFormatSuccess
- * @param {Object} error The error event
- * @private
- */
- p._resultFormatFailed = function (event) {
- this._sendError(event);
- };
-
- /**
- * @method buildPath
- * @protected
- * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}}
- * instead.
- */
- p.buildPath = function (src, data) {
- return createjs.RequestUtils.buildPath(src, data);
- };
-
- /**
- * @method toString
- * @return {String} a string representation of the instance.
- */
- p.toString = function () {
- return "[PreloadJS AbstractLoader]";
- };
-
- createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher");
-
-}());
-
-//##############################################################################
-// AbstractMediaLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that
- * handle HTML media elements, such as Video and Audio.
- * @class AbstractMediaLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @param {String} type The type of media to load. Usually "video" or "audio".
- * @extends AbstractLoader
- * @constructor
- */
- function AbstractMediaLoader(loadItem, preferXHR, type) {
- this.AbstractLoader_constructor(loadItem, preferXHR, type);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "src";
-
- this.on("initialize", this._updateXHR, this);
- };
-
- var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader);
-
- // static properties
- // public methods
- p.load = function () {
- // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here.
- if (!this._tag) {
- this._tag = this._createTag(this._item.src);
- }
-
- this._tag.preload = "auto";
- this._tag.load();
-
- this.AbstractLoader_load();
- };
-
- // protected methods
- /**
- * Creates a new tag for loading if it doesn't exist yet.
- * @method _createTag
- * @private
- */
- p._createTag = function () {};
-
-
- p._createRequest = function() {
- if (!this._preferXHR) {
- this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
- } else {
- this._request = new createjs.XHRRequest(this._item);
- }
- };
-
- // protected methods
- /**
- * Before the item loads, set its mimeType and responseType.
- * @property _updateXHR
- * @param {Event} event
- * @private
- */
- p._updateXHR = function (event) {
- // Only exists for XHR
- if (event.loader.setResponseType) {
- event.loader.setResponseType("blob");
- }
- };
-
- /**
- * The result formatter for media files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLVideoElement|HTMLAudioElement}
- * @private
- */
- p._formatResult = function (loader) {
- this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
- this._tag.onstalled = null;
- if (this._preferXHR) {
- var URL = window.URL || window.webkitURL;
- var result = loader.getResult(true);
-
- loader.getTag().src = URL.createObjectURL(result);
- }
- return loader.getTag();
- };
-
- createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// AbstractRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}},
- * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the
- * hood to get data.
- * @class AbstractRequest
- * @param {LoadItem} item
- * @constructor
- */
- var AbstractRequest = function (item) {
- this._item = item;
- };
-
- var p = createjs.extend(AbstractRequest, createjs.EventDispatcher);
-
- // public methods
- /**
- * Begin a load.
- * @method load
- */
- p.load = function() {};
-
- /**
- * Clean up a request.
- * @method destroy
- */
- p.destroy = function() {};
-
- /**
- * Cancel an in-progress request.
- * @method cancel
- */
- p.cancel = function() {};
-
- createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher");
-
-}());
-
-//##############################################################################
-// TagRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts.
- * @class TagRequest
- * @param {LoadItem} loadItem
- * @param {HTMLElement} tag
- * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
- */
- function TagRequest(loadItem, tag, srcAttribute) {
- this.AbstractRequest_constructor(loadItem);
-
- // protected properties
- /**
- * The HTML tag instance that is used to load.
- * @property _tag
- * @type {HTMLElement}
- * @protected
- */
- this._tag = tag;
-
- /**
- * The tag attribute that specifies the source, such as "src", "href", etc.
- * @property _tagSrcAttribute
- * @type {String}
- * @protected
- */
- this._tagSrcAttribute = srcAttribute;
-
- /**
- * A method closure used for handling the tag load event.
- * @property _loadedHandler
- * @type {Function}
- * @private
- */
- this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
-
- /**
- * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after.
- * @property _addedToDOM
- * @type {Boolean}
- * @private
- */
- this._addedToDOM = false;
-
- /**
- * Determines what the tags initial style.visibility was, so we can set it correctly after a load.
- *
- * @type {null}
- * @private
- */
- this._startTagVisibility = null;
- };
-
- var p = createjs.extend(TagRequest, createjs.AbstractRequest);
-
- // public methods
- p.load = function () {
- this._tag.onload = createjs.proxy(this._handleTagComplete, this);
- this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this);
- this._tag.onerror = createjs.proxy(this._handleError, this);
-
- var evt = new createjs.Event("initialize");
- evt.loader = this._tag;
-
- this.dispatchEvent(evt);
-
- this._hideTag();
-
- this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
-
- this._tag[this._tagSrcAttribute] = this._item.src;
-
- // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail.
- if (this._tag.parentNode == null) {
- window.document.body.appendChild(this._tag);
- this._addedToDOM = true;
- }
- };
-
- p.destroy = function() {
- this._clean();
- this._tag = null;
-
- this.AbstractRequest_destroy();
- };
-
- // private methods
- /**
- * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT
- * and LINK tags), but other cases may exist.
- * @method _handleReadyStateChange
- * @private
- */
- p._handleReadyStateChange = function () {
- clearTimeout(this._loadTimeout);
- // This is strictly for tags in browsers that do not support onload.
- var tag = this._tag;
-
- // Complete is for old IE support.
- if (tag.readyState == "loaded" || tag.readyState == "complete") {
- this._handleTagComplete();
- }
- };
-
- /**
- * Handle any error events from the tag.
- * @method _handleError
- * @protected
- */
- p._handleError = function() {
- this._clean();
- this.dispatchEvent("error");
- };
-
- /**
- * Handle the tag's onload callback.
- * @method _handleTagComplete
- * @private
- */
- p._handleTagComplete = function () {
- this._rawResult = this._tag;
- this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult;
-
- this._clean();
- this._showTag();
-
- this.dispatchEvent("complete");
- };
-
- /**
- * The tag request has not loaded within the time specified in loadTimeout.
- * @method _handleError
- * @param {Object} event The XHR error event.
- * @private
- */
- p._handleTimeout = function () {
- this._clean();
- this.dispatchEvent(new createjs.Event("timeout"));
- };
-
- /**
- * Remove event listeners, but don't destroy the request object
- * @method _clean
- * @private
- */
- p._clean = function() {
- this._tag.onload = null;
- this._tag.onreadystatechange = null;
- this._tag.onerror = null;
- if (this._addedToDOM && this._tag.parentNode != null) {
- this._tag.parentNode.removeChild(this._tag);
- }
- clearTimeout(this._loadTimeout);
- };
-
- p._hideTag = function() {
- this._startTagVisibility = this._tag.style.visibility;
- this._tag.style.visibility = "hidden";
- };
-
- p._showTag = function() {
- this._tag.style.visibility = this._startTagVisibility;
- };
-
- /**
- * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio
- * that is already in a load, but not complete.
- * @method _handleStalled
- * @private
- */
- p._handleStalled = function () {
- //Ignore, let the timeout take care of it. Sometimes its not really stopped.
- };
-
- createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest");
-
-}());
-
-//##############################################################################
-// MediaTagRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio.
- * @class MediaTagRequest
- * @param {LoadItem} loadItem
- * @param {HTMLAudioElement|HTMLVideoElement} tag
- * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
- * @constructor
- */
- function MediaTagRequest(loadItem, tag, srcAttribute) {
- this.AbstractRequest_constructor(loadItem);
-
- // protected properties
- this._tag = tag;
- this._tagSrcAttribute = srcAttribute;
- this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
- };
-
- var p = createjs.extend(MediaTagRequest, createjs.TagRequest);
- var s = MediaTagRequest;
-
- // public methods
- p.load = function () {
- var sc = createjs.proxy(this._handleStalled, this);
- this._stalledCallback = sc;
-
- var pc = createjs.proxy(this._handleProgress, this);
- this._handleProgress = pc;
-
- this._tag.addEventListener("stalled", sc);
- this._tag.addEventListener("progress", pc);
-
- // This will tell us when audio is buffered enough to play through, but not when its loaded.
- // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient.
- this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event.
-
- this.TagRequest_load();
- };
-
- // private methods
- p._handleReadyStateChange = function () {
- clearTimeout(this._loadTimeout);
- // This is strictly for tags in browsers that do not support onload.
- var tag = this._tag;
-
- // Complete is for old IE support.
- if (tag.readyState == "loaded" || tag.readyState == "complete") {
- this._handleTagComplete();
- }
- };
-
- p._handleStalled = function () {
- //Ignore, let the timeout take care of it. Sometimes its not really stopped.
- };
-
- /**
- * An XHR request has reported progress.
- * @method _handleProgress
- * @param {Object} event The XHR progress event.
- * @private
- */
- p._handleProgress = function (event) {
- if (!event || event.loaded > 0 && event.total == 0) {
- return; // Sometimes we get no "total", so just ignore the progress event.
- }
-
- var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
- this.dispatchEvent(newEvent);
- };
-
- // protected methods
- p._clean = function () {
- this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
- this._tag.removeEventListener("stalled", this._stalledCallback);
- this._tag.removeEventListener("progress", this._progressCallback);
-
- this.TagRequest__clean();
- };
-
- createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest");
-
-}());
-
-//##############################################################################
-// XHRRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-// constructor
- /**
- * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used
- * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary.
- * XHR requests load the content as text or binary data, provide progress and consistent completion events, and
- * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for
- * cross-domain loading.
- * @class XHRRequest
- * @constructor
- * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * for an overview of supported file properties.
- * @extends AbstractLoader
- */
- function XHRRequest (item) {
- this.AbstractRequest_constructor(item);
-
- // protected properties
- /**
- * A reference to the XHR request used to load the content.
- * @property _request
- * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP}
- * @private
- */
- this._request = null;
-
- /**
- * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1,
- * typically IE9).
- * @property _loadTimeout
- * @type {Number}
- * @private
- */
- this._loadTimeout = null;
-
- /**
- * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect
- * the version, so we use capabilities to make a best guess.
- * @property _xhrLevel
- * @type {Number}
- * @default 1
- * @private
- */
- this._xhrLevel = 1;
-
- /**
- * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be
- * null until the file is loaded.
- * @property _response
- * @type {mixed}
- * @private
- */
- this._response = null;
-
- /**
- * The response of the loaded file before it is modified. In most cases, content is converted from raw text to
- * an HTML tag or a formatted object which is set to the result property, but the developer may still
- * want to access the raw content as it was loaded.
- * @property _rawResponse
- * @type {String|Object}
- * @private
- */
- this._rawResponse = null;
-
- this._canceled = false;
-
- // Setup our event handlers now.
- this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this);
- this._handleProgressProxy = createjs.proxy(this._handleProgress, this);
- this._handleAbortProxy = createjs.proxy(this._handleAbort, this);
- this._handleErrorProxy = createjs.proxy(this._handleError, this);
- this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this);
- this._handleLoadProxy = createjs.proxy(this._handleLoad, this);
- this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this);
-
- if (!this._createXHR(item)) {
- //TODO: Throw error?
- }
- };
-
- var p = createjs.extend(XHRRequest, createjs.AbstractRequest);
-
-// static properties
- /**
- * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE.
- * @property ACTIVEX_VERSIONS
- * @type {Array}
- * @since 0.4.2
- * @private
- */
- XHRRequest.ACTIVEX_VERSIONS = [
- "Msxml2.XMLHTTP.6.0",
- "Msxml2.XMLHTTP.5.0",
- "Msxml2.XMLHTTP.4.0",
- "MSXML2.XMLHTTP.3.0",
- "MSXML2.XMLHTTP",
- "Microsoft.XMLHTTP"
- ];
-
-// Public methods
- /**
- * Look up the loaded result.
- * @method getResult
- * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content
- * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be
- * returned instead.
- * @return {Object} A result object containing the content that was loaded, such as:
- *
- *
An image tag (<image />) for images
- *
A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the
- * HTML head.
- *
A style tag for CSS (<style />)
- *
Raw text for TEXT
- *
A formatted JavaScript object defined by JSON
- *
An XML document
- *
An binary arraybuffer loaded by XHR
- *
- * Note that if a raw result is requested, but not found, the result will be returned instead.
- */
- p.getResult = function (raw) {
- if (raw && this._rawResponse) {
- return this._rawResponse;
- }
- return this._response;
- };
-
- // Overrides abstract method in AbstractRequest
- p.cancel = function () {
- this.canceled = true;
- this._clean();
- this._request.abort();
- };
-
- // Overrides abstract method in AbstractLoader
- p.load = function () {
- if (this._request == null) {
- this._handleError();
- return;
- }
-
- //Events
- if (this._request.addEventListener != null) {
- this._request.addEventListener("loadstart", this._handleLoadStartProxy, false);
- this._request.addEventListener("progress", this._handleProgressProxy, false);
- this._request.addEventListener("abort", this._handleAbortProxy, false);
- this._request.addEventListener("error", this._handleErrorProxy, false);
- this._request.addEventListener("timeout", this._handleTimeoutProxy, false);
-
- // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
- this._request.addEventListener("load", this._handleLoadProxy, false);
- this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false);
- } else {
- // IE9 support
- this._request.onloadstart = this._handleLoadStartProxy;
- this._request.onprogress = this._handleProgressProxy;
- this._request.onabort = this._handleAbortProxy;
- this._request.onerror = this._handleErrorProxy;
- this._request.ontimeout = this._handleTimeoutProxy;
-
- // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
- this._request.onload = this._handleLoadProxy;
- this._request.onreadystatechange = this._handleReadyStateChangeProxy;
- }
-
- // Set up a timeout if we don't have XHR2
- if (this._xhrLevel == 1) {
- this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
- }
-
- // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome
- try {
- if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) {
- this._request.send();
- } else if (this._item.method == createjs.AbstractLoader.POST) {
- this._request.send(createjs.RequestUtils.formatQueryString(this._item.values));
- }
- } catch (error) {
- this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error));
- }
- };
-
- p.setResponseType = function (type) {
- // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded
- if (type === 'blob') {
- type = window.URL ? 'blob' : 'arraybuffer';
- this._responseType = type;
- }
- this._request.responseType = type;
- };
-
- /**
- * Get all the response headers from the XmlHttpRequest.
- *
- * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match
- * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair,
- * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE
- * pair.
- * @method getAllResponseHeaders
- * @return {String}
- * @since 0.4.1
- */
- p.getAllResponseHeaders = function () {
- if (this._request.getAllResponseHeaders instanceof Function) {
- return this._request.getAllResponseHeaders();
- } else {
- return null;
- }
- };
-
- /**
- * Get a specific response header from the XmlHttpRequest.
- *
- * From the docs: Returns the header field value from the response of which the field name matches
- * header, unless the field name is Set-Cookie or Set-Cookie2.
- * @method getResponseHeader
- * @param {String} header The header name to retrieve.
- * @return {String}
- * @since 0.4.1
- */
- p.getResponseHeader = function (header) {
- if (this._request.getResponseHeader instanceof Function) {
- return this._request.getResponseHeader(header);
- } else {
- return null;
- }
- };
-
-// protected methods
- /**
- * The XHR request has reported progress.
- * @method _handleProgress
- * @param {Object} event The XHR progress event.
- * @private
- */
- p._handleProgress = function (event) {
- if (!event || event.loaded > 0 && event.total == 0) {
- return; // Sometimes we get no "total", so just ignore the progress event.
- }
-
- var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
- this.dispatchEvent(newEvent);
- };
-
- /**
- * The XHR request has reported a load start.
- * @method _handleLoadStart
- * @param {Object} event The XHR loadStart event.
- * @private
- */
- p._handleLoadStart = function (event) {
- clearTimeout(this._loadTimeout);
- this.dispatchEvent("loadstart");
- };
-
- /**
- * The XHR request has reported an abort event.
- * @method handleAbort
- * @param {Object} event The XHR abort event.
- * @private
- */
- p._handleAbort = function (event) {
- this._clean();
- this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event));
- };
-
- /**
- * The XHR request has reported an error event.
- * @method _handleError
- * @param {Object} event The XHR error event.
- * @private
- */
- p._handleError = function (event) {
- this._clean();
- this.dispatchEvent(new createjs.ErrorEvent(event.message));
- };
-
- /**
- * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload
- * event, so we must monitor the readyStateChange to determine if the file is loaded.
- * @method _handleReadyStateChange
- * @param {Object} event The XHR readyStateChange event.
- * @private
- */
- p._handleReadyStateChange = function (event) {
- if (this._request.readyState == 4) {
- this._handleLoad();
- }
- };
-
- /**
- * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has
- * request.readyState == 4. Only the first call to this method will be processed.
- * @method _handleLoad
- * @param {Object} event The XHR load event.
- * @private
- */
- p._handleLoad = function (event) {
- if (this.loaded) {
- return;
- }
- this.loaded = true;
-
- var error = this._checkError();
- if (error) {
- this._handleError(error);
- return;
- }
-
- this._response = this._getResponse();
- // Convert arraybuffer back to blob
- if (this._responseType === 'arraybuffer') {
- try {
- this._response = new Blob([this._response]);
- } catch (e) {
- // Fallback to use BlobBuilder if Blob constructor is not supported
- // Tested on Android 2.3 ~ 4.2 and iOS5 safari
- window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
- if (e.name === 'TypeError' && window.BlobBuilder) {
- var builder = new BlobBuilder();
- builder.append(this._response);
- this._response = builder.getBlob();
- }
- }
- }
- this._clean();
-
- this.dispatchEvent(new createjs.Event("complete"));
- };
-
- /**
- * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout
- * callback.
- * @method _handleTimeout
- * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout.
- * @private
- */
- p._handleTimeout = function (event) {
- this._clean();
-
- this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event));
- };
-
-// Protected
- /**
- * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note
- * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code.
- * @method _checkError
- * @return {int} If the request status returns an error code.
- * @private
- */
- p._checkError = function () {
- //LM: Probably need additional handlers here, maybe 501
- var status = parseInt(this._request.status);
-
- switch (status) {
- case 404: // Not Found
- case 0: // Not Loaded
- return new Error(status);
- }
- return null;
- };
-
- /**
- * Validate the response. Different browsers have different approaches, some of which throw errors when accessed
- * in other browsers. If there is no response, the _response property will remain null.
- * @method _getResponse
- * @private
- */
- p._getResponse = function () {
- if (this._response != null) {
- return this._response;
- }
-
- if (this._request.response != null) {
- return this._request.response;
- }
-
- // Android 2.2 uses .responseText
- try {
- if (this._request.responseText != null) {
- return this._request.responseText;
- }
- } catch (e) {
- }
-
- // When loading XML, IE9 does not return .response, instead it returns responseXML.xml
- try {
- if (this._request.responseXML != null) {
- return this._request.responseXML;
- }
- } catch (e) {
- }
-
- return null;
- };
-
- /**
- * Create an XHR request. Depending on a number of factors, we get totally different results.
- *
Some browsers get an XDomainRequest when loading cross-domain.
- *
XMLHttpRequest are created when available.
- *
ActiveX.XMLHTTP objects are used in older IE browsers.
- *
Text requests override the mime type if possible
- *
Origin headers are sent for crossdomain requests in some browsers.
- *
Binary loads set the response type to "arraybuffer"
- * @method _createXHR
- * @param {Object} item The requested item that is being loaded.
- * @return {Boolean} If an XHR request or equivalent was successfully created.
- * @private
- */
- p._createXHR = function (item) {
- // Check for cross-domain loads. We can't fully support them, but we can try.
- var crossdomain = createjs.RequestUtils.isCrossDomain(item);
- var headers = {};
-
- // Create the request. Fallback to whatever support we have.
- var req = null;
- if (window.XMLHttpRequest) {
- req = new XMLHttpRequest();
- // This is 8 or 9, so use XDomainRequest instead.
- if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) {
- req = new XDomainRequest();
- }
- } else { // Old IE versions use a different approach
- for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) {
- var axVersion = s.ACTIVEX_VERSIONS[i];
- try {
- req = new ActiveXObject(axVersion);
- break;
- } catch (e) {
- }
- }
- if (req == null) {
- return false;
- }
- }
-
- // Default to utf-8 for Text requests.
- if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) {
- item.mimeType = "text/plain; charset=utf-8";
- }
-
- // IE9 doesn't support overrideMimeType(), so we need to check for it.
- if (item.mimeType && req.overrideMimeType) {
- req.overrideMimeType(item.mimeType);
- }
-
- // Determine the XHR level
- this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1;
-
- var src = null;
- if (item.method == createjs.AbstractLoader.GET) {
- src = createjs.RequestUtils.buildPath(item.src, item.values);
- } else {
- src = item.src;
- }
-
- // Open the request. Set cross-domain flags if it is supported (XHR level 1 only)
- req.open(item.method || createjs.AbstractLoader.GET, src, true);
-
- if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) {
- headers["Origin"] = location.origin;
- }
-
- // To send data we need to set the Content-type header)
- if (item.values && item.method == createjs.AbstractLoader.POST) {
- headers["Content-Type"] = "application/x-www-form-urlencoded";
- }
-
- if (!crossdomain && !headers["X-Requested-With"]) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- if (item.headers) {
- for (var n in item.headers) {
- headers[n] = item.headers[n];
- }
- }
-
- for (n in headers) {
- req.setRequestHeader(n, headers[n])
- }
-
- if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) {
- req.withCredentials = item.withCredentials;
- }
-
- this._request = req;
-
- return true;
- };
-
- /**
- * A request has completed (or failed or canceled), and needs to be disposed.
- * @method _clean
- * @private
- */
- p._clean = function () {
- clearTimeout(this._loadTimeout);
-
- if (this._request.removeEventListener != null) {
- this._request.removeEventListener("loadstart", this._handleLoadStartProxy);
- this._request.removeEventListener("progress", this._handleProgressProxy);
- this._request.removeEventListener("abort", this._handleAbortProxy);
- this._request.removeEventListener("error", this._handleErrorProxy);
- this._request.removeEventListener("timeout", this._handleTimeoutProxy);
- this._request.removeEventListener("load", this._handleLoadProxy);
- this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy);
- } else {
- this._request.onloadstart = null;
- this._request.onprogress = null;
- this._request.onabort = null;
- this._request.onerror = null;
- this._request.ontimeout = null;
- this._request.onload = null;
- this._request.onreadystatechange = null;
- }
- };
-
- p.toString = function () {
- return "[PreloadJS XHRRequest]";
- };
-
- createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest");
-
-}());
-
-//##############################################################################
-// LoadQueue.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-/*
- TODO: WINDOWS ISSUES
- * No error for HTML audio in IE 678
- * SVG no failure error in IE 67 (maybe 8) TAGS AND XHR
- * No script complete handler in IE 67 TAGS (XHR is fine)
- * No XML/JSON in IE6 TAGS
- * Need to hide loading SVG in Opera TAGS
- * No CSS onload/readystatechange in Safari or Android TAGS (requires rule checking)
- * SVG no load or failure in Opera XHR
- * Reported issues with IE7/8
- */
-
-(function () {
- "use strict";
-
-// constructor
- /**
- * The LoadQueue class is the main API for preloading content. LoadQueue is a load manager, which can preload either
- * a single file, or queue of files.
- *
- * Creating a Queue
- * To use LoadQueue, create a LoadQueue instance. If you want to force tag loading where possible, set the preferXHR
- * argument to false.
- *
- * var queue = new createjs.LoadQueue(true);
- *
- * Listening for Events
- * Add any listeners you want to the queue. Since PreloadJS 0.3.0, the {{#crossLink "EventDispatcher"}}{{/crossLink}}
- * lets you add as many listeners as you want for events. You can subscribe to the following events:
- *
{{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}: fired when a queue completes loading all
- * files
- *
{{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}: fired when the queue encounters an error with
- * any file.
- *
{{#crossLink "AbstractLoader/progress:event"}}{{/crossLink}}: Progress for the entire queue has
- * changed.
- *
{{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}: A single file has completed loading.
- *
{{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}: Progress for a single file has changes. Note
- * that only files loaded with XHR (or possibly by plugins) will fire progress events other than 0 or 100%.
- *
- *
- * queue.on("fileload", handleFileLoad, this);
- * queue.on("complete", handleComplete, this);
- *
- * Adding files and manifests
- * Add files you want to load using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or add multiple files at a
- * time using a list or a manifest definition using {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. Files are
- * appended to the end of the active queue, so you can use these methods as many times as you like, whenever you
- * like.
- *
- * queue.loadFile("filePath/file.jpg");
- * queue.loadFile({id:"image", src:"filePath/file.jpg"});
- * queue.loadManifest(["filePath/file.jpg", {id:"image", src:"filePath/file.jpg"}]);
- *
- * // Use an external manifest
- * queue.loadManifest("path/to/manifest.json");
- * queue.loadManifest({src:"manifest.json", type:"manifest"});
- *
- * If you pass `false` as the `loadNow` parameter, the queue will not kick of the load of the files, but it will not
- * stop if it has already been started. Call the {{#crossLink "AbstractLoader/load"}}{{/crossLink}} method to begin
- * a paused queue. Note that a paused queue will automatically resume when new files are added to it with a
- * `loadNow` argument of `true`.
- *
- * queue.load();
- *
- * File Types
- * The file type of a manifest item is auto-determined by the file extension. The pattern matching in PreloadJS
- * should handle the majority of standard file and url formats, and works with common file extensions. If you have
- * either a non-standard file extension, or are serving the file using a proxy script, then you can pass in a
- * type property with any manifest item.
- *
- * queue.loadFile({src:"path/to/myFile.mp3x", type:createjs.AbstractLoader.SOUND});
- *
- * // Note that PreloadJS will not read a file extension from the query string
- * queue.loadFile({src:"http://server.com/proxy?file=image.jpg", type:createjs.AbstractLoader.IMAGE});
- *
- * Supported types are defined on the {{#crossLink "AbstractLoader"}}{{/crossLink}} class, and include:
- *
- *
{{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}: Raw binary data via XHR
{{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}: A list of files to load in JSON format, see
- * {{#crossLink "AbstractLoader/loadManifest"}}{{/crossLink}}
{{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}: JSON SpriteSheet definitions. This
- * will also load sub-images, and provide a {{#crossLink "SpriteSheet"}}{{/crossLink}} instance.
{{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}}: Text files - XHR only
- *
{{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}: Video objects
- *
{{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}: XML data
- *
- *
- * Note: Loader types used to be defined on LoadQueue, but have been moved to AbstractLoader for better
- * portability of loader classes, which can be used individually now. The properties on LoadQueue still exist, but
- * are deprecated.
- *
- * Handling Results
- * When a file is finished downloading, a {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event is
- * dispatched. In an example above, there is an event listener snippet for fileload. Loaded files are usually a
- * formatted object that can be used immediately, including:
- *
- *
Binary: The binary loaded result
- *
CSS: A <link /> tag
- *
Image: An <img /> tag
- *
JavaScript: A <script /> tag
- *
JSON/JSONP: A formatted JavaScript Object
- *
Manifest: A JavaScript object.
- *
Sound: An <audio /> tag
- *
SpriteSheet: A {{#crossLink "SpriteSheet"}}{{/crossLink}} instance, containing loaded images.
- *
SVG: An <object /> tag
- *
Text: Raw text
- *
Video: A Video DOM node
- *
XML: An XML DOM node
- *
- *
- * function handleFileLoad(event) {
- * var item = event.item; // A reference to the item that was passed in to the LoadQueue
- * var type = item.type;
- *
- * // Add any images to the page body.
- * if (type == createjs.LoadQueue.IMAGE) {
- * document.body.appendChild(event.result);
- * }
- * }
- *
- * At any time after the file has been loaded (usually after the queue has completed), any result can be looked up
- * via its "id" using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}. If no id was provided, then the
- * "src" or file path can be used instead, including the `path` defined by a manifest, but not including
- * a base path defined on the LoadQueue. It is recommended to always pass an id if you want to look up content.
- *
- * var image = queue.getResult("image");
- * document.body.appendChild(image);
- *
- * Raw loaded content can be accessed using the rawResult property of the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}
- * event, or can be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}, passing `true` as the 2nd
- * argument. This is only applicable for content that has been parsed for the browser, specifically: JavaScript,
- * CSS, XML, SVG, and JSON objects, or anything loaded with XHR.
- *
- * var image = queue.getResult("image", true); // load the binary image data loaded with XHR.
- *
- * Plugins
- * LoadQueue has a simple plugin architecture to help process and preload content. For example, to preload audio,
- * make sure to install the SoundJS Sound class, which will help load HTML audio,
- * Flash audio, and WebAudio files. This should be installed before loading any audio files.
- *
- * queue.installPlugin(createjs.Sound);
- *
- *
Known Browser Issues
- *
- *
Browsers without audio support can not load audio files.
- *
Safari on Mac OS X can only play HTML audio if QuickTime is installed
- *
HTML Audio tags will only download until their canPlayThrough event is fired. Browsers other
- * than Chrome will continue to download in the background.
- *
When loading scripts using tags, they are automatically added to the document.
- *
Scripts loaded via XHR may not be properly inspectable with browser tools.
- *
IE6 and IE7 (and some other browsers) may not be able to load XML, Text, or JSON, since they require
- * XHR to work.
- *
Content loaded via tags will not show progress, and will continue to download in the background when
- * canceled, although no events will be dispatched.
- *
- *
- * @class LoadQueue
- * @param {Boolean} [preferXHR=true] Determines whether the preload instance will favor loading with XHR (XML HTTP
- * Requests), or HTML tags. When this is `false`, the queue will use tag loading when possible, and fall back on XHR
- * when necessary.
- * @param {String} [basePath=""] A path that will be prepended on to the source parameter of all items in the queue
- * before they are loaded. Sources beginning with a protocol such as `http://` or a relative path such as `../`
- * will not receive a base path.
- * @param {String|Boolean} [crossOrigin=""] An optional flag to support images loaded from a CORS-enabled server. To
- * use it, set this value to `true`, which will default the crossOrigin property on images to "Anonymous". Any
- * string value will be passed through, but only "" and "Anonymous" are recommended. Note: The crossOrigin
- * parameter is deprecated. Use LoadItem.crossOrigin instead
- *
- * @constructor
- * @extends AbstractLoader
- */
- function LoadQueue (preferXHR, basePath, crossOrigin) {
- this.AbstractLoader_constructor();
-
- /**
- * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}.
- * @property _plugins
- * @type {Array}
- * @private
- * @since 0.6.1
- */
- this._plugins = [];
-
- /**
- * An object hash of callbacks that are fired for each file type before the file is loaded, giving plugins the
- * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}
- * method for more information.
- * @property _typeCallbacks
- * @type {Object}
- * @private
- */
- this._typeCallbacks = {};
-
- /**
- * An object hash of callbacks that are fired for each file extension before the file is loaded, giving plugins the
- * ability to override properties of the load. Please see the {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}}
- * method for more information.
- * @property _extensionCallbacks
- * @type {null}
- * @private
- */
- this._extensionCallbacks = {};
-
- /**
- * The next preload queue to process when this one is complete. If an error is thrown in the current queue, and
- * {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}} is `true`, the next queue will not be processed.
- * @property next
- * @type {LoadQueue}
- * @default null
- */
- this.next = null;
-
- /**
- * Ensure loaded scripts "complete" in the order they are specified. Loaded scripts are added to the document head
- * once they are loaded. Scripts loaded via tags will load one-at-a-time when this property is `true`, whereas
- * scripts loaded using XHR can load in any order, but will "finish" and be added to the document in the order
- * specified.
- *
- * Any items can be set to load in order by setting the {{#crossLink "maintainOrder:property"}}{{/crossLink}}
- * property on the load item, or by ensuring that only one connection can be open at a time using
- * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Note that when the `maintainScriptOrder` property
- * is set to `true`, scripts items are automatically set to `maintainOrder=true`, and changing the
- * `maintainScriptOrder` to `false` during a load will not change items already in a queue.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.setMaxConnections(3); // Set a higher number to load multiple items at once
- * queue.maintainScriptOrder = true; // Ensure scripts are loaded in order
- * queue.loadManifest([
- * "script1.js",
- * "script2.js",
- * "image.png", // Load any time
- * {src: "image2.png", maintainOrder: true} // Will wait for script2.js
- * "image3.png",
- * "script3.js" // Will wait for image2.png before loading (or completing when loading with XHR)
- * ]);
- *
- * @property maintainScriptOrder
- * @type {Boolean}
- * @default true
- */
- this.maintainScriptOrder = true;
-
- /**
- * Determines if the LoadQueue will stop processing the current queue when an error is encountered.
- * @property stopOnError
- * @type {Boolean}
- * @default false
- */
- this.stopOnError = false;
-
- /**
- * The number of maximum open connections that a loadQueue tries to maintain. Please see
- * {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} for more information.
- * @property _maxConnections
- * @type {Number}
- * @default 1
- * @private
- */
- this._maxConnections = 1;
-
- /**
- * An internal list of all the default Loaders that are included with PreloadJS. Before an item is loaded, the
- * available loader list is iterated, in the order they are included, and as soon as a loader indicates it can
- * handle the content, it will be selected. The default loader, ({{#crossLink "TextLoader"}}{{/crossLink}} is
- * last in the list, so it will be used if no other match is found. Typically, loaders will match based on the
- * {{#crossLink "LoadItem/type"}}{{/crossLink}}, which is automatically determined using the file extension of
- * the {{#crossLink "LoadItem/src:property"}}{{/crossLink}}.
- *
- * Loaders can be removed from PreloadJS by simply not including them.
- *
- * Custom loaders installed using {{#crossLink "registerLoader"}}{{/crossLink}} will be prepended to this list
- * so that they are checked first.
- * @property _availableLoaders
- * @type {Array}
- * @private
- * @since 0.6.0
- */
- this._availableLoaders = [
- createjs.ImageLoader,
- createjs.JavaScriptLoader,
- createjs.CSSLoader,
- createjs.JSONLoader,
- createjs.JSONPLoader,
- createjs.SoundLoader,
- createjs.ManifestLoader,
- createjs.SpriteSheetLoader,
- createjs.XMLLoader,
- createjs.SVGLoader,
- createjs.BinaryLoader,
- createjs.VideoLoader,
- createjs.TextLoader
- ];
-
- /**
- * The number of built in loaders, so they can't be removed by {{#crossLink "unregisterLoader"}}{{/crossLink}.
- * @property _defaultLoaderLength
- * @type {Number}
- * @private
- * @since 0.6.0
- */
- this._defaultLoaderLength = this._availableLoaders.length;
-
- this.init(preferXHR, basePath, crossOrigin);
- }
-
- var p = createjs.extend(LoadQueue, createjs.AbstractLoader);
- var s = LoadQueue;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
- /**
- * An internal initialization method, which is used for initial set up, but also to reset the LoadQueue.
- * @method init
- * @param preferXHR
- * @param basePath
- * @param crossOrigin
- * @private
- */
- p.init = function (preferXHR, basePath, crossOrigin) {
-
- // public properties
- /**
- * @property useXHR
- * @type {Boolean}
- * @readonly
- * @default true
- * @deprecated Use preferXHR instead.
- */
- this.useXHR = true;
-
- /**
- * Try and use XMLHttpRequest (XHR) when possible. Note that LoadQueue will default to tag loading or XHR
- * loading depending on the requirements for a media type. For example, HTML audio can not be loaded with XHR,
- * and plain text can not be loaded with tags, so it will default the the correct type instead of using the
- * user-defined type.
- * @type {Boolean}
- * @default true
- * @since 0.6.0
- */
- this.preferXHR = true; //TODO: Get/Set
- this._preferXHR = true;
- this.setPreferXHR(preferXHR);
-
- // protected properties
- /**
- * Whether the queue is currently paused or not.
- * @property _paused
- * @type {boolean}
- * @private
- */
- this._paused = false;
-
- /**
- * A path that will be prepended on to the item's {{#crossLink "LoadItem/src:property"}}{{/crossLink}}. The
- * `_basePath` property will only be used if an item's source is relative, and does not include a protocol such
- * as `http://`, or a relative path such as `../`.
- * @property _basePath
- * @type {String}
- * @private
- * @since 0.3.1
- */
- this._basePath = basePath;
-
- /**
- * An optional flag to set on images that are loaded using PreloadJS, which enables CORS support. Images loaded
- * cross-domain by servers that support CORS require the crossOrigin flag to be loaded and interacted with by
- * a canvas. When loading locally, or with a server with no CORS support, this flag can cause other security issues,
- * so it is recommended to only set it if you are sure the server supports it. Currently, supported values are ""
- * and "Anonymous".
- * @property _crossOrigin
- * @type {String}
- * @default ""
- * @private
- * @since 0.4.1
- */
- this._crossOrigin = crossOrigin;
-
- /**
- * Determines if the loadStart event was dispatched already. This event is only fired one time, when the first
- * file is requested.
- * @property _loadStartWasDispatched
- * @type {Boolean}
- * @default false
- * @private
- */
- this._loadStartWasDispatched = false;
-
- /**
- * Determines if there is currently a script loading. This helps ensure that only a single script loads at once when
- * using a script tag to do preloading.
- * @property _currentlyLoadingScript
- * @type {Boolean}
- * @private
- */
- this._currentlyLoadingScript = null;
-
- /**
- * An array containing the currently downloading files.
- * @property _currentLoads
- * @type {Array}
- * @private
- */
- this._currentLoads = [];
-
- /**
- * An array containing the queued items that have not yet started downloading.
- * @property _loadQueue
- * @type {Array}
- * @private
- */
- this._loadQueue = [];
-
- /**
- * An array containing downloads that have not completed, so that the LoadQueue can be properly reset.
- * @property _loadQueueBackup
- * @type {Array}
- * @private
- */
- this._loadQueueBackup = [];
-
- /**
- * An object hash of items that have finished downloading, indexed by the {{#crossLink "LoadItem"}}{{/crossLink}}
- * id.
- * @property _loadItemsById
- * @type {Object}
- * @private
- */
- this._loadItemsById = {};
-
- /**
- * An object hash of items that have finished downloading, indexed by {{#crossLink "LoadItem"}}{{/crossLink}}
- * source.
- * @property _loadItemsBySrc
- * @type {Object}
- * @private
- */
- this._loadItemsBySrc = {};
-
- /**
- * An object hash of loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}.
- * @property _loadedResults
- * @type {Object}
- * @private
- */
- this._loadedResults = {};
-
- /**
- * An object hash of un-parsed loaded items, indexed by the ID of the {{#crossLink "LoadItem"}}{{/crossLink}}.
- * @property _loadedRawResults
- * @type {Object}
- * @private
- */
- this._loadedRawResults = {};
-
- /**
- * The number of items that have been requested. This helps manage an overall progress without knowing how large
- * the files are before they are downloaded. This does not include items inside of loaders such as the
- * {{#crossLink "ManifestLoader"}}{{/crossLink}}.
- * @property _numItems
- * @type {Number}
- * @default 0
- * @private
- */
- this._numItems = 0;
-
- /**
- * The number of items that have completed loaded. This helps manage an overall progress without knowing how large
- * the files are before they are downloaded.
- * @property _numItemsLoaded
- * @type {Number}
- * @default 0
- * @private
- */
- this._numItemsLoaded = 0;
-
- /**
- * A list of scripts in the order they were requested. This helps ensure that scripts are "completed" in the right
- * order.
- * @property _scriptOrder
- * @type {Array}
- * @private
- */
- this._scriptOrder = [];
-
- /**
- * A list of scripts that have been loaded. Items are added to this list as null when they are
- * requested, contain the loaded item if it has completed, but not been dispatched to the user, and true
- * once they are complete and have been dispatched.
- * @property _loadedScripts
- * @type {Array}
- * @private
- */
- this._loadedScripts = [];
-
- /**
- * The last progress amount. This is used to suppress duplicate progress events.
- * @property _lastProgress
- * @type {Number}
- * @private
- * @since 0.6.0
- */
- this._lastProgress = NaN;
-
- };
-
-// static properties
- /**
- * The time in milliseconds to assume a load has failed. An {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}
- * event is dispatched if the timeout is reached before any data is received.
- * @property loadTimeout
- * @type {Number}
- * @default 8000
- * @static
- * @since 0.4.1
- * @deprecated In favour of {{#crossLink "LoadItem/LOAD_TIMEOUT_DEFAULT:property}}{{/crossLink}} property.
- */
- s.loadTimeout = 8000;
-
- /**
- * The time in milliseconds to assume a load has failed.
- * @property LOAD_TIMEOUT
- * @type {Number}
- * @default 0
- * @deprecated in favor of the {{#crossLink "LoadQueue/loadTimeout:property"}}{{/crossLink}} property.
- */
- s.LOAD_TIMEOUT = 0;
-
-// Preload Types
- /**
- * @property BINARY
- * @type {String}
- * @default binary
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}} instead.
- */
- s.BINARY = createjs.AbstractLoader.BINARY;
-
- /**
- * @property CSS
- * @type {String}
- * @default css
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead.
- */
- s.CSS = createjs.AbstractLoader.CSS;
-
- /**
- * @property IMAGE
- * @type {String}
- * @default image
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}} instead.
- */
- s.IMAGE = createjs.AbstractLoader.IMAGE;
-
- /**
- * @property JAVASCRIPT
- * @type {String}
- * @default javascript
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead.
- */
- s.JAVASCRIPT = createjs.AbstractLoader.JAVASCRIPT;
-
- /**
- * @property JSON
- * @type {String}
- * @default json
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}} instead.
- */
- s.JSON = createjs.AbstractLoader.JSON;
-
- /**
- * @property JSONP
- * @type {String}
- * @default jsonp
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}} instead.
- */
- s.JSONP = createjs.AbstractLoader.JSONP;
-
- /**
- * @property MANIFEST
- * @type {String}
- * @default manifest
- * @static
- * @since 0.4.1
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}} instead.
- */
- s.MANIFEST = createjs.AbstractLoader.MANIFEST;
-
- /**
- * @property SOUND
- * @type {String}
- * @default sound
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead.
- */
- s.SOUND = createjs.AbstractLoader.SOUND;
-
- /**
- * @property VIDEO
- * @type {String}
- * @default video
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}} instead.
- */
- s.VIDEO = createjs.AbstractLoader.VIDEO;
-
- /**
- * @property SVG
- * @type {String}
- * @default svg
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}} instead.
- */
- s.SVG = createjs.AbstractLoader.SVG;
-
- /**
- * @property TEXT
- * @type {String}
- * @default text
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}} instead.
- */
- s.TEXT = createjs.AbstractLoader.TEXT;
-
- /**
- * @property XML
- * @type {String}
- * @default xml
- * @static
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}} instead.
- */
- s.XML = createjs.AbstractLoader.XML;
-
- /**
- * @property POST
- * @type {string}
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} instead.
- */
- s.POST = createjs.AbstractLoader.POST;
-
- /**
- * @property GET
- * @type {string}
- * @deprecated Use the AbstractLoader {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} instead.
- */
- s.GET = createjs.AbstractLoader.GET;
-
-// events
- /**
- * This event is fired when an individual file has loaded, and been processed.
- * @event fileload
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the
- * object will contain that value as a `src` property.
- * @param {Object} result The HTML tag or parsed result of the loaded item.
- * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted
- * to a usable object.
- * @since 0.3.0
- */
-
- /**
- * This {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when an an individual file's progress changes.
- * @event fileprogress
- * @since 0.3.0
- */
-
- /**
- * This event is fired when an individual file starts to load.
- * @event filestart
- * @param {Object} The object that dispatched the event.
- * @param {String} type The event type.
- * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the
- * object will contain that value as a property.
- */
-
- /**
- * Although it extends {{#crossLink "AbstractLoader"}}{{/crossLink}}, the `initialize` event is never fired from
- * a LoadQueue instance.
- * @event initialize
- * @private
- */
-
-// public methods
- /**
- * Register a custom loaders class. New loaders are given precedence over loaders added earlier and default loaders.
- * It is recommended that loaders extend {{#crossLink "AbstractLoader"}}{{/crossLink}}. Loaders can only be added
- * once, and will be prepended to the list of available loaders.
- * @method registerLoader
- * @param {Function|AbstractLoader} loader The AbstractLoader class to add.
- * @since 0.6.0
- */
- p.registerLoader = function (loader) {
- if (!loader || !loader.canLoadItem) {
- throw new Error("loader is of an incorrect type.");
- } else if (this._availableLoaders.indexOf(loader) != -1) {
- throw new Error("loader already exists."); //LM: Maybe just silently fail here
- }
-
- this._availableLoaders.unshift(loader);
- };
-
- /**
- * Remove a custom loader added using {{#crossLink "registerLoader"}}{{/crossLink}}. Only custom loaders can be
- * unregistered, the default loaders will always be available.
- * @method unregisterLoader
- * @param {Function|AbstractLoader} loader The AbstractLoader class to remove
- */
- p.unregisterLoader = function (loader) {
- var idx = this._availableLoaders.indexOf(loader);
- if (idx != -1 && idx < this._defaultLoaderLength - 1) {
- this._availableLoaders.splice(idx, 1);
- }
- };
-
- /**
- * @method setUseXHR
- * @param {Boolean} value The new useXHR value to set.
- * @return {Boolean} The new useXHR value. If XHR is not supported by the browser, this will return false, even if
- * the provided value argument was true.
- * @since 0.3.0
- * @deprecated use the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property, or the
- * {{#crossLink "LoadQueue/setUseXHR"}}{{/crossLink}} method instead.
- */
- p.setUseXHR = function (value) {
- return this.setPreferXHR(value);
- };
-
- /**
- * Change the {{#crossLink "preferXHR:property"}}{{/crossLink}} value. Note that if this is set to `true`, it may
- * fail, or be ignored depending on the browser's capabilities and the load type.
- * @method setPreferXHR
- * @param {Boolean} value
- * @returns {Boolean} The value of {{#crossLink "preferXHR"}}{{/crossLink}} that was successfully set.
- * @since 0.6.0
- */
- p.setPreferXHR = function (value) {
- // Determine if we can use XHR. XHR defaults to TRUE, but the browser may not support it.
- //TODO: Should we be checking for the other XHR types? Might have to do a try/catch on the different types similar to createXHR.
- this.preferXHR = (value != false && window.XMLHttpRequest != null);
- return this.preferXHR;
- };
-
- /**
- * Stops all queued and loading items, and clears the queue. This also removes all internal references to loaded
- * content, and allows the queue to be used again.
- * @method removeAll
- * @since 0.3.0
- */
- p.removeAll = function () {
- this.remove();
- };
-
- /**
- * Stops an item from being loaded, and removes it from the queue. If nothing is passed, all items are removed.
- * This also removes internal references to loaded item(s).
- *
- *
Example
- *
- * queue.loadManifest([
- * {src:"test.png", id:"png"},
- * {src:"test.jpg", id:"jpg"},
- * {src:"test.mp3", id:"mp3"}
- * ]);
- * queue.remove("png"); // Single item by ID
- * queue.remove("png", "test.jpg"); // Items as arguments. Mixed id and src.
- * queue.remove(["test.png", "jpg"]); // Items in an Array. Mixed id and src.
- *
- * @method remove
- * @param {String | Array} idsOrUrls* The id or ids to remove from this queue. You can pass an item, an array of
- * items, or multiple items as arguments.
- * @since 0.3.0
- */
- p.remove = function (idsOrUrls) {
- var args = null;
-
- if (idsOrUrls && !Array.isArray(idsOrUrls)) {
- args = [idsOrUrls];
- } else if (idsOrUrls) {
- args = idsOrUrls;
- } else if (arguments.length > 0) {
- return;
- }
-
- var itemsWereRemoved = false;
-
- // Destroy everything
- if (!args) {
- this.close();
- for (var n in this._loadItemsById) {
- this._disposeItem(this._loadItemsById[n]);
- }
- this.init(this.preferXHR, this._basePath);
-
- // Remove specific items
- } else {
- while (args.length) {
- var item = args.pop();
- var r = this.getResult(item);
-
- //Remove from the main load Queue
- for (i = this._loadQueue.length - 1; i >= 0; i--) {
- loadItem = this._loadQueue[i].getItem();
- if (loadItem.id == item || loadItem.src == item) {
- this._loadQueue.splice(i, 1)[0].cancel();
- break;
- }
- }
-
- //Remove from the backup queue
- for (i = this._loadQueueBackup.length - 1; i >= 0; i--) {
- loadItem = this._loadQueueBackup[i].getItem();
- if (loadItem.id == item || loadItem.src == item) {
- this._loadQueueBackup.splice(i, 1)[0].cancel();
- break;
- }
- }
-
- if (r) {
- this._disposeItem(this.getItem(item));
- } else {
- for (var i = this._currentLoads.length - 1; i >= 0; i--) {
- var loadItem = this._currentLoads[i].getItem();
- if (loadItem.id == item || loadItem.src == item) {
- this._currentLoads.splice(i, 1)[0].cancel();
- itemsWereRemoved = true;
- break;
- }
- }
- }
- }
-
- // If this was called during a load, try to load the next item.
- if (itemsWereRemoved) {
- this._loadNext();
- }
- }
- };
-
- /**
- * Stops all open loads, destroys any loaded items, and resets the queue, so all items can
- * be reloaded again by calling {{#crossLink "AbstractLoader/load"}}{{/crossLink}}. Items are not removed from the
- * queue. To remove items use the {{#crossLink "LoadQueue/remove"}}{{/crossLink}} or
- * {{#crossLink "LoadQueue/removeAll"}}{{/crossLink}} method.
- * @method reset
- * @since 0.3.0
- */
- p.reset = function () {
- this.close();
- for (var n in this._loadItemsById) {
- this._disposeItem(this._loadItemsById[n]);
- }
-
- //Reset the queue to its start state
- var a = [];
- for (var i = 0, l = this._loadQueueBackup.length; i < l; i++) {
- a.push(this._loadQueueBackup[i].getItem());
- }
-
- this.loadManifest(a, false);
- };
-
- /**
- * Register a plugin. Plugins can map to load types (sound, image, etc), or specific extensions (png, mp3, etc).
- * Currently, only one plugin can exist per type/extension.
- *
- * When a plugin is installed, a getPreloadHandlers() method will be called on it. For more information
- * on this method, check out the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method in the
- * {{#crossLink "SamplePlugin"}}{{/crossLink}} class.
- *
- * Before a file is loaded, a matching plugin has an opportunity to modify the load. If a `callback` is returned
- * from the {{#crossLink "SamplePlugin/getPreloadHandlers"}}{{/crossLink}} method, it will be invoked first, and its
- * result may cancel or modify the item. The callback method can also return a `completeHandler` to be fired when
- * the file is loaded, or a `tag` object, which will manage the actual download. For more information on these
- * methods, check out the {{#crossLink "SamplePlugin/preloadHandler"}}{{/crossLink}} and {{#crossLink "SamplePlugin/fileLoadHandler"}}{{/crossLink}}
- * methods on the {{#crossLink "SamplePlugin"}}{{/crossLink}}.
- *
- * @method installPlugin
- * @param {Function} plugin The plugin class to install.
- */
- p.installPlugin = function (plugin) {
- if (plugin == null) {
- return;
- }
-
- if (plugin.getPreloadHandlers != null) {
- this._plugins.push(plugin);
- var map = plugin.getPreloadHandlers();
- map.scope = plugin;
-
- if (map.types != null) {
- for (var i = 0, l = map.types.length; i < l; i++) {
- this._typeCallbacks[map.types[i]] = map;
- }
- }
-
- if (map.extensions != null) {
- for (i = 0, l = map.extensions.length; i < l; i++) {
- this._extensionCallbacks[map.extensions[i]] = map;
- }
- }
- }
- };
-
- /**
- * Set the maximum number of concurrent connections. Note that browsers and servers may have a built-in maximum
- * number of open connections, so any additional connections may remain in a pending state until the browser
- * opens the connection. When loading scripts using tags, and when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}}
- * is `true`, only one script is loaded at a time due to browser limitations.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.setMaxConnections(10); // Allow 10 concurrent loads
- *
- * @method setMaxConnections
- * @param {Number} value The number of concurrent loads to allow. By default, only a single connection per LoadQueue
- * is open at any time.
- */
- p.setMaxConnections = function (value) {
- this._maxConnections = value;
- if (!this._paused && this._loadQueue.length > 0) {
- this._loadNext();
- }
- };
-
- /**
- * Load a single file. To add multiple files at once, use the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
- * method.
- *
- * Files are always appended to the current queue, so this method can be used multiple times to add files.
- * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method.
- * @method loadFile
- * @param {LoadItem|Object|String} file The file object or path to load. A file can be either
- *
- *
A {{#crossLink "LoadItem"}}{{/crossLink}} instance
- *
An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
- *
OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}}
- * in the background.
- *
- * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default
- * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}}, and the value is
- * `true`, the queue will resume automatically.
- * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the
- * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}},
- * its files will NOT use the basePath parameter. The basePath parameter is deprecated.
- * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue
- * constructor, or a `path` property in a manifest definition.
- */
- p.loadFile = function (file, loadNow, basePath) {
- if (file == null) {
- var event = new createjs.ErrorEvent("PRELOAD_NO_FILE");
- this._sendError(event);
- return;
- }
- this._addItem(file, null, basePath);
-
- if (loadNow !== false) {
- this.setPaused(false);
- } else {
- this.setPaused(true);
- }
- };
-
- /**
- * Load an array of files. To load a single file, use the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} method.
- * The files in the manifest are requested in the same order, but may complete in a different order if the max
- * connections are set above 1 using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}. Scripts will load
- * in the right order as long as {{#crossLink "LoadQueue/maintainScriptOrder"}}{{/crossLink}} is true (which is
- * default).
- *
- * Files are always appended to the current queue, so this method can be used multiple times to add files.
- * To clear the queue first, use the {{#crossLink "AbstractLoader/close"}}{{/crossLink}} method.
- * @method loadManifest
- * @param {Array|String|Object} manifest An list of files to load. The loadManifest call supports four types of
- * manifests:
- *
- *
A string path, which points to a manifest file, which is a JSON file that contains a "manifest" property,
- * which defines the list of files to load, and can optionally contain a "path" property, which will be
- * prepended to each file in the list.
- *
An object which defines a "src", which is a JSON or JSONP file. A "callback" can be defined for JSONP
- * file. The JSON/JSONP file should contain a "manifest" property, which defines the list of files to load,
- * and can optionally contain a "path" property, which will be prepended to each file in the list.
- *
An object which contains a "manifest" property, which defines the list of files to load, and can
- * optionally contain a "path" property, which will be prepended to each file in the list.
- *
An Array of files to load.
- *
- *
- * Each "file" in a manifest can be either:
- *
- *
A {{#crossLink "LoadItem"}}{{/crossLink}} instance
- *
An object containing properties defined by {{#crossLink "LoadItem"}}{{/crossLink}}
- *
OR A string path to a resource. Note that this kind of load item will be converted to a {{#crossLink "LoadItem"}}{{/crossLink}}
- * in the background.
- *
- *
- * @param {Boolean} [loadNow=true] Kick off an immediate load (true) or wait for a load call (false). The default
- * value is true. If the queue is paused using {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} and this value is
- * `true`, the queue will resume automatically.
- * @param {String} [basePath] A base path that will be prepended to each file. The basePath argument overrides the
- * path specified in the constructor. Note that if you load a manifest using a file of type {{#crossLink "LoadQueue/MANIFEST:property"}}{{/crossLink}},
- * its files will NOT use the basePath parameter. The basePath parameter is deprecated.
- * This parameter will be removed in a future version. Please either use the `basePath` parameter in the LoadQueue
- * constructor, or a `path` property in a manifest definition.
- */
- p.loadManifest = function (manifest, loadNow, basePath) {
- var fileList = null;
- var path = null;
-
- // Array-based list of items
- if (Array.isArray(manifest)) {
- if (manifest.length == 0) {
- var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_EMPTY");
- this._sendError(event);
- return;
- }
- fileList = manifest;
-
- // String-based. Only file manifests can be specified this way. Any other types will cause an error when loaded.
- } else if (typeof(manifest) === "string") {
- fileList = [
- {
- src: manifest,
- type: s.MANIFEST
- }
- ];
-
- } else if (typeof(manifest) == "object") {
-
- // An object that defines a manifest path
- if (manifest.src !== undefined) {
- if (manifest.type == null) {
- manifest.type = s.MANIFEST;
- } else if (manifest.type != s.MANIFEST) {
- var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_TYPE");
- this._sendError(event);
- }
- fileList = [manifest];
-
- // An object that defines a manifest
- } else if (manifest.manifest !== undefined) {
- fileList = manifest.manifest;
- path = manifest.path;
- }
-
- // Unsupported. This will throw an error.
- } else {
- var event = new createjs.ErrorEvent("PRELOAD_MANIFEST_NULL");
- this._sendError(event);
- return;
- }
-
- for (var i = 0, l = fileList.length; i < l; i++) {
- this._addItem(fileList[i], path, basePath);
- }
-
- if (loadNow !== false) {
- this.setPaused(false);
- } else {
- this.setPaused(true);
- }
-
- };
-
- /**
- * Start a LoadQueue that was created, but not automatically started.
- * @method load
- */
- p.load = function () {
- this.setPaused(false);
- };
-
- /**
- * Look up a {{#crossLink "LoadItem"}}{{/crossLink}} using either the "id" or "src" that was specified when loading it. Note that if no "id" was
- * supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The
- * `basePath` will not be part of the ID.
- * @method getItem
- * @param {String} value The id or src of the load item.
- * @return {Object} The load item that was initially requested using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}}
- * event as the `item` parameter.
- */
- p.getItem = function (value) {
- return this._loadItemsById[value] || this._loadItemsBySrc[value];
- };
-
- /**
- * Look up a loaded result using either the "id" or "src" that was specified when loading it. Note that if no "id"
- * was supplied with the load item, the ID will be the "src", including a `path` property defined by a manifest. The
- * `basePath` will not be part of the ID.
- * @method getResult
- * @param {String} value The id or src of the load item.
- * @param {Boolean} [rawResult=false] Return a raw result instead of a formatted result. This applies to content
- * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be
- * returned instead.
- * @return {Object} A result object containing the content that was loaded, such as:
- *
- *
An image tag (<image />) for images
- *
A script tag for JavaScript (<script />). Note that scripts are automatically added to the HTML
- * DOM.
- *
A style tag for CSS (<style /> or <link >)
- *
Raw text for TEXT
- *
A formatted JavaScript object defined by JSON
- *
An XML document
- *
A binary arraybuffer loaded by XHR
- *
An audio tag (<audio >) for HTML audio. Note that it is recommended to use SoundJS APIs to play
- * loaded audio. Specifically, audio loaded by Flash and WebAudio will return a loader object using this method
- * which can not be used to play audio back.
- *
- * This object is also returned via the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event as the 'item`
- * parameter. Note that if a raw result is requested, but not found, the result will be returned instead.
- */
- p.getResult = function (value, rawResult) {
- var item = this._loadItemsById[value] || this._loadItemsBySrc[value];
- if (item == null) {
- return null;
- }
- var id = item.id;
- if (rawResult && this._loadedRawResults[id]) {
- return this._loadedRawResults[id];
- }
- return this._loadedResults[id];
- };
-
- /**
- * Generate an list of items loaded by this queue.
- * @method getItems
- * @param {Boolean} loaded Determines if only items that have been loaded should be returned. If false, in-progress
- * and failed load items will also be included.
- * @returns {Array} A list of objects that have been loaded. Each item includes the {{#crossLink "LoadItem"}}{{/crossLink}},
- * result, and rawResult.
- * @since 0.6.0
- */
- p.getItems = function (loaded) {
- var arr = [];
- for (var n in this._loadItemsById) {
- var item = this._loadItemsById[n];
- var result = this.getResult(n);
- if (loaded === true && result == null) {
- continue;
- }
- arr.push({
- item: item,
- result: result,
- rawResult: this.getResult(n, true)
- });
- }
- return arr;
- };
-
- /**
- * Pause or resume the current load. Active loads will not be cancelled, but the next items in the queue will not
- * be processed when active loads complete. LoadQueues are not paused by default.
- *
- * Note that if new items are added to the queue using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or
- * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}, a paused queue will be resumed, unless the `loadNow`
- * argument is `false`.
- * @method setPaused
- * @param {Boolean} value Whether the queue should be paused or not.
- */
- p.setPaused = function (value) {
- this._paused = value;
- if (!this._paused) {
- this._loadNext();
- }
- };
-
- /**
- * Close the active queue. Closing a queue completely empties the queue, and prevents any remaining items from
- * starting to download. Note that currently any active loads will remain open, and events may be processed.
- *
- * To stop and restart a queue, use the {{#crossLink "LoadQueue/setPaused"}}{{/crossLink}} method instead.
- * @method close
- */
- p.close = function () {
- while (this._currentLoads.length) {
- this._currentLoads.pop().cancel();
- }
- this._scriptOrder.length = 0;
- this._loadedScripts.length = 0;
- this.loadStartWasDispatched = false;
- this._itemCount = 0;
- this._lastProgress = NaN;
- };
-
-// protected methods
- /**
- * Add an item to the queue. Items are formatted into a usable object containing all the properties necessary to
- * load the content. The load queue is populated with the loader instance that handles preloading, and not the load
- * item that was passed in by the user. To look up the load item by id or src, use the {{#crossLink "LoadQueue.getItem"}}{{/crossLink}}
- * method.
- * @method _addItem
- * @param {String|Object} value The item to add to the queue.
- * @param {String} [path] An optional path prepended to the `src`. The path will only be prepended if the src is
- * relative, and does not start with a protocol such as `http://`, or a path like `../`. If the LoadQueue was
- * provided a {{#crossLink "_basePath"}}{{/crossLink}}, then it will optionally be prepended after.
- * @param {String} [basePath] DeprecatedAn optional basePath passed into a {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} call. This parameter will be removed in a future tagged
- * version.
- * @private
- */
- p._addItem = function (value, path, basePath) {
- var item = this._createLoadItem(value, path, basePath); // basePath and manifest path are added to the src.
- if (item == null) {
- return;
- } // Sometimes plugins or types should be skipped.
- var loader = this._createLoader(item);
- if (loader != null) {
- if ("plugins" in loader) {
- loader.plugins = this._plugins;
- }
- item._loader = loader;
- this._loadQueue.push(loader);
- this._loadQueueBackup.push(loader);
-
- this._numItems++;
- this._updateProgress();
-
- // Only worry about script order when using XHR to load scripts. Tags are only loading one at a time.
- if ((this.maintainScriptOrder
- && item.type == createjs.LoadQueue.JAVASCRIPT
- //&& loader instanceof createjs.XHRLoader //NOTE: Have to track all JS files this way
- )
- || item.maintainOrder === true) {
- this._scriptOrder.push(item);
- this._loadedScripts.push(null);
- }
- }
- };
-
- /**
- * Create a refined {{#crossLink "LoadItem"}}{{/crossLink}}, which contains all the required properties. The type of
- * item is determined by browser support, requirements based on the file type, and developer settings. For example,
- * XHR is only used for file types that support it in new browsers.
- *
- * Before the item is returned, any plugins registered to handle the type or extension will be fired, which may
- * alter the load item.
- * @method _createLoadItem
- * @param {String | Object | HTMLAudioElement | HTMLImageElement} value The item that needs to be preloaded.
- * @param {String} [path] A path to prepend to the item's source. Sources beginning with http:// or similar will
- * not receive a path. Since PreloadJS 0.4.1, the src will be modified to include the `path` and {{#crossLink "LoadQueue/_basePath:property"}}{{/crossLink}}
- * when it is added.
- * @param {String} [basePath] Deprectated A base path to prepend to the items source in addition to
- * the path argument.
- * @return {Object} The loader instance that will be used.
- * @private
- */
- p._createLoadItem = function (value, path, basePath) {
- var item = createjs.LoadItem.create(value);
- if (item == null) {
- return null;
- }
-
- var bp = ""; // Store the generated basePath
- var useBasePath = basePath || this._basePath;
-
- if (item.src instanceof Object) {
- if (!item.type) {
- return null;
- } // the the src is an object, type is required to pass off to plugin
- if (path) {
- bp = path;
- var pathMatch = createjs.RequestUtils.parseURI(path);
- // Also append basePath
- if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) {
- bp = useBasePath + bp;
- }
- } else if (useBasePath != null) {
- bp = useBasePath;
- }
- } else {
- // Determine Extension, etc.
- var match = createjs.RequestUtils.parseURI(item.src);
- if (match.extension) {
- item.ext = match.extension;
- }
- if (item.type == null) {
- item.type = createjs.RequestUtils.getTypeByExtension(item.ext);
- }
-
- // Inject path & basePath
- var autoId = item.src;
- if (!match.absolute && !match.relative) {
- if (path) {
- bp = path;
- var pathMatch = createjs.RequestUtils.parseURI(path);
- autoId = path + autoId;
- // Also append basePath
- if (useBasePath != null && !pathMatch.absolute && !pathMatch.relative) {
- bp = useBasePath + bp;
- }
- } else if (useBasePath != null) {
- bp = useBasePath;
- }
- }
- item.src = bp + item.src;
- }
- item.path = bp;
-
- // If there's no id, set one now.
- if (item.id === undefined || item.id === null || item.id === "") {
- item.id = autoId;
- }
-
- // Give plugins a chance to modify the loadItem:
- var customHandler = this._typeCallbacks[item.type] || this._extensionCallbacks[item.ext];
- if (customHandler) {
- // Plugins are now passed both the full source, as well as a combined path+basePath (appropriately)
- var result = customHandler.callback.call(customHandler.scope, item, this);
-
- // The plugin will handle the load, or has canceled it. Ignore it.
- if (result === false) {
- return null;
-
- // Load as normal:
- } else if (result === true) {
- // Do Nothing
-
- // Result is a loader class:
- } else if (result != null) {
- item._loader = result;
- }
-
- // Update the extension in case the type changed:
- match = createjs.RequestUtils.parseURI(item.src);
- if (match.extension != null) {
- item.ext = match.extension;
- }
- }
-
- // Store the item for lookup. This also helps clean-up later.
- this._loadItemsById[item.id] = item;
- this._loadItemsBySrc[item.src] = item;
-
- if (item.crossOrigin == null) {
- item.crossOrigin = this._crossOrigin;
- }
-
- return item;
- };
-
- /**
- * Create a loader for a load item.
- * @method _createLoader
- * @param {Object} item A formatted load item that can be used to generate a loader.
- * @return {AbstractLoader} A loader that can be used to load content.
- * @private
- */
- p._createLoader = function (item) {
- if (item._loader != null) { // A plugin already specified a loader
- return item._loader;
- }
-
- // Initially, try and use the provided/supported XHR mode:
- var preferXHR = this.preferXHR;
-
- for (var i = 0; i < this._availableLoaders.length; i++) {
- var loader = this._availableLoaders[i];
- if (loader && loader.canLoadItem(item)) {
- return new loader(item, preferXHR);
- }
- }
-
- // TODO: Log error (requires createjs.log)
- return null;
- };
-
- /**
- * Load the next item in the queue. If the queue is empty (all items have been loaded), then the complete event
- * is processed. The queue will "fill up" any empty slots, up to the max connection specified using
- * {{#crossLink "LoadQueue.setMaxConnections"}}{{/crossLink}} method. The only exception is scripts that are loaded
- * using tags, which have to be loaded one at a time to maintain load order.
- * @method _loadNext
- * @private
- */
- p._loadNext = function () {
- if (this._paused) {
- return;
- }
-
- // Only dispatch loadstart event when the first file is loaded.
- if (!this._loadStartWasDispatched) {
- this._sendLoadStart();
- this._loadStartWasDispatched = true;
- }
-
- // The queue has completed.
- if (this._numItems == this._numItemsLoaded) {
- this.loaded = true;
- this._sendComplete();
-
- // Load the next queue, if it has been defined.
- if (this.next && this.next.load) {
- this.next.load();
- }
- } else {
- this.loaded = false;
- }
-
- // Must iterate forwards to load in the right order.
- for (var i = 0; i < this._loadQueue.length; i++) {
- if (this._currentLoads.length >= this._maxConnections) {
- break;
- }
- var loader = this._loadQueue[i];
-
- // Determine if we should be only loading one tag-script at a time:
- // Note: maintainOrder items don't do anything here because we can hold onto their loaded value
- if (!this._canStartLoad(loader)) {
- continue;
- }
- this._loadQueue.splice(i, 1);
- i--;
- this._loadItem(loader);
- }
- };
-
- /**
- * Begin loading an item. Event listeners are not added to the loaders until the load starts.
- * @method _loadItem
- * @param {AbstractLoader} loader The loader instance to start. Currently, this will be an XHRLoader or TagLoader.
- * @private
- */
- p._loadItem = function (loader) {
- loader.on("fileload", this._handleFileLoad, this);
- loader.on("progress", this._handleProgress, this);
- loader.on("complete", this._handleFileComplete, this);
- loader.on("error", this._handleError, this);
- loader.on("fileerror", this._handleFileError, this);
- this._currentLoads.push(loader);
- this._sendFileStart(loader.getItem());
- loader.load();
- };
-
- /**
- * The callback that is fired when a loader loads a file. This enables loaders like {{#crossLink "ManifestLoader"}}{{/crossLink}}
- * to maintain internal queues, but for this queue to dispatch the {{#crossLink "fileload:event"}}{{/crossLink}}
- * events.
- * @param {Event} event The {{#crossLink "AbstractLoader/fileload:event"}}{{/crossLink}} event from the loader.
- * @private
- * @since 0.6.0
- */
- p._handleFileLoad = function (event) {
- event.target = null;
- this.dispatchEvent(event);
- };
-
- /**
- * The callback that is fired when a loader encounters an error from an internal file load operation. This enables
- * loaders like M
- * @param event
- * @private
- */
- p._handleFileError = function (event) {
- var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, event.item);
- this._sendError(newEvent);
- };
-
- /**
- * The callback that is fired when a loader encounters an error. The queue will continue loading unless {{#crossLink "LoadQueue/stopOnError:property"}}{{/crossLink}}
- * is set to `true`.
- * @method _handleError
- * @param {ErrorEvent} event The error event, containing relevant error information.
- * @private
- */
- p._handleError = function (event) {
- var loader = event.target;
- this._numItemsLoaded++;
-
- this._finishOrderedItem(loader, true);
- this._updateProgress();
-
- var newEvent = new createjs.ErrorEvent("FILE_LOAD_ERROR", null, loader.getItem());
- // TODO: Propagate actual error message.
-
- this._sendError(newEvent);
-
- if (!this.stopOnError) {
- this._removeLoadItem(loader);
- this._cleanLoadItem(loader);
- this._loadNext();
- } else {
- this.setPaused(true);
- }
- };
-
- /**
- * An item has finished loading. We can assume that it is totally loaded, has been parsed for immediate use, and
- * is available as the "result" property on the load item. The raw text result for a parsed item (such as JSON, XML,
- * CSS, JavaScript, etc) is available as the "rawResult" property, and can also be looked up using {{#crossLink "LoadQueue/getResult"}}{{/crossLink}}.
- * @method _handleFileComplete
- * @param {Event} event The event object from the loader.
- * @private
- */
- p._handleFileComplete = function (event) {
- var loader = event.target;
- var item = loader.getItem();
-
- var result = loader.getResult();
- this._loadedResults[item.id] = result;
- var rawResult = loader.getResult(true);
- if (rawResult != null && rawResult !== result) {
- this._loadedRawResults[item.id] = rawResult;
- }
-
- this._saveLoadedItems(loader);
-
- // Remove the load item
- this._removeLoadItem(loader);
-
- if (!this._finishOrderedItem(loader)) {
- // The item was NOT managed, so process it now
- this._processFinishedLoad(item, loader);
- }
-
- // Clean up the load item
- this._cleanLoadItem(loader);
- };
-
- /**
- * Some loaders might load additional content, other than the item they were passed (such as {{#crossLink "ManifestLoader"}}{{/crossLink}}).
- * Any items exposed by the loader using {{#crossLink "AbstractLoader/getLoadItems"}}{{/crossLink}} are added to the
- * LoadQueue's look-ups, including {{#crossLink "getItem"}}{{/crossLink}} and {{#crossLink "getResult"}}{{/crossLink}}
- * methods.
- * @method _saveLoadedItems
- * @param {AbstractLoader} loader
- * @protected
- * @since 0.6.0
- */
- p._saveLoadedItems = function (loader) {
- // TODO: Not sure how to handle this. Would be nice to expose the items.
- // Loaders may load sub-items. This adds them to this queue
- var list = loader.getLoadedItems();
- if (list === null) {
- return;
- }
-
- for (var i = 0; i < list.length; i++) {
- var item = list[i].item;
-
- // Store item lookups
- this._loadItemsBySrc[item.src] = item;
- this._loadItemsById[item.id] = item;
-
- // Store loaded content
- this._loadedResults[item.id] = list[i].result;
- this._loadedRawResults[item.id] = list[i].rawResult;
- }
- };
-
- /**
- * Flag an item as finished. If the item's order is being managed, then ensure that it is allowed to finish, and if
- * so, trigger prior items to trigger as well.
- * @method _finishOrderedItem
- * @param {AbstractLoader} loader
- * @param {Boolean} loadFailed
- * @return {Boolean} If the item's order is being managed. This allows the caller to take an alternate
- * behaviour if it is.
- * @private
- */
- p._finishOrderedItem = function (loader, loadFailed) {
- var item = loader.getItem();
-
- if ((this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT)
- || item.maintainOrder) {
-
- //TODO: Evaluate removal of the _currentlyLoadingScript
- if (loader instanceof createjs.JavaScriptLoader) {
- this._currentlyLoadingScript = false;
- }
-
- var index = createjs.indexOf(this._scriptOrder, item);
- if (index == -1) {
- return false;
- } // This loader no longer exists
- this._loadedScripts[index] = (loadFailed === true) ? true : item;
-
- this._checkScriptLoadOrder();
- return true;
- }
-
- return false;
- };
-
- /**
- * Ensure the scripts load and dispatch in the correct order. When using XHR, scripts are stored in an array in the
- * order they were added, but with a "null" value. When they are completed, the value is set to the load item,
- * and then when they are processed and dispatched, the value is set to `true`. This method simply
- * iterates the array, and ensures that any loaded items that are not preceded by a `null` value are
- * dispatched.
- * @method _checkScriptLoadOrder
- * @private
- */
- p._checkScriptLoadOrder = function () {
- var l = this._loadedScripts.length;
-
- for (var i = 0; i < l; i++) {
- var item = this._loadedScripts[i];
- if (item === null) {
- break;
- } // This is still loading. Do not process further.
- if (item === true) {
- continue;
- } // This has completed, and been processed. Move on.
-
- var loadItem = this._loadedResults[item.id];
- if (item.type == createjs.LoadQueue.JAVASCRIPT) {
- // Append script tags to the head automatically.
- createjs.DomUtils.appendToHead(loadItem);
- }
-
- var loader = item._loader;
- this._processFinishedLoad(item, loader);
- this._loadedScripts[i] = true;
- }
- };
-
- /**
- * A file has completed loading, and the LoadQueue can move on. This triggers the complete event, and kick-starts
- * the next item.
- * @method _processFinishedLoad
- * @param {LoadItem|Object} item
- * @param {AbstractLoader} loader
- * @protected
- */
- p._processFinishedLoad = function (item, loader) {
- this._numItemsLoaded++;
-
- // Since LoadQueue needs maintain order, we can't append scripts in the loader.
- // So we do it here instead. Or in _checkScriptLoadOrder();
- if (!this.maintainScriptOrder && item.type == createjs.LoadQueue.JAVASCRIPT) {
- var tag = loader.getTag();
- createjs.DomUtils.appendToHead(tag);
- }
-
- this._updateProgress();
- this._sendFileComplete(item, loader);
- this._loadNext();
- };
-
- /**
- * Ensure items with `maintainOrder=true` that are before the specified item have loaded. This only applies to
- * JavaScript items that are being loaded with a TagLoader, since they have to be loaded and completed before
- * the script can even be started, since it exist in the DOM while loading.
- * @method _canStartLoad
- * @param {AbstractLoader} loader The loader for the item
- * @return {Boolean} Whether the item can start a load or not.
- * @private
- */
- p._canStartLoad = function (loader) {
- if (!this.maintainScriptOrder || loader.preferXHR) {
- return true;
- }
- var item = loader.getItem();
- if (item.type != createjs.LoadQueue.JAVASCRIPT) {
- return true;
- }
- if (this._currentlyLoadingScript) {
- return false;
- }
-
- var index = this._scriptOrder.indexOf(item);
- var i = 0;
- while (i < index) {
- var checkItem = this._loadedScripts[i];
- if (checkItem == null) {
- return false;
- }
- i++;
- }
- this._currentlyLoadingScript = true;
- return true;
- };
-
- /**
- * A load item is completed or was canceled, and needs to be removed from the LoadQueue.
- * @method _removeLoadItem
- * @param {AbstractLoader} loader A loader instance to remove.
- * @private
- */
- p._removeLoadItem = function (loader) {
- var l = this._currentLoads.length;
- for (var i = 0; i < l; i++) {
- if (this._currentLoads[i] == loader) {
- this._currentLoads.splice(i, 1);
- break;
- }
- }
- };
-
- /**
- * Remove unneeded references from a loader.
- *
- * @param loader
- * @private
- */
- p._cleanLoadItem = function(loader) {
- var item = loader.getItem();
- if (item) {
- delete item._loader;
- }
- }
-
- /**
- * An item has dispatched progress. Propagate that progress, and update the LoadQueue's overall progress.
- * @method _handleProgress
- * @param {ProgressEvent} event The progress event from the item.
- * @private
- */
- p._handleProgress = function (event) {
- var loader = event.target;
- this._sendFileProgress(loader.getItem(), loader.progress);
- this._updateProgress();
- };
-
- /**
- * Overall progress has changed, so determine the new progress amount and dispatch it. This changes any time an
- * item dispatches progress or completes. Note that since we don't always know the actual filesize of items before
- * they are loaded. In this case, we define a "slot" for each item (1 item in 10 would get 10%), and then append
- * loaded progress on top of the already-loaded items.
- *
- * For example, if 5/10 items have loaded, and item 6 is 20% loaded, the total progress would be:
- *
- *
5/10 of the items in the queue (50%)
- *
plus 20% of item 6's slot (2%)
- *
equals 52%
- *
- * @method _updateProgress
- * @private
- */
- p._updateProgress = function () {
- var loaded = this._numItemsLoaded / this._numItems; // Fully Loaded Progress
- var remaining = this._numItems - this._numItemsLoaded;
- if (remaining > 0) {
- var chunk = 0;
- for (var i = 0, l = this._currentLoads.length; i < l; i++) {
- chunk += this._currentLoads[i].progress;
- }
- loaded += (chunk / remaining) * (remaining / this._numItems);
- }
-
- if (this._lastProgress != loaded) {
- this._sendProgress(loaded);
- this._lastProgress = loaded;
- }
- };
-
- /**
- * Clean out item results, to free them from memory. Mainly, the loaded item and results are cleared from internal
- * hashes.
- * @method _disposeItem
- * @param {LoadItem|Object} item The item that was passed in for preloading.
- * @private
- */
- p._disposeItem = function (item) {
- delete this._loadedResults[item.id];
- delete this._loadedRawResults[item.id];
- delete this._loadItemsById[item.id];
- delete this._loadItemsBySrc[item.src];
- };
-
- /**
- * Dispatch a "fileprogress" {{#crossLink "Event"}}{{/crossLink}}. Please see the LoadQueue {{#crossLink "LoadQueue/fileprogress:event"}}{{/crossLink}}
- * event for details on the event payload.
- * @method _sendFileProgress
- * @param {LoadItem|Object} item The item that is being loaded.
- * @param {Number} progress The amount the item has been loaded (between 0 and 1).
- * @protected
- */
- p._sendFileProgress = function (item, progress) {
- if (this._isCanceled() || this._paused) {
- return;
- }
- if (!this.hasEventListener("fileprogress")) {
- return;
- }
-
- //LM: Rework ProgressEvent to support this?
- var event = new createjs.Event("fileprogress");
- event.progress = progress;
- event.loaded = progress;
- event.total = 1;
- event.item = item;
-
- this.dispatchEvent(event);
- };
-
- /**
- * Dispatch a fileload {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event for
- * details on the event payload.
- * @method _sendFileComplete
- * @param {LoadItemObject} item The item that is being loaded.
- * @param {AbstractLoader} loader
- * @protected
- */
- p._sendFileComplete = function (item, loader) {
- if (this._isCanceled() || this._paused) {
- return;
- }
-
- var event = new createjs.Event("fileload");
- event.loader = loader;
- event.item = item;
- event.result = this._loadedResults[item.id];
- event.rawResult = this._loadedRawResults[item.id];
-
- // This calls a handler specified on the actual load item. Currently, the SoundJS plugin uses this.
- if (item.completeHandler) {
- item.completeHandler(event);
- }
-
- this.hasEventListener("fileload") && this.dispatchEvent(event);
- };
-
- /**
- * Dispatch a filestart {{#crossLink "Event"}}{{/crossLink}} immediately before a file starts to load. Please see
- * the {{#crossLink "LoadQueue/filestart:event"}}{{/crossLink}} event for details on the event payload.
- * @method _sendFileStart
- * @param {LoadItem|Object} item The item that is being loaded.
- * @protected
- */
- p._sendFileStart = function (item) {
- var event = new createjs.Event("filestart");
- event.item = item;
- this.hasEventListener("filestart") && this.dispatchEvent(event);
- };
-
- p.toString = function () {
- return "[PreloadJS LoadQueue]";
- };
-
- createjs.LoadQueue = createjs.promote(LoadQueue, "AbstractLoader");
-}());
-
-//##############################################################################
-// TextLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for Text files.
- * @class TextLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function TextLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.TEXT);
- };
-
- var p = createjs.extend(TextLoader, createjs.AbstractLoader);
- var s = TextLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader loads items that are of type {{#crossLink "AbstractLoader/TEXT:property"}}{{/crossLink}},
- * but is also the default loader if a file type can not be determined.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.TEXT;
- };
-
- createjs.TextLoader = createjs.promote(TextLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// BinaryLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for binary files. This is useful for loading web audio, or content that requires an ArrayBuffer.
- * @class BinaryLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function BinaryLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.BINARY);
- this.on("initialize", this._updateXHR, this);
- };
-
- var p = createjs.extend(BinaryLoader, createjs.AbstractLoader);
- var s = BinaryLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/BINARY:property"}}{{/crossLink}}
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.BINARY;
- };
-
- // private methods
- /**
- * Before the item loads, set the response type to "arraybuffer"
- * @property _updateXHR
- * @param {Event} event
- * @private
- */
- p._updateXHR = function (event) {
- event.loader.setResponseType("arraybuffer");
- };
-
- createjs.BinaryLoader = createjs.promote(BinaryLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// CSSLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for CSS files.
- * @class CSSLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractLoader
- * @constructor
- */
- function CSSLoader(loadItem, preferXHR) {
- this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.CSS);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "href";
-
- if (preferXHR) {
- this._tag = document.createElement("style");
- } else {
- this._tag = document.createElement("link");
- }
-
- this._tag.rel = "stylesheet";
- this._tag.type = "text/css";
- };
-
- var p = createjs.extend(CSSLoader, createjs.AbstractLoader);
- var s = CSSLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/CSS:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.CSS;
- };
-
- // protected methods
- /**
- * The result formatter for CSS files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLLinkElement|HTMLStyleElement}
- * @private
- */
- p._formatResult = function (loader) {
- if (this._preferXHR) {
- var tag = loader.getTag();
-
- if (tag.styleSheet) { // IE
- tag.styleSheet.cssText = loader.getResult(true);
- } else {
- var textNode = document.createTextNode(loader.getResult(true));
- tag.appendChild(textNode);
- }
- } else {
- tag = this._tag;
- }
-
- createjs.DomUtils.appendToHead(tag);
-
- return tag;
- };
-
- createjs.CSSLoader = createjs.promote(CSSLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// ImageLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for image files.
- * @class ImageLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractLoader
- * @constructor
- */
- function ImageLoader (loadItem, preferXHR) {
- this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.IMAGE);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "src";
-
- // Check if the preload item is already a tag.
- if (createjs.RequestUtils.isImageTag(loadItem)) {
- this._tag = loadItem;
- } else if (createjs.RequestUtils.isImageTag(loadItem.src)) {
- this._tag = loadItem.src;
- } else if (createjs.RequestUtils.isImageTag(loadItem.tag)) {
- this._tag = loadItem.tag;
- }
-
- if (this._tag != null) {
- this._preferXHR = false;
- } else {
- this._tag = document.createElement("img");
- }
-
- this.on("initialize", this._updateXHR, this);
- };
-
- var p = createjs.extend(ImageLoader, createjs.AbstractLoader);
- var s = ImageLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/IMAGE:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.IMAGE;
- };
-
- // public methods
- p.load = function () {
- if (this._tag.src != "" && this._tag.complete) {
- this._sendComplete();
- return;
- }
-
- var crossOrigin = this._item.crossOrigin;
- if (crossOrigin == true) { crossOrigin = "Anonymous"; }
- if (crossOrigin != null && !createjs.RequestUtils.isLocal(this._item.src)) {
- this._tag.crossOrigin = crossOrigin;
- }
-
- this.AbstractLoader_load();
- };
-
- // protected methods
- /**
- * Before the item loads, set its mimeType and responseType.
- * @property _updateXHR
- * @param {Event} event
- * @private
- */
- p._updateXHR = function (event) {
- event.loader.mimeType = 'text/plain; charset=x-user-defined-binary';
-
- // Only exists for XHR
- if (event.loader.setResponseType) {
- event.loader.setResponseType("blob");
- }
- };
-
- /**
- * The result formatter for Image files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLImageElement}
- * @private
- */
- p._formatResult = function (loader) {
- return this._formatImage;
- };
-
- /**
- * The asynchronous image formatter function. This is required because images have
- * a short delay before they are ready.
- * @method _formatImage
- * @param {Function} successCallback The method to call when the result has finished formatting
- * @param {Function} errorCallback The method to call if an error occurs during formatting
- * @private
- */
- p._formatImage = function (successCallback, errorCallback) {
- var tag = this._tag;
- var URL = window.URL || window.webkitURL;
-
- if (!this._preferXHR) {
- //document.body.removeChild(tag);
- } else if (URL) {
- var objURL = URL.createObjectURL(this.getResult(true));
- tag.src = objURL;
-
- tag.addEventListener("load", this._cleanUpURL, false);
- tag.addEventListener("error", this._cleanUpURL, false);
- } else {
- tag.src = this._item.src;
- }
-
- if (tag.complete) {
- successCallback(tag);
- } else {
- tag.onload = createjs.proxy(function() {
- successCallback(this._tag);
- }, this);
-
- tag.onerror = createjs.proxy(function() {
- errorCallback(_this._tag);
- }, this);
- }
- };
-
- /**
- * Clean up the ObjectURL, the tag is done with it. Note that this function is run
- * as an event listener without a proxy/closure, as it doesn't require it - so do not
- * include any functionality that requires scope without changing it.
- * @method _cleanUpURL
- * @param event
- * @private
- */
- p._cleanUpURL = function (event) {
- var URL = window.URL || window.webkitURL;
- URL.revokeObjectURL(event.target.src);
- };
-
- createjs.ImageLoader = createjs.promote(ImageLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// JavaScriptLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for JavaScript files.
- * @class JavaScriptLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractLoader
- * @constructor
- */
- function JavaScriptLoader(loadItem, preferXHR) {
- this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.JAVASCRIPT);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "src";
- this.setTag(document.createElement("script"));
- };
-
- var p = createjs.extend(JavaScriptLoader, createjs.AbstractLoader);
- var s = JavaScriptLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/JAVASCRIPT:property"}}{{/crossLink}}
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.JAVASCRIPT;
- };
-
- // protected methods
- /**
- * The result formatter for JavaScript files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLLinkElement|HTMLStyleElement}
- * @private
- */
- p._formatResult = function (loader) {
- var tag = loader.getTag();
- if (this._preferXHR) {
- tag.text = loader.getResult(true);
- }
- return tag;
- };
-
- createjs.JavaScriptLoader = createjs.promote(JavaScriptLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// JSONLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for JSON files. To load JSON cross-domain, use JSONP and the {{#crossLink "JSONPLoader"}}{{/crossLink}}
- * instead. To load JSON-formatted manifests, use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to
- * load EaselJS SpriteSheets, use {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}.
- * @class JSONLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function JSONLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.JSON);
-
- // public properties
- this.resultFormatter = this._formatResult;
- };
-
- var p = createjs.extend(JSONLoader, createjs.AbstractLoader);
- var s = JSONLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/JSON:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.JSON;
- };
-
- // protected methods
- /**
- * The result formatter for JSON files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLLinkElement|HTMLStyleElement}
- * @private
- */
- p._formatResult = function (loader) {
- var json = null;
- try {
- json = createjs.DataUtils.parseJSON(loader.getResult(true));
- } catch (e) {
- var event = new createjs.ErrorEvent("JSON_FORMAT", null, e);
- this._sendError(event);
- return e;
- }
-
- return json;
- };
-
- createjs.JSONLoader = createjs.promote(JSONLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// JSONPLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for JSONP files, which are JSON-formatted text files, wrapped in a callback. To load regular JSON
- * without a callback use the {{#crossLink "JSONLoader"}}{{/crossLink}} instead. To load JSON-formatted manifests,
- * use {{#crossLink "ManifestLoader"}}{{/crossLink}}, and to load EaselJS SpriteSheets, use
- * {{#crossLink "SpriteSheetLoader"}}{{/crossLink}}.
- *
- * JSONP is a format that provides a solution for loading JSON files cross-domain without requiring CORS.
- * JSONP files are loaded as JavaScript, and the "callback" is executed once they are loaded. The callback in the
- * JSONP must match the callback passed to the loadItem.
- *
- *
- *
- * var loadItem = {id:"json", type:"jsonp", src:"http://server.com/text.json", callback:"callbackName"}
- * var queue = new createjs.LoadQueue();
- * queue.on("complete", handleComplete);
- * queue.loadItem(loadItem);
- *
- * function handleComplete(event) }
- * var json = queue.getResult("json");
- * console.log(json.obj.bool); // true
- * }
- *
- * Note that JSONP files loaded concurrently require a unique callback. To ensure JSONP files are loaded
- * in order, either use the {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}} method (set to 1),
- * or set {{#crossLink "LoadItem/maintainOrder:property"}}{{/crossLink}} on items with the same callback.
- *
- * @class JSONPLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function JSONPLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, false, createjs.AbstractLoader.JSONP);
- this.setTag(document.createElement("script"));
- this.getTag().type = "text/javascript";
- };
-
- var p = createjs.extend(JSONPLoader, createjs.AbstractLoader);
- var s = JSONPLoader;
-
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/JSONP:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.JSONP;
- };
-
- // public methods
- p.cancel = function () {
- this.AbstractLoader_cancel();
- this._dispose();
- };
-
- /**
- * Loads the JSONp file. Because of the unique loading needs of JSONp
- * we don't use the AbstractLoader.load() method.
- *
- * @method load
- *
- */
- p.load = function () {
- if (this._item.callback == null) {
- throw new Error('callback is required for loading JSONP requests.');
- }
-
- // TODO: Look into creating our own iFrame to handle the load
- // In the first attempt, FF did not get the result
- // result instanceof Object did not work either
- // so we would need to clone the result.
- if (window[this._item.callback] != null) {
- throw new Error(
- "JSONP callback '" +
- this._item.callback +
- "' already exists on window. You need to specify a different callback or re-name the current one.");
- }
-
- window[this._item.callback] = createjs.proxy(this._handleLoad, this);
- window.document.body.appendChild(this._tag);
-
- this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
-
- // Load the tag
- this._tag.src = this._item.src;
- };
-
- // private methods
- /**
- * Handle the JSONP callback, which is a public method defined on `window`.
- * @method _handleLoad
- * @param {Object} data The formatted JSON data.
- * @private
- */
- p._handleLoad = function (data) {
- this._result = this._rawResult = data;
- this._sendComplete();
-
- this._dispose();
- };
-
- /**
- * The tag request has not loaded within the time specfied in loadTimeout.
- * @method _handleError
- * @param {Object} event The XHR error event.
- * @private
- */
- p._handleTimeout = function () {
- this._dispose();
- this.dispatchEvent(new createjs.ErrorEvent("timeout"));
- };
-
- /**
- * Clean up the JSONP load. This clears out the callback and script tag that this loader creates.
- * @method _dispose
- * @private
- */
- p._dispose = function () {
- window.document.body.removeChild(this._tag);
- delete window[this._item.callback];
-
- clearTimeout(this._loadTimeout);
- };
-
- createjs.JSONPLoader = createjs.promote(JSONPLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// ManifestLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for JSON manifests. Items inside the manifest are loaded before the loader completes. To load manifests
- * using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}} as part of the
- * {{#crossLink "LoadItem"}}{{/crossLink}}.
- *
- * The list of files in the manifest must be defined on the top-level JSON object in a `manifest` property. This
- * example shows a sample manifest definition, as well as how to to include a sub-manifest.
- *
- * {
- * "path": "assets/",
- * "manifest": [
- * "image.png",
- * {"src": "image2.png", "id":"image2"},
- * {"src": "sub-manifest.json", "type":"manifest", "callback":"jsonCallback"}
- * ]
- * }
- *
- * When a ManifestLoader has completed loading, the parent loader (usually a {{#crossLink "LoadQueue"}}{{/crossLink}},
- * but could also be another ManifestLoader) will inherit all the loaded items, so you can access them directly.
- *
- * Note that the {{#crossLink "JSONLoader"}}{{/crossLink}} and {{#crossLink "JSONPLoader"}}{{/crossLink}} are
- * higher priority loaders, so manifests must set the {{#crossLink "LoadItem"}}{{/crossLink}}
- * {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property to {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}.
- * @class ManifestLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function ManifestLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, null, createjs.AbstractLoader.MANIFEST);
-
- // Public Properties
- /**
- * An array of the plugins registered using {{#crossLink "LoadQueue/installPlugin"}}{{/crossLink}},
- * used to pass plugins to new LoadQueues that may be created.
- * @property _plugins
- * @type {Array}
- * @private
- * @since 0.6.1
- */
- this.plugins = null;
-
-
- // Protected Properties
- /**
- * An internal {{#crossLink "LoadQueue"}}{{/crossLink}} that loads the contents of the manifest.
- * @property _manifestQueue
- * @type {LoadQueue}
- * @private
- */
- this._manifestQueue = null;
- };
-
- var p = createjs.extend(ManifestLoader, createjs.AbstractLoader);
- var s = ManifestLoader;
-
- // static properties
- /**
- * The amount of progress that the manifest itself takes up.
- * @property MANIFEST_PROGRESS
- * @type {number}
- * @default 0.25 (25%)
- * @private
- * @static
- */
- s.MANIFEST_PROGRESS = 0.25;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/MANIFEST:property"}}{{/crossLink}}
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.MANIFEST;
- };
-
- // public methods
- p.load = function () {
- this.AbstractLoader_load();
- };
-
- // protected methods
- p._createRequest = function() {
- var callback = this._item.callback;
- if (callback != null) {
- this._request = new createjs.JSONPLoader(this._item);
- } else {
- this._request = new createjs.JSONLoader(this._item);
- }
- };
-
- p.handleEvent = function (event) {
- switch (event.type) {
- case "complete":
- this._rawResult = event.target.getResult(true);
- this._result = event.target.getResult();
- this._sendProgress(s.MANIFEST_PROGRESS);
- this._loadManifest(this._result);
- return;
- case "progress":
- event.loaded *= s.MANIFEST_PROGRESS;
- this.progress = event.loaded / event.total;
- if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
- this._sendProgress(event);
- return;
- }
- this.AbstractLoader_handleEvent(event);
- };
-
- p.destroy = function() {
- this.AbstractLoader_destroy();
- this._manifestQueue.close();
- };
-
- /**
- * Create and load the manifest items once the actual manifest has been loaded.
- * @method _loadManifest
- * @param {Object} json
- * @private
- */
- p._loadManifest = function (json) {
- if (json && json.manifest) {
- var queue = this._manifestQueue = new createjs.LoadQueue();
- queue.on("fileload", this._handleManifestFileLoad, this);
- queue.on("progress", this._handleManifestProgress, this);
- queue.on("complete", this._handleManifestComplete, this, true);
- queue.on("error", this._handleManifestError, this, true);
- for(var i = 0, l = this.plugins.length; i < l; i++) { // conserve order of plugins
- queue.installPlugin(this.plugins[i]);
- }
- queue.loadManifest(json);
- } else {
- this._sendComplete();
- }
- };
-
- /**
- * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed.
- * @method _handleManifestFileLoad
- * @param {Event} event
- * @private
- */
- p._handleManifestFileLoad = function (event) {
- event.target = null;
- this.dispatchEvent(event);
- };
-
- /**
- * The manifest has completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}
- * {{#crossLink "Event"}}{{/crossLink}} from the ManifestLoader.
- * @method _handleManifestComplete
- * @param {Event} event
- * @private
- */
- p._handleManifestComplete = function (event) {
- this._loadedItems = this._manifestQueue.getItems(true);
- this._sendComplete();
- };
-
- /**
- * The manifest has reported progress.
- * @method _handleManifestProgress
- * @param {ProgressEvent} event
- * @private
- */
- p._handleManifestProgress = function (event) {
- this.progress = event.progress * (1 - s.MANIFEST_PROGRESS) + s.MANIFEST_PROGRESS;
- this._sendProgress(this.progress);
- };
-
- /**
- * The manifest has reported an error with one of the files.
- * @method _handleManifestError
- * @param {ErrorEvent} event
- * @private
- */
- p._handleManifestError = function (event) {
- var newEvent = new createjs.Event("fileerror");
- newEvent.item = event.data;
- this.dispatchEvent(newEvent);
- };
-
- createjs.ManifestLoader = createjs.promote(ManifestLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// SoundLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which
- * should be created by either a library playing the sound (such as SoundJS, or an
- * external framework that handles audio playback. To load content that can be played by WebAudio, use the
- * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually.
- * @class SoundLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractMediaLoader
- * @constructor
- */
- function SoundLoader(loadItem, preferXHR) {
- this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND);
-
- // protected properties
- if (createjs.RequestUtils.isAudioTag(loadItem)) {
- this._tag = loadItem;
- } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) {
- this._tag = loadItem;
- } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) {
- this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src;
- }
-
- if (this._tag != null) {
- this._preferXHR = false;
- }
- };
-
- var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader);
- var s = SoundLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.SOUND;
- };
-
- // protected methods
- p._createTag = function (src) {
- var tag = document.createElement("audio");
- tag.autoplay = false;
- tag.preload = "none";
-
- //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works.
- tag.src = src;
- return tag;
- };
-
- createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader");
-
-}());
-
-//##############################################################################
-// VideoLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for video files.
- * @class VideoLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractMediaLoader
- * @constructor
- */
- function VideoLoader(loadItem, preferXHR) {
- this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.VIDEO);
-
- if (createjs.RequestUtils.isVideoTag(loadItem) || createjs.RequestUtils.isVideoTag(loadItem.src)) {
- this.setTag(createjs.RequestUtils.isVideoTag(loadItem)?loadItem:loadItem.src);
-
- // We can't use XHR for a tag that's passed in.
- this._preferXHR = false;
- } else {
- this.setTag(this._createTag());
- }
- };
-
- var p = createjs.extend(VideoLoader, createjs.AbstractMediaLoader);
- var s = VideoLoader;
-
- /**
- * Create a new video tag
- *
- * @returns {HTMLElement}
- * @private
- */
- p._createTag = function () {
- return document.createElement("video");
- };
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/VIDEO:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.VIDEO;
- };
-
- createjs.VideoLoader = createjs.promote(VideoLoader, "AbstractMediaLoader");
-
-}());
-
-//##############################################################################
-// SpriteSheetLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for EaselJS SpriteSheets. Images inside the spritesheet definition are loaded before the loader
- * completes. To load SpriteSheets using JSONP, specify a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}}
- * as part of the {{#crossLink "LoadItem"}}{{/crossLink}}. Note that the {{#crossLink "JSONLoader"}}{{/crossLink}}
- * and {{#crossLink "JSONPLoader"}}{{/crossLink}} are higher priority loaders, so SpriteSheets must
- * set the {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/type:property"}}{{/crossLink}} property
- * to {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}.
- *
- * The {{#crossLink "LoadItem"}}{{/crossLink}} {{#crossLink "LoadItem/crossOrigin:property"}}{{/crossLink}} as well
- * as the {{#crossLink "LoadQueue's"}}{{/crossLink}} `basePath` argument and {{#crossLink "LoadQueue/_preferXHR"}}{{/crossLink}}
- * property supplied to the {{#crossLink "LoadQueue"}}{{/crossLink}} are passed on to the sub-manifest that loads
- * the SpriteSheet images.
- *
- * Note that the SpriteSheet JSON does not respect the {{#crossLink "LoadQueue/_preferXHR:property"}}{{/crossLink}}
- * property, which should instead be determined by the presence of a {{#crossLink "LoadItem/callback:property"}}{{/crossLink}}
- * property on the SpriteSheet load item. This is because the JSON loaded will have a different format depending on
- * if it is loaded as JSON, so just changing `preferXHR` is not enough to change how it is loaded.
- * @class SpriteSheetLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function SpriteSheetLoader(loadItem, preferXHR) {
- this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SPRITESHEET);
-
- // protected properties
- /**
- * An internal queue which loads the SpriteSheet's images.
- * @method _manifestQueue
- * @type {LoadQueue}
- * @private
- */
- this._manifestQueue = null;
- }
-
- var p = createjs.extend(SpriteSheetLoader, createjs.AbstractLoader);
- var s = SpriteSheetLoader;
-
- // static properties
- /**
- * The amount of progress that the manifest itself takes up.
- * @property SPRITESHEET_PROGRESS
- * @type {number}
- * @default 0.25 (25%)
- * @private
- * @static
- */
- s.SPRITESHEET_PROGRESS = 0.25;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/SPRITESHEET:property"}}{{/crossLink}}
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.SPRITESHEET;
- };
-
- // public methods
- p.destroy = function() {
- this.AbstractLoader_destroy;
- this._manifestQueue.close();
- };
-
- // protected methods
- p._createRequest = function() {
- var callback = this._item.callback;
- if (callback != null) {
- this._request = new createjs.JSONPLoader(this._item);
- } else {
- this._request = new createjs.JSONLoader(this._item);
- }
- };
-
- p.handleEvent = function (event) {
- switch (event.type) {
- case "complete":
- this._rawResult = event.target.getResult(true);
- this._result = event.target.getResult();
- this._sendProgress(s.SPRITESHEET_PROGRESS);
- this._loadManifest(this._result);
- return;
- case "progress":
- event.loaded *= s.SPRITESHEET_PROGRESS;
- this.progress = event.loaded / event.total;
- if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
- this._sendProgress(event);
- return;
- }
- this.AbstractLoader_handleEvent(event);
- };
-
- /**
- * Create and load the images once the SpriteSheet JSON has been loaded.
- * @method _loadManifest
- * @param {Object} json
- * @private
- */
- p._loadManifest = function (json) {
- if (json && json.images) {
- var queue = this._manifestQueue = new createjs.LoadQueue(this._preferXHR, this._item.path, this._item.crossOrigin);
- queue.on("complete", this._handleManifestComplete, this, true);
- queue.on("fileload", this._handleManifestFileLoad, this);
- queue.on("progress", this._handleManifestProgress, this);
- queue.on("error", this._handleManifestError, this, true);
- queue.loadManifest(json.images);
- }
- };
-
- /**
- * An item from the {{#crossLink "_manifestQueue:property"}}{{/crossLink}} has completed.
- * @method _handleManifestFileLoad
- * @param {Event} event
- * @private
- */
- p._handleManifestFileLoad = function (event) {
- var image = event.result;
- if (image != null) {
- var images = this.getResult().images;
- var pos = images.indexOf(event.item.src);
- images[pos] = image;
- }
- };
-
- /**
- * The images have completed loading. This triggers the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}}
- * {{#crossLink "Event"}}{{/crossLink}} from the SpriteSheetLoader.
- * @method _handleManifestComplete
- * @param {Event} event
- * @private
- */
- p._handleManifestComplete = function (event) {
- this._result = new createjs.SpriteSheet(this._result);
- this._loadedItems = this._manifestQueue.getItems(true);
- this._sendComplete();
- };
-
- /**
- * The images {{#crossLink "LoadQueue"}}{{/crossLink}} has reported progress.
- * @method _handleManifestProgress
- * @param {ProgressEvent} event
- * @private
- */
- p._handleManifestProgress = function (event) {
- this.progress = event.progress * (1 - s.SPRITESHEET_PROGRESS) + s.SPRITESHEET_PROGRESS;
- this._sendProgress(this.progress);
- };
-
- /**
- * An image has reported an error.
- * @method _handleManifestError
- * @param {ErrorEvent} event
- * @private
- */
- p._handleManifestError = function (event) {
- var newEvent = new createjs.Event("fileerror");
- newEvent.item = event.data;
- this.dispatchEvent(newEvent);
- };
-
- createjs.SpriteSheetLoader = createjs.promote(SpriteSheetLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// SVGLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for SVG files.
- * @class SVGLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractLoader
- * @constructor
- */
- function SVGLoader(loadItem, preferXHR) {
- this.AbstractLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SVG);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "data";
-
- if (preferXHR) {
- this.setTag(document.createElement("svg"));
- } else {
- this.setTag(document.createElement("object"));
- this.getTag().type = "image/svg+xml";
- }
- };
-
- var p = createjs.extend(SVGLoader, createjs.AbstractLoader);
- var s = SVGLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/SVG:property"}}{{/crossLink}}
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.SVG;
- };
-
- // protected methods
- /**
- * The result formatter for SVG files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {Object}
- * @private
- */
- p._formatResult = function (loader) {
- // mime should be image/svg+xml, but Opera requires text/xml
- var xml = createjs.DataUtils.parseXML(loader.getResult(true), "text/xml");
- var tag = loader.getTag();
-
- if (!this._preferXHR && document.body.contains(tag)) {
- document.body.removeChild(tag);
- }
-
- if (xml.documentElement != null) {
- tag.appendChild(xml.documentElement);
- tag.style.visibility = "visible";
- return tag;
- } else { // For browsers that don't support SVG, just give them the XML. (IE 9-8)
- return xml;
- }
- };
-
- createjs.SVGLoader = createjs.promote(SVGLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// XMLLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for CSS files.
- * @class XMLLoader
- * @param {LoadItem|Object} loadItem
- * @extends AbstractLoader
- * @constructor
- */
- function XMLLoader(loadItem) {
- this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.XML);
-
- // public properties
- this.resultFormatter = this._formatResult;
- };
-
- var p = createjs.extend(XMLLoader, createjs.AbstractLoader);
- var s = XMLLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/XML:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.XML;
- };
-
- // protected methods
- /**
- * The result formatter for XML files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {XMLDocument}
- * @private
- */
- p._formatResult = function (loader) {
- return createjs.DataUtils.parseXML(loader.getResult(true), "text/xml");
- };
-
- createjs.XMLLoader = createjs.promote(XMLLoader, "AbstractLoader");
-
-}());
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js b/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js
deleted file mode 100644
index 6f898e826e..0000000000
--- a/bomberman/frontend/src/main/webapp/js/lib/soundjs-NEXT.combined.js
+++ /dev/null
@@ -1,7949 +0,0 @@
-/*!
-* SoundJS
-* Visit http://createjs.com/ for documentation, updates and examples.
-*
-* Copyright (c) 2010 gskinner.com, inc.
-*
-* Permission is hereby granted, free of charge, to any person
-* obtaining a copy of this software and associated documentation
-* files (the "Software"), to deal in the Software without
-* restriction, including without limitation the rights to use,
-* copy, modify, merge, publish, distribute, sublicense, and/or sell
-* copies of the Software, and to permit persons to whom the
-* Software is furnished to do so, subject to the following
-* conditions:
-*
-* The above copyright notice and this permission notice shall be
-* included in all copies or substantial portions of the Software.
-*
-* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
-* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
-* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-* OTHER DEALINGS IN THE SOFTWARE.
-*/
-
-
-//##############################################################################
-// version.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
-
- /**
- * Static class holding library specific information such as the version and buildDate of the library.
- * The SoundJS class has been renamed {{#crossLink "Sound"}}{{/crossLink}}. Please see {{#crossLink "Sound"}}{{/crossLink}}
- * for information on using sound.
- * @class SoundJS
- **/
- var s = createjs.SoundJS = createjs.SoundJS || {};
-
- /**
- * The version string for this release.
- * @property version
- * @type String
- * @static
- **/
- s.version = /*=version*/"NEXT"; // injected by build process
-
- /**
- * The build date for this release in UTC format.
- * @property buildDate
- * @type String
- * @static
- **/
- s.buildDate = /*=date*/"Fri, 04 Dec 2015 17:24:04 GMT"; // injected by build process
-
-})();
-
-//##############################################################################
-// extend.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Sets up the prototype chain and constructor property for a new class.
- *
- * This should be called right after creating the class constructor.
- *
- * function MySubClass() {}
- * createjs.extend(MySubClass, MySuperClass);
- * MySubClass.prototype.doSomething = function() { }
- *
- * var foo = new MySubClass();
- * console.log(foo instanceof MySuperClass); // true
- * console.log(foo.prototype.constructor === MySubClass); // true
- *
- * @method extend
- * @param {Function} subclass The subclass.
- * @param {Function} superclass The superclass to extend.
- * @return {Function} Returns the subclass's new prototype.
- */
-createjs.extend = function(subclass, superclass) {
- "use strict";
-
- function o() { this.constructor = subclass; }
- o.prototype = superclass.prototype;
- return (subclass.prototype = new o());
-};
-
-//##############################################################################
-// promote.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Promotes any methods on the super class that were overridden, by creating an alias in the format `prefix_methodName`.
- * It is recommended to use the super class's name as the prefix.
- * An alias to the super class's constructor is always added in the format `prefix_constructor`.
- * This allows the subclass to call super class methods without using `function.call`, providing better performance.
- *
- * For example, if `MySubClass` extends `MySuperClass`, and both define a `draw` method, then calling `promote(MySubClass, "MySuperClass")`
- * would add a `MySuperClass_constructor` method to MySubClass and promote the `draw` method on `MySuperClass` to the
- * prototype of `MySubClass` as `MySuperClass_draw`.
- *
- * This should be called after the class's prototype is fully defined.
- *
- * function ClassA(name) {
- * this.name = name;
- * }
- * ClassA.prototype.greet = function() {
- * return "Hello "+this.name;
- * }
- *
- * function ClassB(name, punctuation) {
- * this.ClassA_constructor(name);
- * this.punctuation = punctuation;
- * }
- * createjs.extend(ClassB, ClassA);
- * ClassB.prototype.greet = function() {
- * return this.ClassA_greet()+this.punctuation;
- * }
- * createjs.promote(ClassB, "ClassA");
- *
- * var foo = new ClassB("World", "!?!");
- * console.log(foo.greet()); // Hello World!?!
- *
- * @method promote
- * @param {Function} subclass The class to promote super class methods on.
- * @param {String} prefix The prefix to add to the promoted method names. Usually the name of the superclass.
- * @return {Function} Returns the subclass.
- */
-createjs.promote = function(subclass, prefix) {
- "use strict";
-
- var subP = subclass.prototype, supP = (Object.getPrototypeOf&&Object.getPrototypeOf(subP))||subP.__proto__;
- if (supP) {
- subP[(prefix+="_") + "constructor"] = supP.constructor; // constructor is not always innumerable
- for (var n in supP) {
- if (subP.hasOwnProperty(n) && (typeof supP[n] == "function")) { subP[prefix + n] = supP[n]; }
- }
- }
- return subclass;
-};
-
-//##############################################################################
-// IndexOf.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-
-/**
- * Finds the first occurrence of a specified value searchElement in the passed in array, and returns the index of
- * that value. Returns -1 if value is not found.
- *
- * var i = createjs.indexOf(myArray, myElementToFind);
- *
- * @method indexOf
- * @param {Array} array Array to search for searchElement
- * @param searchElement Element to find in array.
- * @return {Number} The first index of searchElement in array.
- */
-createjs.indexOf = function (array, searchElement){
- "use strict";
-
- for (var i = 0,l=array.length; i < l; i++) {
- if (searchElement === array[i]) {
- return i;
- }
- }
- return -1;
-};
-
-//##############################################################################
-// Proxy.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * Various utilities that the CreateJS Suite uses. Utilities are created as separate files, and will be available on the
- * createjs namespace directly.
- *
- *
Example
- *
- * myObject.addEventListener("change", createjs.proxy(myMethod, scope));
- *
- * @class Utility Methods
- * @main Utility Methods
- */
-
-(function() {
- "use strict";
-
- /**
- * A function proxy for methods. By default, JavaScript methods do not maintain scope, so passing a method as a
- * callback will result in the method getting called in the scope of the caller. Using a proxy ensures that the
- * method gets called in the correct scope.
- *
- * Additional arguments can be passed that will be applied to the function when it is called.
- *
- *
Example
- *
- * myObject.addEventListener("event", createjs.proxy(myHandler, this, arg1, arg2));
- *
- * function myHandler(arg1, arg2) {
- * // This gets called when myObject.myCallback is executed.
- * }
- *
- * @method proxy
- * @param {Function} method The function to call
- * @param {Object} scope The scope to call the method name on
- * @param {mixed} [arg] * Arguments that are appended to the callback for additional params.
- * @public
- * @static
- */
- createjs.proxy = function (method, scope) {
- var aArgs = Array.prototype.slice.call(arguments, 2);
- return function () {
- return method.apply(scope, Array.prototype.slice.call(arguments, 0).concat(aArgs));
- };
- }
-
-}());
-
-//##############################################################################
-// BrowserDetect.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-/**
- * @class Utility Methods
- */
-(function() {
- "use strict";
-
- /**
- * An object that determines the current browser, version, operating system, and other environment
- * variables via user agent string.
- *
- * Used for audio because feature detection is unable to detect the many limitations of mobile devices.
- *
- *
Example
- *
- * if (createjs.BrowserDetect.isIOS) { // do stuff }
- *
- * @property BrowserDetect
- * @type {Object}
- * @param {Boolean} isFirefox True if our browser is Firefox.
- * @param {Boolean} isOpera True if our browser is opera.
- * @param {Boolean} isChrome True if our browser is Chrome. Note that Chrome for Android returns true, but is a
- * completely different browser with different abilities.
- * @param {Boolean} isIOS True if our browser is safari for iOS devices (iPad, iPhone, and iPod).
- * @param {Boolean} isAndroid True if our browser is Android.
- * @param {Boolean} isBlackberry True if our browser is Blackberry.
- * @constructor
- * @static
- */
- function BrowserDetect() {
- throw "BrowserDetect cannot be instantiated";
- };
-
- var agent = BrowserDetect.agent = window.navigator.userAgent;
- BrowserDetect.isWindowPhone = (agent.indexOf("IEMobile") > -1) || (agent.indexOf("Windows Phone") > -1);
- BrowserDetect.isFirefox = (agent.indexOf("Firefox") > -1);
- BrowserDetect.isOpera = (window.opera != null);
- BrowserDetect.isChrome = (agent.indexOf("Chrome") > -1); // NOTE that Chrome on Android returns true but is a completely different browser with different abilities
- BrowserDetect.isIOS = (agent.indexOf("iPod") > -1 || agent.indexOf("iPhone") > -1 || agent.indexOf("iPad") > -1) && !BrowserDetect.isWindowPhone;
- BrowserDetect.isAndroid = (agent.indexOf("Android") > -1) && !BrowserDetect.isWindowPhone;
- BrowserDetect.isBlackberry = (agent.indexOf("Blackberry") > -1);
-
- createjs.BrowserDetect = BrowserDetect;
-
-}());
-
-//##############################################################################
-// EventDispatcher.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
-
-// constructor:
- /**
- * EventDispatcher provides methods for managing queues of event listeners and dispatching events.
- *
- * You can either extend EventDispatcher or mix its methods into an existing prototype or instance by using the
- * EventDispatcher {{#crossLink "EventDispatcher/initialize"}}{{/crossLink}} method.
- *
- * Together with the CreateJS Event class, EventDispatcher provides an extended event model that is based on the
- * DOM Level 2 event model, including addEventListener, removeEventListener, and dispatchEvent. It supports
- * bubbling / capture, preventDefault, stopPropagation, stopImmediatePropagation, and handleEvent.
- *
- * EventDispatcher also exposes a {{#crossLink "EventDispatcher/on"}}{{/crossLink}} method, which makes it easier
- * to create scoped listeners, listeners that only run once, and listeners with associated arbitrary data. The
- * {{#crossLink "EventDispatcher/off"}}{{/crossLink}} method is merely an alias to
- * {{#crossLink "EventDispatcher/removeEventListener"}}{{/crossLink}}.
- *
- * Another addition to the DOM Level 2 model is the {{#crossLink "EventDispatcher/removeAllEventListeners"}}{{/crossLink}}
- * method, which can be used to listeners for all events, or listeners for a specific event. The Event object also
- * includes a {{#crossLink "Event/remove"}}{{/crossLink}} method which removes the active listener.
- *
- *
Example
- * Add EventDispatcher capabilities to the "MyClass" class.
- *
- * EventDispatcher.initialize(MyClass.prototype);
- *
- * Add an event (see {{#crossLink "EventDispatcher/addEventListener"}}{{/crossLink}}).
- *
- * instance.addEventListener("eventName", handlerMethod);
- * function handlerMethod(event) {
- * console.log(event.target + " Was Clicked");
- * }
- *
- * Maintaining proper scope
- * Scope (ie. "this") can be be a challenge with events. Using the {{#crossLink "EventDispatcher/on"}}{{/crossLink}}
- * method to subscribe to events simplifies this.
- *
- * instance.addEventListener("click", function(event) {
- * console.log(instance == this); // false, scope is ambiguous.
- * });
- *
- * instance.on("click", function(event) {
- * console.log(instance == this); // true, "on" uses dispatcher scope by default.
- * });
- *
- * If you want to use addEventListener instead, you may want to use function.bind() or a similar proxy to manage
- * scope.
- *
- * Browser support
- * The event model in CreateJS can be used separately from the suite in any project, however the inheritance model
- * requires modern browsers (IE9+).
- *
- *
- * @class EventDispatcher
- * @constructor
- **/
- function EventDispatcher() {
-
-
- // private properties:
- /**
- * @protected
- * @property _listeners
- * @type Object
- **/
- this._listeners = null;
-
- /**
- * @protected
- * @property _captureListeners
- * @type Object
- **/
- this._captureListeners = null;
- }
- var p = EventDispatcher.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// static public methods:
- /**
- * Static initializer to mix EventDispatcher methods into a target object or prototype.
- *
- * EventDispatcher.initialize(MyClass.prototype); // add to the prototype of the class
- * EventDispatcher.initialize(myObject); // add to a specific instance
- *
- * @method initialize
- * @static
- * @param {Object} target The target object to inject EventDispatcher methods into. This can be an instance or a
- * prototype.
- **/
- EventDispatcher.initialize = function(target) {
- target.addEventListener = p.addEventListener;
- target.on = p.on;
- target.removeEventListener = target.off = p.removeEventListener;
- target.removeAllEventListeners = p.removeAllEventListeners;
- target.hasEventListener = p.hasEventListener;
- target.dispatchEvent = p.dispatchEvent;
- target._dispatchEvent = p._dispatchEvent;
- target.willTrigger = p.willTrigger;
- };
-
-
-// public methods:
- /**
- * Adds the specified event listener. Note that adding multiple listeners to the same function will result in
- * multiple callbacks getting fired.
- *
- *
Example
- *
- * displayObject.addEventListener("click", handleClick);
- * function handleClick(event) {
- * // Click happened.
- * }
- *
- * @method addEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function | Object} Returns the listener for chaining or assignment.
- **/
- p.addEventListener = function(type, listener, useCapture) {
- var listeners;
- if (useCapture) {
- listeners = this._captureListeners = this._captureListeners||{};
- } else {
- listeners = this._listeners = this._listeners||{};
- }
- var arr = listeners[type];
- if (arr) { this.removeEventListener(type, listener, useCapture); }
- arr = listeners[type]; // remove may have deleted the array
- if (!arr) { listeners[type] = [listener]; }
- else { arr.push(listener); }
- return listener;
- };
-
- /**
- * A shortcut method for using addEventListener that makes it easier to specify an execution scope, have a listener
- * only run once, associate arbitrary data with the listener, and remove the listener.
- *
- * This method works by creating an anonymous wrapper function and subscribing it with addEventListener.
- * The wrapper function is returned for use with `removeEventListener` (or `off`).
- *
- * IMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener, or use
- * {{#crossLink "Event/remove"}}{{/crossLink}}. Likewise, each time you call `on` a NEW wrapper function is subscribed, so multiple calls
- * to `on` with the same params will create multiple listeners.
- *
- *
Example
- *
- * var listener = myBtn.on("click", handleClick, null, false, {count:3});
- * function handleClick(evt, data) {
- * data.count -= 1;
- * console.log(this == myBtn); // true - scope defaults to the dispatcher
- * if (data.count == 0) {
- * alert("clicked 3 times!");
- * myBtn.off("click", listener);
- * // alternately: evt.remove();
- * }
- * }
- *
- * @method on
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener An object with a handleEvent method, or a function that will be called when
- * the event is dispatched.
- * @param {Object} [scope] The scope to execute the listener in. Defaults to the dispatcher/currentTarget for function listeners, and to the listener itself for object listeners (ie. using handleEvent).
- * @param {Boolean} [once=false] If true, the listener will remove itself after the first time it is triggered.
- * @param {*} [data] Arbitrary data that will be included as the second parameter when the listener is called.
- * @param {Boolean} [useCapture=false] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- * @return {Function} Returns the anonymous function that was created and assigned as the listener. This is needed to remove the listener later using .removeEventListener.
- **/
- p.on = function(type, listener, scope, once, data, useCapture) {
- if (listener.handleEvent) {
- scope = scope||listener;
- listener = listener.handleEvent;
- }
- scope = scope||this;
- return this.addEventListener(type, function(evt) {
- listener.call(scope, evt, data);
- once&&evt.remove();
- }, useCapture);
- };
-
- /**
- * Removes the specified event listener.
- *
- * Important Note: that you must pass the exact function reference used when the event was added. If a proxy
- * function, or function closure is used as the callback, the proxy/closure reference must be used - a new proxy or
- * closure will not work.
- *
- *
Example
- *
- * displayObject.removeEventListener("click", handleClick);
- *
- * @method removeEventListener
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.removeEventListener = function(type, listener, useCapture) {
- var listeners = useCapture ? this._captureListeners : this._listeners;
- if (!listeners) { return; }
- var arr = listeners[type];
- if (!arr) { return; }
- for (var i=0,l=arr.length; iIMPORTANT: To remove a listener added with `on`, you must pass in the returned wrapper function as the listener. See
- * {{#crossLink "EventDispatcher/on"}}{{/crossLink}} for an example.
- *
- * @method off
- * @param {String} type The string type of the event.
- * @param {Function | Object} listener The listener function or object.
- * @param {Boolean} [useCapture] For events that bubble, indicates whether to listen for the event in the capture or bubbling/target phase.
- **/
- p.off = p.removeEventListener;
-
- /**
- * Removes all listeners for the specified type, or all listeners of all types.
- *
- *
Example
- *
- * // Remove all listeners
- * displayObject.removeAllEventListeners();
- *
- * // Remove all click listeners
- * displayObject.removeAllEventListeners("click");
- *
- * @method removeAllEventListeners
- * @param {String} [type] The string type of the event. If omitted, all listeners for all types will be removed.
- **/
- p.removeAllEventListeners = function(type) {
- if (!type) { this._listeners = this._captureListeners = null; }
- else {
- if (this._listeners) { delete(this._listeners[type]); }
- if (this._captureListeners) { delete(this._captureListeners[type]); }
- }
- };
-
- /**
- * Dispatches the specified event to all listeners.
- *
- *
Example
- *
- * // Use a string event
- * this.dispatchEvent("complete");
- *
- * // Use an Event instance
- * var event = new createjs.Event("progress");
- * this.dispatchEvent(event);
- *
- * @method dispatchEvent
- * @param {Object | String | Event} eventObj An object with a "type" property, or a string type.
- * While a generic object will work, it is recommended to use a CreateJS Event instance. If a string is used,
- * dispatchEvent will construct an Event instance if necessary with the specified type. This latter approach can
- * be used to avoid event object instantiation for non-bubbling events that may not have any listeners.
- * @param {Boolean} [bubbles] Specifies the `bubbles` value when a string was passed to eventObj.
- * @param {Boolean} [cancelable] Specifies the `cancelable` value when a string was passed to eventObj.
- * @return {Boolean} Returns false if `preventDefault()` was called on a cancelable event, true otherwise.
- **/
- p.dispatchEvent = function(eventObj, bubbles, cancelable) {
- if (typeof eventObj == "string") {
- // skip everything if there's no listeners and it doesn't bubble:
- var listeners = this._listeners;
- if (!bubbles && (!listeners || !listeners[eventObj])) { return true; }
- eventObj = new createjs.Event(eventObj, bubbles, cancelable);
- } else if (eventObj.target && eventObj.clone) {
- // redispatching an active event object, so clone it:
- eventObj = eventObj.clone();
- }
-
- // TODO: it would be nice to eliminate this. Maybe in favour of evtObj instanceof Event? Or !!evtObj.createEvent
- try { eventObj.target = this; } catch (e) {} // try/catch allows redispatching of native events
-
- if (!eventObj.bubbles || !this.parent) {
- this._dispatchEvent(eventObj, 2);
- } else {
- var top=this, list=[top];
- while (top.parent) { list.push(top = top.parent); }
- var i, l=list.length;
-
- // capture & atTarget
- for (i=l-1; i>=0 && !eventObj.propagationStopped; i--) {
- list[i]._dispatchEvent(eventObj, 1+(i==0));
- }
- // bubbling
- for (i=1; i
- *
capture phase: starting from the top parent to the target
- *
at target phase: currently being dispatched from the target
- *
bubbling phase: from the target to the top parent
- *
- * @property eventPhase
- * @type Number
- * @default 0
- * @readonly
- */
- this.eventPhase = 0;
-
- /**
- * Indicates whether the event will bubble through the display list.
- * @property bubbles
- * @type Boolean
- * @default false
- * @readonly
- */
- this.bubbles = !!bubbles;
-
- /**
- * Indicates whether the default behaviour of this event can be cancelled via
- * {{#crossLink "Event/preventDefault"}}{{/crossLink}}. This is set via the Event constructor.
- * @property cancelable
- * @type Boolean
- * @default false
- * @readonly
- */
- this.cancelable = !!cancelable;
-
- /**
- * The epoch time at which this event was created.
- * @property timeStamp
- * @type Number
- * @default 0
- * @readonly
- */
- this.timeStamp = (new Date()).getTime();
-
- /**
- * Indicates if {{#crossLink "Event/preventDefault"}}{{/crossLink}} has been called
- * on this event.
- * @property defaultPrevented
- * @type Boolean
- * @default false
- * @readonly
- */
- this.defaultPrevented = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopPropagation"}}{{/crossLink}} or
- * {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called on this event.
- * @property propagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.propagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/stopImmediatePropagation"}}{{/crossLink}} has been called
- * on this event.
- * @property immediatePropagationStopped
- * @type Boolean
- * @default false
- * @readonly
- */
- this.immediatePropagationStopped = false;
-
- /**
- * Indicates if {{#crossLink "Event/remove"}}{{/crossLink}} has been called on this event.
- * @property removed
- * @type Boolean
- * @default false
- * @readonly
- */
- this.removed = false;
- }
- var p = Event.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-// public methods:
- /**
- * Sets {{#crossLink "Event/defaultPrevented"}}{{/crossLink}} to true if the event is cancelable.
- * Mirrors the DOM level 2 event standard. In general, cancelable events that have `preventDefault()` called will
- * cancel the default behaviour associated with the event.
- * @method preventDefault
- **/
- p.preventDefault = function() {
- this.defaultPrevented = this.cancelable&&true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopPropagation
- **/
- p.stopPropagation = function() {
- this.propagationStopped = true;
- };
-
- /**
- * Sets {{#crossLink "Event/propagationStopped"}}{{/crossLink}} and
- * {{#crossLink "Event/immediatePropagationStopped"}}{{/crossLink}} to true.
- * Mirrors the DOM event standard.
- * @method stopImmediatePropagation
- **/
- p.stopImmediatePropagation = function() {
- this.immediatePropagationStopped = this.propagationStopped = true;
- };
-
- /**
- * Causes the active listener to be removed via removeEventListener();
- *
- * myBtn.addEventListener("click", function(evt) {
- * // do stuff...
- * evt.remove(); // removes this listener.
- * });
- *
- * @method remove
- **/
- p.remove = function() {
- this.removed = true;
- };
-
- /**
- * Returns a clone of the Event instance.
- * @method clone
- * @return {Event} a clone of the Event instance.
- **/
- p.clone = function() {
- return new Event(this.type, this.bubbles, this.cancelable);
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the instance.
- * @return {Event} Returns the instance the method is called on (useful for chaining calls.)
- * @chainable
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- /**
- * Returns a string representation of this object.
- * @method toString
- * @return {String} a string representation of the instance.
- **/
- p.toString = function() {
- return "[Event (type="+this.type+")]";
- };
-
- createjs.Event = Event;
-}());
-
-//##############################################################################
-// ErrorEvent.js
-//##############################################################################
-
-this.createjs = this.createjs||{};
-
-(function() {
- "use strict";
-
- /**
- * A general error {{#crossLink "Event"}}{{/crossLink}}, that describes an error that occurred, as well as any details.
- * @class ErrorEvent
- * @param {String} [title] The error title
- * @param {String} [message] The error description
- * @param {Object} [data] Additional error data
- * @constructor
- */
- function ErrorEvent(title, message, data) {
- this.Event_constructor("error");
-
- /**
- * The short error title, which indicates the type of error that occurred.
- * @property title
- * @type String
- */
- this.title = title;
-
- /**
- * The verbose error message, containing details about the error.
- * @property message
- * @type String
- */
- this.message = message;
-
- /**
- * Additional data attached to an error.
- * @property data
- * @type {Object}
- */
- this.data = data;
- }
-
- var p = createjs.extend(ErrorEvent, createjs.Event);
-
- p.clone = function() {
- return new createjs.ErrorEvent(this.title, this.message, this.data);
- };
-
- createjs.ErrorEvent = createjs.promote(ErrorEvent, "Event");
-
-}());
-
-//##############################################################################
-// ProgressEvent.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function (scope) {
- "use strict";
-
- // constructor
- /**
- * A CreateJS {{#crossLink "Event"}}{{/crossLink}} that is dispatched when progress changes.
- * @class ProgressEvent
- * @param {Number} loaded The amount that has been loaded. This can be any number relative to the total.
- * @param {Number} [total=1] The total amount that will load. This will default to 1, so if the `loaded` value is
- * a percentage (between 0 and 1), it can be omitted.
- * @todo Consider having this event be a "fileprogress" event as well
- * @constructor
- */
- function ProgressEvent(loaded, total) {
- this.Event_constructor("progress");
-
- /**
- * The amount that has been loaded (out of a total amount)
- * @property loaded
- * @type {Number}
- */
- this.loaded = loaded;
-
- /**
- * The total "size" of the load.
- * @property total
- * @type {Number}
- * @default 1
- */
- this.total = (total == null) ? 1 : total;
-
- /**
- * The percentage (out of 1) that the load has been completed. This is calculated using `loaded/total`.
- * @property progress
- * @type {Number}
- * @default 0
- */
- this.progress = (total == 0) ? 0 : this.loaded / this.total;
- };
-
- var p = createjs.extend(ProgressEvent, createjs.Event);
-
- /**
- * Returns a clone of the ProgressEvent instance.
- * @method clone
- * @return {ProgressEvent} a clone of the Event instance.
- **/
- p.clone = function() {
- return new createjs.ProgressEvent(this.loaded, this.total);
- };
-
- createjs.ProgressEvent = createjs.promote(ProgressEvent, "Event");
-
-}(window));
-
-//##############################################################################
-// LoadItem.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * All loaders accept an item containing the properties defined in this class. If a raw object is passed instead,
- * it will not be affected, but it must contain at least a {{#crossLink "src:property"}}{{/crossLink}} property. A
- * string path or HTML tag is also acceptable, but it will be automatically converted to a LoadItem using the
- * {{#crossLink "create"}}{{/crossLink}} method by {{#crossLink "AbstractLoader"}}{{/crossLink}}
- * @class LoadItem
- * @constructor
- * @since 0.6.0
- */
- function LoadItem() {
- /**
- * The source of the file that is being loaded. This property is required. The source can either be a
- * string (recommended), or an HTML tag.
- * This can also be an object, but in that case it has to include a type and be handled by a plugin.
- * @property src
- * @type {String}
- * @default null
- */
- this.src = null;
-
- /**
- * The type file that is being loaded. The type of the file is usually inferred by the extension, but can also
- * be set manually. This is helpful in cases where a file does not have an extension.
- * @property type
- * @type {String}
- * @default null
- */
- this.type = null;
-
- /**
- * A string identifier which can be used to reference the loaded object. If none is provided, this will be
- * automatically set to the {{#crossLink "src:property"}}{{/crossLink}}.
- * @property id
- * @type {String}
- * @default null
- */
- this.id = null;
-
- /**
- * Determines if a manifest will maintain the order of this item, in relation to other items in the manifest
- * that have also set the `maintainOrder` property to `true`. This only applies when the max connections has
- * been set above 1 (using {{#crossLink "LoadQueue/setMaxConnections"}}{{/crossLink}}). Everything with this
- * property set to `false` will finish as it is loaded. Ordered items are combined with script tags loading in
- * order when {{#crossLink "LoadQueue/maintainScriptOrder:property"}}{{/crossLink}} is set to `true`.
- * @property maintainOrder
- * @type {Boolean}
- * @default false
- */
- this.maintainOrder = false;
-
- /**
- * A callback used by JSONP requests that defines what global method to call when the JSONP content is loaded.
- * @property callback
- * @type {String}
- * @default null
- */
- this.callback = null;
-
- /**
- * An arbitrary data object, which is included with the loaded object.
- * @property data
- * @type {Object}
- * @default null
- */
- this.data = null;
-
- /**
- * The request method used for HTTP calls. Both {{#crossLink "AbstractLoader/GET:property"}}{{/crossLink}} or
- * {{#crossLink "AbstractLoader/POST:property"}}{{/crossLink}} request types are supported, and are defined as
- * constants on {{#crossLink "AbstractLoader"}}{{/crossLink}}.
- * @property method
- * @type {String}
- * @default get
- */
- this.method = createjs.LoadItem.GET;
-
- /**
- * An object hash of name/value pairs to send to the server.
- * @property values
- * @type {Object}
- * @default null
- */
- this.values = null;
-
- /**
- * An object hash of headers to attach to an XHR request. PreloadJS will automatically attach some default
- * headers when required, including "Origin", "Content-Type", and "X-Requested-With". You may override the
- * default headers by including them in your headers object.
- * @property headers
- * @type {Object}
- * @default null
- */
- this.headers = null;
-
- /**
- * Enable credentials for XHR requests.
- * @property withCredentials
- * @type {Boolean}
- * @default false
- */
- this.withCredentials = false;
-
- /**
- * Set the mime type of XHR-based requests. This is automatically set to "text/plain; charset=utf-8" for text
- * based files (json, xml, text, css, js).
- * @property mimeType
- * @type {String}
- * @default null
- */
- this.mimeType = null;
-
- /**
- * Sets the crossOrigin attribute for CORS-enabled images loading cross-domain.
- * @property crossOrigin
- * @type {boolean}
- * @default Anonymous
- */
- this.crossOrigin = null;
-
- /**
- * The duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
- * (level one) loading, as XHR (level 2) provides its own timeout event.
- * @property loadTimeout
- * @type {Number}
- * @default 8000 (8 seconds)
- */
- this.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
- };
-
- var p = LoadItem.prototype = {};
- var s = LoadItem;
-
- /**
- * Default duration in milliseconds to wait before a request times out. This only applies to tag-based and and XHR
- * (level one) loading, as XHR (level 2) provides its own timeout event.
- * @property LOAD_TIMEOUT_DEFAULT
- * @type {number}
- * @static
- */
- s.LOAD_TIMEOUT_DEFAULT = 8000;
-
- /**
- * Create a LoadItem.
- *
- *
String-based items are converted to a LoadItem with a populated {{#crossLink "src:property"}}{{/crossLink}}.
- *
LoadItem instances are returned as-is
- *
Objects are returned with any needed properties added
- *
- * @method create
- * @param {LoadItem|String|Object} value The load item value
- * @returns {LoadItem|Object}
- * @static
- */
- s.create = function (value) {
- if (typeof value == "string") {
- var item = new LoadItem();
- item.src = value;
- return item;
- } else if (value instanceof s) {
- return value;
- } else if (value instanceof Object && value.src) {
- if (value.loadTimeout == null) {
- value.loadTimeout = s.LOAD_TIMEOUT_DEFAULT;
- }
- return value;
- } else {
- throw new Error("Type not recognized.");
- }
- };
-
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- *
Example
- *
- * var loadItem = new createjs.LoadItem().set({src:"image.png", maintainOrder:true});
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the LoadItem instance.
- * @return {LoadItem} Returns the instance the method is called on (useful for chaining calls.)
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- createjs.LoadItem = s;
-
-}());
-
-//##############################################################################
-// RequestUtils.js
-//##############################################################################
-
-(function () {
-
- /**
- * Utilities that assist with parsing load items, and determining file types, etc.
- * @class RequestUtils
- */
- var s = {};
-
- /**
- * The Regular Expression used to test file URLS for an absolute path.
- * @property ABSOLUTE_PATH
- * @type {RegExp}
- * @static
- */
- s.ABSOLUTE_PATT = /^(?:\w+:)?\/{2}/i;
-
- /**
- * The Regular Expression used to test file URLS for a relative path.
- * @property RELATIVE_PATH
- * @type {RegExp}
- * @static
- */
- s.RELATIVE_PATT = (/^[./]*?\//i);
-
- /**
- * The Regular Expression used to test file URLS for an extension. Note that URIs must already have the query string
- * removed.
- * @property EXTENSION_PATT
- * @type {RegExp}
- * @static
- */
- s.EXTENSION_PATT = /\/?[^/]+\.(\w{1,5})$/i;
-
- /**
- * Parse a file path to determine the information we need to work with it. Currently, PreloadJS needs to know:
- *
- *
If the path is absolute. Absolute paths start with a protocol (such as `http://`, `file://`, or
- * `//networkPath`)
- *
If the path is relative. Relative paths start with `../` or `/path` (or similar)
- *
The file extension. This is determined by the filename with an extension. Query strings are dropped, and
- * the file path is expected to follow the format `name.ext`.
- *
- * @method parseURI
- * @param {String} path
- * @returns {Object} An Object with an `absolute` and `relative` Boolean values, as well as an optional 'extension`
- * property, which is the lowercase extension.
- * @static
- */
- s.parseURI = function (path) {
- var info = {absolute: false, relative: false};
- if (path == null) { return info; }
-
- // Drop the query string
- var queryIndex = path.indexOf("?");
- if (queryIndex > -1) {
- path = path.substr(0, queryIndex);
- }
-
- // Absolute
- var match;
- if (s.ABSOLUTE_PATT.test(path)) {
- info.absolute = true;
-
- // Relative
- } else if (s.RELATIVE_PATT.test(path)) {
- info.relative = true;
- }
-
- // Extension
- if (match = path.match(s.EXTENSION_PATT)) {
- info.extension = match[1].toLowerCase();
- }
- return info;
- };
-
- /**
- * Formats an object into a query string for either a POST or GET request.
- * @method formatQueryString
- * @param {Object} data The data to convert to a query string.
- * @param {Array} [query] Existing name/value pairs to append on to this query.
- * @static
- */
- s.formatQueryString = function (data, query) {
- if (data == null) {
- throw new Error('You must specify data.');
- }
- var params = [];
- for (var n in data) {
- params.push(n + '=' + escape(data[n]));
- }
- if (query) {
- params = params.concat(query);
- }
- return params.join('&');
- };
-
- /**
- * A utility method that builds a file path using a source and a data object, and formats it into a new path.
- * @method buildPath
- * @param {String} src The source path to add values to.
- * @param {Object} [data] Object used to append values to this request as a query string. Existing parameters on the
- * path will be preserved.
- * @returns {string} A formatted string that contains the path and the supplied parameters.
- * @static
- */
- s.buildPath = function (src, data) {
- if (data == null) {
- return src;
- }
-
- var query = [];
- var idx = src.indexOf('?');
-
- if (idx != -1) {
- var q = src.slice(idx + 1);
- query = query.concat(q.split('&'));
- }
-
- if (idx != -1) {
- return src.slice(0, idx) + '?' + this.formatQueryString(data, query);
- } else {
- return src + '?' + this.formatQueryString(data, query);
- }
- };
-
- /**
- * @method isCrossDomain
- * @param {LoadItem|Object} item A load item with a `src` property.
- * @return {Boolean} If the load item is loading from a different domain than the current location.
- * @static
- */
- s.isCrossDomain = function (item) {
- var target = document.createElement("a");
- target.href = item.src;
-
- var host = document.createElement("a");
- host.href = location.href;
-
- var crossdomain = (target.hostname != "") &&
- (target.port != host.port ||
- target.protocol != host.protocol ||
- target.hostname != host.hostname);
- return crossdomain;
- };
-
- /**
- * @method isLocal
- * @param {LoadItem|Object} item A load item with a `src` property
- * @return {Boolean} If the load item is loading from the "file:" protocol. Assume that the host must be local as
- * well.
- * @static
- */
- s.isLocal = function (item) {
- var target = document.createElement("a");
- target.href = item.src;
- return target.hostname == "" && target.protocol == "file:";
- };
-
- /**
- * Determine if a specific type should be loaded as a binary file. Currently, only images and items marked
- * specifically as "binary" are loaded as binary. Note that audio is not a binary type, as we can not play
- * back using an audio tag if it is loaded as binary. Plugins can change the item type to binary to ensure they get
- * a binary result to work with. Binary files are loaded using XHR2. Types are defined as static constants on
- * {{#crossLink "AbstractLoader"}}{{/crossLink}}.
- * @method isBinary
- * @param {String} type The item type.
- * @return {Boolean} If the specified type is binary.
- * @static
- */
- s.isBinary = function (type) {
- switch (type) {
- case createjs.AbstractLoader.IMAGE:
- case createjs.AbstractLoader.BINARY:
- return true;
- default:
- return false;
- }
- };
-
- /**
- * Check if item is a valid HTMLImageElement
- * @method isImageTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isImageTag = function(item) {
- return item instanceof HTMLImageElement;
- };
-
- /**
- * Check if item is a valid HTMLAudioElement
- * @method isAudioTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isAudioTag = function(item) {
- if (window.HTMLAudioElement) {
- return item instanceof HTMLAudioElement;
- } else {
- return false;
- }
- };
-
- /**
- * Check if item is a valid HTMLVideoElement
- * @method isVideoTag
- * @param {Object} item
- * @returns {Boolean}
- * @static
- */
- s.isVideoTag = function(item) {
- if (window.HTMLVideoElement) {
- return item instanceof HTMLVideoElement;
- } else {
- return false;
- }
- };
-
- /**
- * Determine if a specific type is a text-based asset, and should be loaded as UTF-8.
- * @method isText
- * @param {String} type The item type.
- * @return {Boolean} If the specified type is text.
- * @static
- */
- s.isText = function (type) {
- switch (type) {
- case createjs.AbstractLoader.TEXT:
- case createjs.AbstractLoader.JSON:
- case createjs.AbstractLoader.MANIFEST:
- case createjs.AbstractLoader.XML:
- case createjs.AbstractLoader.CSS:
- case createjs.AbstractLoader.SVG:
- case createjs.AbstractLoader.JAVASCRIPT:
- case createjs.AbstractLoader.SPRITESHEET:
- return true;
- default:
- return false;
- }
- };
-
- /**
- * Determine the type of the object using common extensions. Note that the type can be passed in with the load item
- * if it is an unusual extension.
- * @method getTypeByExtension
- * @param {String} extension The file extension to use to determine the load type.
- * @return {String} The determined load type (for example, AbstractLoader.IMAGE). Will return `null` if
- * the type can not be determined by the extension.
- * @static
- */
- s.getTypeByExtension = function (extension) {
- if (extension == null) {
- return createjs.AbstractLoader.TEXT;
- }
-
- switch (extension.toLowerCase()) {
- case "jpeg":
- case "jpg":
- case "gif":
- case "png":
- case "webp":
- case "bmp":
- return createjs.AbstractLoader.IMAGE;
- case "ogg":
- case "mp3":
- case "webm":
- return createjs.AbstractLoader.SOUND;
- case "mp4":
- case "webm":
- case "ts":
- return createjs.AbstractLoader.VIDEO;
- case "json":
- return createjs.AbstractLoader.JSON;
- case "xml":
- return createjs.AbstractLoader.XML;
- case "css":
- return createjs.AbstractLoader.CSS;
- case "js":
- return createjs.AbstractLoader.JAVASCRIPT;
- case 'svg':
- return createjs.AbstractLoader.SVG;
- default:
- return createjs.AbstractLoader.TEXT;
- }
- };
-
- createjs.RequestUtils = s;
-
-}());
-
-//##############################################################################
-// AbstractLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-// constructor
- /**
- * The base loader, which defines all the generic methods, properties, and events. All loaders extend this class,
- * including the {{#crossLink "LoadQueue"}}{{/crossLink}}.
- * @class AbstractLoader
- * @param {LoadItem|object|string} loadItem The item to be loaded.
- * @param {Boolean} [preferXHR] Determines if the LoadItem should try and load using XHR, or take a
- * tag-based approach, which can be better in cross-domain situations. Not all loaders can load using one or the
- * other, so this is a suggested directive.
- * @param {String} [type] The type of loader. Loader types are defined as constants on the AbstractLoader class,
- * such as {{#crossLink "IMAGE:property"}}{{/crossLink}}, {{#crossLink "CSS:property"}}{{/crossLink}}, etc.
- * @extends EventDispatcher
- */
- function AbstractLoader(loadItem, preferXHR, type) {
- this.EventDispatcher_constructor();
-
- // public properties
- /**
- * If the loader has completed loading. This provides a quick check, but also ensures that the different approaches
- * used for loading do not pile up resulting in more than one `complete` {{#crossLink "Event"}}{{/crossLink}}.
- * @property loaded
- * @type {Boolean}
- * @default false
- */
- this.loaded = false;
-
- /**
- * Determine if the loader was canceled. Canceled loads will not fire complete events. Note that this property
- * is readonly, so {{#crossLink "LoadQueue"}}{{/crossLink}} queues should be closed using {{#crossLink "LoadQueue/close"}}{{/crossLink}}
- * instead.
- * @property canceled
- * @type {Boolean}
- * @default false
- * @readonly
- */
- this.canceled = false;
-
- /**
- * The current load progress (percentage) for this item. This will be a number between 0 and 1.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.loadFile("largeImage.png");
- * queue.on("progress", function() {
- * console.log("Progress:", queue.progress, event.progress);
- * });
- *
- * @property progress
- * @type {Number}
- * @default 0
- */
- this.progress = 0;
-
- /**
- * The type of item this loader will load. See {{#crossLink "AbstractLoader"}}{{/crossLink}} for a full list of
- * supported types.
- * @property type
- * @type {String}
- */
- this.type = type;
-
- /**
- * A formatter function that converts the loaded raw result into the final result. For example, the JSONLoader
- * converts a string of text into a JavaScript object. Not all loaders have a resultFormatter, and this property
- * can be overridden to provide custom formatting.
- *
- * Optionally, a resultFormatter can return a callback function in cases where the formatting needs to be
- * asynchronous, such as creating a new image. The callback function is passed 2 parameters, which are callbacks
- * to handle success and error conditions in the resultFormatter. Note that the resultFormatter method is
- * called in the current scope, as well as the success and error callbacks.
- *
- *
Example asynchronous resultFormatter
- *
- * function _formatResult(loader) {
- * return function(success, error) {
- * if (errorCondition) { error(errorDetailEvent); }
- * success(result);
- * }
- * }
- * @property resultFormatter
- * @type {Function}
- * @default null
- */
- this.resultFormatter = null;
-
- // protected properties
- /**
- * The {{#crossLink "LoadItem"}}{{/crossLink}} this loader represents. Note that this is null in a {{#crossLink "LoadQueue"}}{{/crossLink}},
- * but will be available on loaders such as {{#crossLink "XMLLoader"}}{{/crossLink}} and {{#crossLink "ImageLoader"}}{{/crossLink}}.
- * @property _item
- * @type {LoadItem|Object}
- * @private
- */
- if (loadItem) {
- this._item = createjs.LoadItem.create(loadItem);
- } else {
- this._item = null;
- }
-
- /**
- * Whether the loader will try and load content using XHR (true) or HTML tags (false).
- * @property _preferXHR
- * @type {Boolean}
- * @private
- */
- this._preferXHR = preferXHR;
-
- /**
- * The loaded result after it is formatted by an optional {{#crossLink "resultFormatter"}}{{/crossLink}}. For
- * items that are not formatted, this will be the same as the {{#crossLink "_rawResult:property"}}{{/crossLink}}.
- * The result is accessed using the {{#crossLink "getResult"}}{{/crossLink}} method.
- * @property _result
- * @type {Object|String}
- * @private
- */
- this._result = null;
-
- /**
- * The loaded result before it is formatted. The rawResult is accessed using the {{#crossLink "getResult"}}{{/crossLink}}
- * method, and passing `true`.
- * @property _rawResult
- * @type {Object|String}
- * @private
- */
- this._rawResult = null;
-
- /**
- * A list of items that loaders load behind the scenes. This does not include the main item the loader is
- * responsible for loading. Examples of loaders that have sub-items include the {{#crossLink "SpriteSheetLoader"}}{{/crossLink}} and
- * {{#crossLink "ManifestLoader"}}{{/crossLink}}.
- * @property _loadItems
- * @type {null}
- * @protected
- */
- this._loadedItems = null;
-
- /**
- * The attribute the items loaded using tags use for the source.
- * @type {string}
- * @default null
- * @private
- */
- this._tagSrcAttribute = null;
-
- /**
- * An HTML tag (or similar) that a loader may use to load HTML content, such as images, scripts, etc.
- * @property _tag
- * @type {Object}
- * @private
- */
- this._tag = null;
- };
-
- var p = createjs.extend(AbstractLoader, createjs.EventDispatcher);
- var s = AbstractLoader;
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
- /**
- * Defines a POST request, use for a method value when loading data.
- * @property POST
- * @type {string}
- * @default post
- * @static
- */
- s.POST = "POST";
-
- /**
- * Defines a GET request, use for a method value when loading data.
- * @property GET
- * @type {string}
- * @default get
- * @static
- */
- s.GET = "GET";
-
- /**
- * The preload type for generic binary types. Note that images are loaded as binary files when using XHR.
- * @property BINARY
- * @type {String}
- * @default binary
- * @static
- * @since 0.6.0
- */
- s.BINARY = "binary";
-
- /**
- * The preload type for css files. CSS files are loaded using a <link> when loaded with XHR, or a
- * <style> tag when loaded with tags.
- * @property CSS
- * @type {String}
- * @default css
- * @static
- * @since 0.6.0
- */
- s.CSS = "css";
-
- /**
- * The preload type for image files, usually png, gif, or jpg/jpeg. Images are loaded into an <image> tag.
- * @property IMAGE
- * @type {String}
- * @default image
- * @static
- * @since 0.6.0
- */
- s.IMAGE = "image";
-
- /**
- * The preload type for javascript files, usually with the "js" file extension. JavaScript files are loaded into a
- * <script> tag.
- *
- * Since version 0.4.1+, due to how tag-loaded scripts work, all JavaScript files are automatically injected into
- * the body of the document to maintain parity between XHR and tag-loaded scripts. In version 0.4.0 and earlier,
- * only tag-loaded scripts are injected.
- * @property JAVASCRIPT
- * @type {String}
- * @default javascript
- * @static
- * @since 0.6.0
- */
- s.JAVASCRIPT = "javascript";
-
- /**
- * The preload type for json files, usually with the "json" file extension. JSON data is loaded and parsed into a
- * JavaScript object. Note that if a `callback` is present on the load item, the file will be loaded with JSONP,
- * no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to, and the JSON
- * must contain a matching wrapper function.
- * @property JSON
- * @type {String}
- * @default json
- * @static
- * @since 0.6.0
- */
- s.JSON = "json";
-
- /**
- * The preload type for jsonp files, usually with the "json" file extension. JSON data is loaded and parsed into a
- * JavaScript object. You are required to pass a callback parameter that matches the function wrapper in the JSON.
- * Note that JSONP will always be used if there is a callback present, no matter what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}}
- * property is set to.
- * @property JSONP
- * @type {String}
- * @default jsonp
- * @static
- * @since 0.6.0
- */
- s.JSONP = "jsonp";
-
- /**
- * The preload type for json-based manifest files, usually with the "json" file extension. The JSON data is loaded
- * and parsed into a JavaScript object. PreloadJS will then look for a "manifest" property in the JSON, which is an
- * Array of files to load, following the same format as the {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}
- * method. If a "callback" is specified on the manifest object, then it will be loaded using JSONP instead,
- * regardless of what the {{#crossLink "LoadQueue/preferXHR:property"}}{{/crossLink}} property is set to.
- * @property MANIFEST
- * @type {String}
- * @default manifest
- * @static
- * @since 0.6.0
- */
- s.MANIFEST = "manifest";
-
- /**
- * The preload type for sound files, usually mp3, ogg, or wav. When loading via tags, audio is loaded into an
- * <audio> tag.
- * @property SOUND
- * @type {String}
- * @default sound
- * @static
- * @since 0.6.0
- */
- s.SOUND = "sound";
-
- /**
- * The preload type for video files, usually mp4, ts, or ogg. When loading via tags, video is loaded into an
- * <video> tag.
- * @property VIDEO
- * @type {String}
- * @default video
- * @static
- * @since 0.6.0
- */
- s.VIDEO = "video";
-
- /**
- * The preload type for SpriteSheet files. SpriteSheet files are JSON files that contain string image paths.
- * @property SPRITESHEET
- * @type {String}
- * @default spritesheet
- * @static
- * @since 0.6.0
- */
- s.SPRITESHEET = "spritesheet";
-
- /**
- * The preload type for SVG files.
- * @property SVG
- * @type {String}
- * @default svg
- * @static
- * @since 0.6.0
- */
- s.SVG = "svg";
-
- /**
- * The preload type for text files, which is also the default file type if the type can not be determined. Text is
- * loaded as raw text.
- * @property TEXT
- * @type {String}
- * @default text
- * @static
- * @since 0.6.0
- */
- s.TEXT = "text";
-
- /**
- * The preload type for xml files. XML is loaded into an XML document.
- * @property XML
- * @type {String}
- * @default xml
- * @static
- * @since 0.6.0
- */
- s.XML = "xml";
-
-// Events
- /**
- * The {{#crossLink "ProgressEvent"}}{{/crossLink}} that is fired when the overall progress changes. Prior to
- * version 0.6.0, this was just a regular {{#crossLink "Event"}}{{/crossLink}}.
- * @event progress
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a load starts.
- * @event loadstart
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.3.1
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the entire queue has been loaded.
- * @event complete
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "ErrorEvent"}}{{/crossLink}} that is fired when the loader encounters an error. If the error was
- * encountered by a file, the event will contain the item that caused the error. Prior to version 0.6.0, this was
- * just a regular {{#crossLink "Event"}}{{/crossLink}}.
- * @event error
- * @since 0.3.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when the loader encounters an internal file load error.
- * This enables loaders to maintain internal queues, and surface file load errors.
- * @event fileerror
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The even type ("fileerror")
- * @param {LoadItem|object} The item that encountered the error
- * @since 0.6.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired when a loader internally loads a file. This enables
- * loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}} to maintain internal {{#crossLink "LoadQueue"}}{{/crossLink}}s
- * and notify when they have loaded a file. The {{#crossLink "LoadQueue"}}{{/crossLink}} class dispatches a
- * slightly different {{#crossLink "LoadQueue/fileload:event"}}{{/crossLink}} event.
- * @event fileload
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type ("fileload")
- * @param {Object} item The file item which was specified in the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * or {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}} call. If only a string path or tag was specified, the
- * object will contain that value as a `src` property.
- * @param {Object} result The HTML tag or parsed result of the loaded item.
- * @param {Object} rawResult The unprocessed result, usually the raw text or binary data before it is converted
- * to a usable object.
- * @since 0.6.0
- */
-
- /**
- * The {{#crossLink "Event"}}{{/crossLink}} that is fired after the internal request is created, but before a load.
- * This allows updates to the loader for specific loading needs, such as binary or XHR image loading.
- * @event initialize
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type ("initialize")
- * @param {AbstractLoader} loader The loader that has been initialized.
- */
-
-
- /**
- * Get a reference to the manifest item that is loaded by this loader. In some cases this will be the value that was
- * passed into {{#crossLink "LoadQueue"}}{{/crossLink}} using {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}} or
- * {{#crossLink "LoadQueue/loadManifest"}}{{/crossLink}}. However if only a String path was passed in, then it will
- * be a {{#crossLink "LoadItem"}}{{/crossLink}}.
- * @method getItem
- * @return {Object} The manifest item that this loader is responsible for loading.
- * @since 0.6.0
- */
- p.getItem = function () {
- return this._item;
- };
-
- /**
- * Get a reference to the content that was loaded by the loader (only available after the {{#crossLink "complete:event"}}{{/crossLink}}
- * event is dispatched.
- * @method getResult
- * @param {Boolean} [raw=false] Determines if the returned result will be the formatted content, or the raw loaded
- * data (if it exists).
- * @return {Object}
- * @since 0.6.0
- */
- p.getResult = function (raw) {
- return raw ? this._rawResult : this._result;
- };
-
- /**
- * Return the `tag` this object creates or uses for loading.
- * @method getTag
- * @return {Object} The tag instance
- * @since 0.6.0
- */
- p.getTag = function () {
- return this._tag;
- };
-
- /**
- * Set the `tag` this item uses for loading.
- * @method setTag
- * @param {Object} tag The tag instance
- * @since 0.6.0
- */
- p.setTag = function(tag) {
- this._tag = tag;
- };
-
- /**
- * Begin loading the item. This method is required when using a loader by itself.
- *
- *
Example
- *
- * var queue = new createjs.LoadQueue();
- * queue.on("complete", handleComplete);
- * queue.loadManifest(fileArray, false); // Note the 2nd argument that tells the queue not to start loading yet
- * queue.load();
- *
- * @method load
- */
- p.load = function () {
- this._createRequest();
-
- this._request.on("complete", this, this);
- this._request.on("progress", this, this);
- this._request.on("loadStart", this, this);
- this._request.on("abort", this, this);
- this._request.on("timeout", this, this);
- this._request.on("error", this, this);
-
- var evt = new createjs.Event("initialize");
- evt.loader = this._request;
- this.dispatchEvent(evt);
-
- this._request.load();
- };
-
- /**
- * Close the the item. This will stop any open requests (although downloads using HTML tags may still continue in
- * the background), but events will not longer be dispatched.
- * @method cancel
- */
- p.cancel = function () {
- this.canceled = true;
- this.destroy();
- };
-
- /**
- * Clean up the loader.
- * @method destroy
- */
- p.destroy = function() {
- if (this._request) {
- this._request.removeAllEventListeners();
- this._request.destroy();
- }
-
- this._request = null;
-
- this._item = null;
- this._rawResult = null;
- this._result = null;
-
- this._loadItems = null;
-
- this.removeAllEventListeners();
- };
-
- /**
- * Get any items loaded internally by the loader. The enables loaders such as {{#crossLink "ManifestLoader"}}{{/crossLink}}
- * to expose items it loads internally.
- * @method getLoadedItems
- * @return {Array} A list of the items loaded by the loader.
- * @since 0.6.0
- */
- p.getLoadedItems = function () {
- return this._loadedItems;
- };
-
-
- // Private methods
- /**
- * Create an internal request used for loading. By default, an {{#crossLink "XHRRequest"}}{{/crossLink}} or
- * {{#crossLink "TagRequest"}}{{/crossLink}} is created, depending on the value of {{#crossLink "preferXHR:property"}}{{/crossLink}}.
- * Other loaders may override this to use different request types, such as {{#crossLink "ManifestLoader"}}{{/crossLink}},
- * which uses {{#crossLink "JSONLoader"}}{{/crossLink}} or {{#crossLink "JSONPLoader"}}{{/crossLink}} under the hood.
- * @method _createRequest
- * @protected
- */
- p._createRequest = function() {
- if (!this._preferXHR) {
- this._request = new createjs.TagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
- } else {
- this._request = new createjs.XHRRequest(this._item);
- }
- };
-
- /**
- * Create the HTML tag used for loading. This method does nothing by default, and needs to be implemented
- * by loaders that require tag loading.
- * @method _createTag
- * @param {String} src The tag source
- * @return {HTMLElement} The tag that was created
- * @protected
- */
- p._createTag = function(src) { return null; };
-
- /**
- * Dispatch a loadstart {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/loadstart:event"}}{{/crossLink}}
- * event for details on the event payload.
- * @method _sendLoadStart
- * @protected
- */
- p._sendLoadStart = function () {
- if (this._isCanceled()) { return; }
- this.dispatchEvent("loadstart");
- };
-
- /**
- * Dispatch a {{#crossLink "ProgressEvent"}}{{/crossLink}}.
- * @method _sendProgress
- * @param {Number | Object} value The progress of the loaded item, or an object containing loaded
- * and total properties.
- * @protected
- */
- p._sendProgress = function (value) {
- if (this._isCanceled()) { return; }
- var event = null;
- if (typeof(value) == "number") {
- this.progress = value;
- event = new createjs.ProgressEvent(this.progress);
- } else {
- event = value;
- this.progress = value.loaded / value.total;
- event.progress = this.progress;
- if (isNaN(this.progress) || this.progress == Infinity) { this.progress = 0; }
- }
- this.hasEventListener("progress") && this.dispatchEvent(event);
- };
-
- /**
- * Dispatch a complete {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/complete:event"}}{{/crossLink}} event
- * @method _sendComplete
- * @protected
- */
- p._sendComplete = function () {
- if (this._isCanceled()) { return; }
-
- this.loaded = true;
-
- var event = new createjs.Event("complete");
- event.rawResult = this._rawResult;
-
- if (this._result != null) {
- event.result = this._result;
- }
-
- this.dispatchEvent(event);
- };
-
- /**
- * Dispatch an error {{#crossLink "Event"}}{{/crossLink}}. Please see the {{#crossLink "AbstractLoader/error:event"}}{{/crossLink}}
- * event for details on the event payload.
- * @method _sendError
- * @param {ErrorEvent} event The event object containing specific error properties.
- * @protected
- */
- p._sendError = function (event) {
- if (this._isCanceled() || !this.hasEventListener("error")) { return; }
- if (event == null) {
- event = new createjs.ErrorEvent("PRELOAD_ERROR_EMPTY"); // TODO: Populate error
- }
- this.dispatchEvent(event);
- };
-
- /**
- * Determine if the load has been canceled. This is important to ensure that method calls or asynchronous events
- * do not cause issues after the queue has been cleaned up.
- * @method _isCanceled
- * @return {Boolean} If the loader has been canceled.
- * @protected
- */
- p._isCanceled = function () {
- if (window.createjs == null || this.canceled) {
- return true;
- }
- return false;
- };
-
- /**
- * A custom result formatter function, which is called just before a request dispatches its complete event. Most
- * loader types already have an internal formatter, but this can be user-overridden for custom formatting. The
- * formatted result will be available on Loaders using {{#crossLink "getResult"}}{{/crossLink}}, and passing `true`.
- * @property resultFormatter
- * @type Function
- * @return {Object} The formatted result
- * @since 0.6.0
- */
- p.resultFormatter = null;
-
- /**
- * Handle events from internal requests. By default, loaders will handle, and redispatch the necessary events, but
- * this method can be overridden for custom behaviours.
- * @method handleEvent
- * @param {Event} event The event that the internal request dispatches.
- * @protected
- * @since 0.6.0
- */
- p.handleEvent = function (event) {
- switch (event.type) {
- case "complete":
- this._rawResult = event.target._response;
- var result = this.resultFormatter && this.resultFormatter(this);
- if (result instanceof Function) {
- result.call(this,
- createjs.proxy(this._resultFormatSuccess, this),
- createjs.proxy(this._resultFormatFailed, this)
- );
- } else {
- this._result = result || this._rawResult;
- this._sendComplete();
- }
- break;
- case "progress":
- this._sendProgress(event);
- break;
- case "error":
- this._sendError(event);
- break;
- case "loadstart":
- this._sendLoadStart();
- break;
- case "abort":
- case "timeout":
- if (!this._isCanceled()) {
- this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_" + event.type.toUpperCase() + "_ERROR"));
- }
- break;
- }
- };
-
- /**
- * The "success" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
- * functions.
- * @method _resultFormatSuccess
- * @param {Object} result The formatted result
- * @private
- */
- p._resultFormatSuccess = function (result) {
- this._result = result;
- this._sendComplete();
- };
-
- /**
- * The "error" callback passed to {{#crossLink "AbstractLoader/resultFormatter"}}{{/crossLink}} asynchronous
- * functions.
- * @method _resultFormatSuccess
- * @param {Object} error The error event
- * @private
- */
- p._resultFormatFailed = function (event) {
- this._sendError(event);
- };
-
- /**
- * @method buildPath
- * @protected
- * @deprecated Use the {{#crossLink "RequestUtils"}}{{/crossLink}} method {{#crossLink "RequestUtils/buildPath"}}{{/crossLink}}
- * instead.
- */
- p.buildPath = function (src, data) {
- return createjs.RequestUtils.buildPath(src, data);
- };
-
- /**
- * @method toString
- * @return {String} a string representation of the instance.
- */
- p.toString = function () {
- return "[PreloadJS AbstractLoader]";
- };
-
- createjs.AbstractLoader = createjs.promote(AbstractLoader, "EventDispatcher");
-
-}());
-
-//##############################################################################
-// AbstractMediaLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * The AbstractMediaLoader is a base class that handles some of the shared methods and properties of loaders that
- * handle HTML media elements, such as Video and Audio.
- * @class AbstractMediaLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @param {String} type The type of media to load. Usually "video" or "audio".
- * @extends AbstractLoader
- * @constructor
- */
- function AbstractMediaLoader(loadItem, preferXHR, type) {
- this.AbstractLoader_constructor(loadItem, preferXHR, type);
-
- // public properties
- this.resultFormatter = this._formatResult;
-
- // protected properties
- this._tagSrcAttribute = "src";
-
- this.on("initialize", this._updateXHR, this);
- };
-
- var p = createjs.extend(AbstractMediaLoader, createjs.AbstractLoader);
-
- // static properties
- // public methods
- p.load = function () {
- // TagRequest will handle most of this, but Sound / Video need a few custom properties, so just handle them here.
- if (!this._tag) {
- this._tag = this._createTag(this._item.src);
- }
-
- this._tag.preload = "auto";
- this._tag.load();
-
- this.AbstractLoader_load();
- };
-
- // protected methods
- /**
- * Creates a new tag for loading if it doesn't exist yet.
- * @method _createTag
- * @private
- */
- p._createTag = function () {};
-
-
- p._createRequest = function() {
- if (!this._preferXHR) {
- this._request = new createjs.MediaTagRequest(this._item, this._tag || this._createTag(), this._tagSrcAttribute);
- } else {
- this._request = new createjs.XHRRequest(this._item);
- }
- };
-
- // protected methods
- /**
- * Before the item loads, set its mimeType and responseType.
- * @property _updateXHR
- * @param {Event} event
- * @private
- */
- p._updateXHR = function (event) {
- // Only exists for XHR
- if (event.loader.setResponseType) {
- event.loader.setResponseType("blob");
- }
- };
-
- /**
- * The result formatter for media files.
- * @method _formatResult
- * @param {AbstractLoader} loader
- * @returns {HTMLVideoElement|HTMLAudioElement}
- * @private
- */
- p._formatResult = function (loader) {
- this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
- this._tag.onstalled = null;
- if (this._preferXHR) {
- var URL = window.URL || window.webkitURL;
- var result = loader.getResult(true);
-
- loader.getTag().src = URL.createObjectURL(result);
- }
- return loader.getTag();
- };
-
- createjs.AbstractMediaLoader = createjs.promote(AbstractMediaLoader, "AbstractLoader");
-
-}());
-
-//##############################################################################
-// AbstractRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * A base class for actual data requests, such as {{#crossLink "XHRRequest"}}{{/crossLink}}, {{#crossLink "TagRequest"}}{{/crossLink}},
- * and {{#crossLink "MediaRequest"}}{{/crossLink}}. PreloadJS loaders will typically use a data loader under the
- * hood to get data.
- * @class AbstractRequest
- * @param {LoadItem} item
- * @constructor
- */
- var AbstractRequest = function (item) {
- this._item = item;
- };
-
- var p = createjs.extend(AbstractRequest, createjs.EventDispatcher);
-
- // public methods
- /**
- * Begin a load.
- * @method load
- */
- p.load = function() {};
-
- /**
- * Clean up a request.
- * @method destroy
- */
- p.destroy = function() {};
-
- /**
- * Cancel an in-progress request.
- * @method cancel
- */
- p.cancel = function() {};
-
- createjs.AbstractRequest = createjs.promote(AbstractRequest, "EventDispatcher");
-
-}());
-
-//##############################################################################
-// TagRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * An {{#crossLink "AbstractRequest"}}{{/crossLink}} that loads HTML tags, such as images and scripts.
- * @class TagRequest
- * @param {LoadItem} loadItem
- * @param {HTMLElement} tag
- * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
- */
- function TagRequest(loadItem, tag, srcAttribute) {
- this.AbstractRequest_constructor(loadItem);
-
- // protected properties
- /**
- * The HTML tag instance that is used to load.
- * @property _tag
- * @type {HTMLElement}
- * @protected
- */
- this._tag = tag;
-
- /**
- * The tag attribute that specifies the source, such as "src", "href", etc.
- * @property _tagSrcAttribute
- * @type {String}
- * @protected
- */
- this._tagSrcAttribute = srcAttribute;
-
- /**
- * A method closure used for handling the tag load event.
- * @property _loadedHandler
- * @type {Function}
- * @private
- */
- this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
-
- /**
- * Determines if the element was added to the DOM automatically by PreloadJS, so it can be cleaned up after.
- * @property _addedToDOM
- * @type {Boolean}
- * @private
- */
- this._addedToDOM = false;
-
- /**
- * Determines what the tags initial style.visibility was, so we can set it correctly after a load.
- *
- * @type {null}
- * @private
- */
- this._startTagVisibility = null;
- };
-
- var p = createjs.extend(TagRequest, createjs.AbstractRequest);
-
- // public methods
- p.load = function () {
- this._tag.onload = createjs.proxy(this._handleTagComplete, this);
- this._tag.onreadystatechange = createjs.proxy(this._handleReadyStateChange, this);
- this._tag.onerror = createjs.proxy(this._handleError, this);
-
- var evt = new createjs.Event("initialize");
- evt.loader = this._tag;
-
- this.dispatchEvent(evt);
-
- this._hideTag();
-
- this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
-
- this._tag[this._tagSrcAttribute] = this._item.src;
-
- // wdg:: Append the tag AFTER setting the src, or SVG loading on iOS will fail.
- if (this._tag.parentNode == null) {
- window.document.body.appendChild(this._tag);
- this._addedToDOM = true;
- }
- };
-
- p.destroy = function() {
- this._clean();
- this._tag = null;
-
- this.AbstractRequest_destroy();
- };
-
- // private methods
- /**
- * Handle the readyStateChange event from a tag. We need this in place of the `onload` callback (mainly SCRIPT
- * and LINK tags), but other cases may exist.
- * @method _handleReadyStateChange
- * @private
- */
- p._handleReadyStateChange = function () {
- clearTimeout(this._loadTimeout);
- // This is strictly for tags in browsers that do not support onload.
- var tag = this._tag;
-
- // Complete is for old IE support.
- if (tag.readyState == "loaded" || tag.readyState == "complete") {
- this._handleTagComplete();
- }
- };
-
- /**
- * Handle any error events from the tag.
- * @method _handleError
- * @protected
- */
- p._handleError = function() {
- this._clean();
- this.dispatchEvent("error");
- };
-
- /**
- * Handle the tag's onload callback.
- * @method _handleTagComplete
- * @private
- */
- p._handleTagComplete = function () {
- this._rawResult = this._tag;
- this._result = this.resultFormatter && this.resultFormatter(this) || this._rawResult;
-
- this._clean();
- this._showTag();
-
- this.dispatchEvent("complete");
- };
-
- /**
- * The tag request has not loaded within the time specified in loadTimeout.
- * @method _handleError
- * @param {Object} event The XHR error event.
- * @private
- */
- p._handleTimeout = function () {
- this._clean();
- this.dispatchEvent(new createjs.Event("timeout"));
- };
-
- /**
- * Remove event listeners, but don't destroy the request object
- * @method _clean
- * @private
- */
- p._clean = function() {
- this._tag.onload = null;
- this._tag.onreadystatechange = null;
- this._tag.onerror = null;
- if (this._addedToDOM && this._tag.parentNode != null) {
- this._tag.parentNode.removeChild(this._tag);
- }
- clearTimeout(this._loadTimeout);
- };
-
- p._hideTag = function() {
- this._startTagVisibility = this._tag.style.visibility;
- this._tag.style.visibility = "hidden";
- };
-
- p._showTag = function() {
- this._tag.style.visibility = this._startTagVisibility;
- };
-
- /**
- * Handle a stalled audio event. The main place this happens is with HTMLAudio in Chrome when playing back audio
- * that is already in a load, but not complete.
- * @method _handleStalled
- * @private
- */
- p._handleStalled = function () {
- //Ignore, let the timeout take care of it. Sometimes its not really stopped.
- };
-
- createjs.TagRequest = createjs.promote(TagRequest, "AbstractRequest");
-
-}());
-
-//##############################################################################
-// MediaTagRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * An {{#crossLink "TagRequest"}}{{/crossLink}} that loads HTML tags for video and audio.
- * @class MediaTagRequest
- * @param {LoadItem} loadItem
- * @param {HTMLAudioElement|HTMLVideoElement} tag
- * @param {String} srcAttribute The tag attribute that specifies the source, such as "src", "href", etc.
- * @constructor
- */
- function MediaTagRequest(loadItem, tag, srcAttribute) {
- this.AbstractRequest_constructor(loadItem);
-
- // protected properties
- this._tag = tag;
- this._tagSrcAttribute = srcAttribute;
- this._loadedHandler = createjs.proxy(this._handleTagComplete, this);
- };
-
- var p = createjs.extend(MediaTagRequest, createjs.TagRequest);
- var s = MediaTagRequest;
-
- // public methods
- p.load = function () {
- var sc = createjs.proxy(this._handleStalled, this);
- this._stalledCallback = sc;
-
- var pc = createjs.proxy(this._handleProgress, this);
- this._handleProgress = pc;
-
- this._tag.addEventListener("stalled", sc);
- this._tag.addEventListener("progress", pc);
-
- // This will tell us when audio is buffered enough to play through, but not when its loaded.
- // The tag doesn't keep loading in Chrome once enough has buffered, and we have decided that behaviour is sufficient.
- this._tag.addEventListener && this._tag.addEventListener("canplaythrough", this._loadedHandler, false); // canplaythrough callback doesn't work in Chrome, so we use an event.
-
- this.TagRequest_load();
- };
-
- // private methods
- p._handleReadyStateChange = function () {
- clearTimeout(this._loadTimeout);
- // This is strictly for tags in browsers that do not support onload.
- var tag = this._tag;
-
- // Complete is for old IE support.
- if (tag.readyState == "loaded" || tag.readyState == "complete") {
- this._handleTagComplete();
- }
- };
-
- p._handleStalled = function () {
- //Ignore, let the timeout take care of it. Sometimes its not really stopped.
- };
-
- /**
- * An XHR request has reported progress.
- * @method _handleProgress
- * @param {Object} event The XHR progress event.
- * @private
- */
- p._handleProgress = function (event) {
- if (!event || event.loaded > 0 && event.total == 0) {
- return; // Sometimes we get no "total", so just ignore the progress event.
- }
-
- var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
- this.dispatchEvent(newEvent);
- };
-
- // protected methods
- p._clean = function () {
- this._tag.removeEventListener && this._tag.removeEventListener("canplaythrough", this._loadedHandler);
- this._tag.removeEventListener("stalled", this._stalledCallback);
- this._tag.removeEventListener("progress", this._progressCallback);
-
- this.TagRequest__clean();
- };
-
- createjs.MediaTagRequest = createjs.promote(MediaTagRequest, "TagRequest");
-
-}());
-
-//##############################################################################
-// XHRRequest.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-// constructor
- /**
- * A preloader that loads items using XHR requests, usually XMLHttpRequest. However XDomainRequests will be used
- * for cross-domain requests if possible, and older versions of IE fall back on to ActiveX objects when necessary.
- * XHR requests load the content as text or binary data, provide progress and consistent completion events, and
- * can be canceled during load. Note that XHR is not supported in IE 6 or earlier, and is not recommended for
- * cross-domain loading.
- * @class XHRRequest
- * @constructor
- * @param {Object} item The object that defines the file to load. Please see the {{#crossLink "LoadQueue/loadFile"}}{{/crossLink}}
- * for an overview of supported file properties.
- * @extends AbstractLoader
- */
- function XHRRequest (item) {
- this.AbstractRequest_constructor(item);
-
- // protected properties
- /**
- * A reference to the XHR request used to load the content.
- * @property _request
- * @type {XMLHttpRequest | XDomainRequest | ActiveX.XMLHTTP}
- * @private
- */
- this._request = null;
-
- /**
- * A manual load timeout that is used for browsers that do not support the onTimeout event on XHR (XHR level 1,
- * typically IE9).
- * @property _loadTimeout
- * @type {Number}
- * @private
- */
- this._loadTimeout = null;
-
- /**
- * The browser's XHR (XMLHTTPRequest) version. Supported versions are 1 and 2. There is no official way to detect
- * the version, so we use capabilities to make a best guess.
- * @property _xhrLevel
- * @type {Number}
- * @default 1
- * @private
- */
- this._xhrLevel = 1;
-
- /**
- * The response of a loaded file. This is set because it is expensive to look up constantly. This property will be
- * null until the file is loaded.
- * @property _response
- * @type {mixed}
- * @private
- */
- this._response = null;
-
- /**
- * The response of the loaded file before it is modified. In most cases, content is converted from raw text to
- * an HTML tag or a formatted object which is set to the result property, but the developer may still
- * want to access the raw content as it was loaded.
- * @property _rawResponse
- * @type {String|Object}
- * @private
- */
- this._rawResponse = null;
-
- this._canceled = false;
-
- // Setup our event handlers now.
- this._handleLoadStartProxy = createjs.proxy(this._handleLoadStart, this);
- this._handleProgressProxy = createjs.proxy(this._handleProgress, this);
- this._handleAbortProxy = createjs.proxy(this._handleAbort, this);
- this._handleErrorProxy = createjs.proxy(this._handleError, this);
- this._handleTimeoutProxy = createjs.proxy(this._handleTimeout, this);
- this._handleLoadProxy = createjs.proxy(this._handleLoad, this);
- this._handleReadyStateChangeProxy = createjs.proxy(this._handleReadyStateChange, this);
-
- if (!this._createXHR(item)) {
- //TODO: Throw error?
- }
- };
-
- var p = createjs.extend(XHRRequest, createjs.AbstractRequest);
-
-// static properties
- /**
- * A list of XMLHTTP object IDs to try when building an ActiveX object for XHR requests in earlier versions of IE.
- * @property ACTIVEX_VERSIONS
- * @type {Array}
- * @since 0.4.2
- * @private
- */
- XHRRequest.ACTIVEX_VERSIONS = [
- "Msxml2.XMLHTTP.6.0",
- "Msxml2.XMLHTTP.5.0",
- "Msxml2.XMLHTTP.4.0",
- "MSXML2.XMLHTTP.3.0",
- "MSXML2.XMLHTTP",
- "Microsoft.XMLHTTP"
- ];
-
-// Public methods
- /**
- * Look up the loaded result.
- * @method getResult
- * @param {Boolean} [raw=false] Return a raw result instead of a formatted result. This applies to content
- * loaded via XHR such as scripts, XML, CSS, and Images. If there is no raw result, the formatted result will be
- * returned instead.
- * @return {Object} A result object containing the content that was loaded, such as:
- *
- *
An image tag (<image />) for images
- *
A script tag for JavaScript (<script />). Note that scripts loaded with tags may be added to the
- * HTML head.
- *
A style tag for CSS (<style />)
- *
Raw text for TEXT
- *
A formatted JavaScript object defined by JSON
- *
An XML document
- *
An binary arraybuffer loaded by XHR
- *
- * Note that if a raw result is requested, but not found, the result will be returned instead.
- */
- p.getResult = function (raw) {
- if (raw && this._rawResponse) {
- return this._rawResponse;
- }
- return this._response;
- };
-
- // Overrides abstract method in AbstractRequest
- p.cancel = function () {
- this.canceled = true;
- this._clean();
- this._request.abort();
- };
-
- // Overrides abstract method in AbstractLoader
- p.load = function () {
- if (this._request == null) {
- this._handleError();
- return;
- }
-
- //Events
- if (this._request.addEventListener != null) {
- this._request.addEventListener("loadstart", this._handleLoadStartProxy, false);
- this._request.addEventListener("progress", this._handleProgressProxy, false);
- this._request.addEventListener("abort", this._handleAbortProxy, false);
- this._request.addEventListener("error", this._handleErrorProxy, false);
- this._request.addEventListener("timeout", this._handleTimeoutProxy, false);
-
- // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
- this._request.addEventListener("load", this._handleLoadProxy, false);
- this._request.addEventListener("readystatechange", this._handleReadyStateChangeProxy, false);
- } else {
- // IE9 support
- this._request.onloadstart = this._handleLoadStartProxy;
- this._request.onprogress = this._handleProgressProxy;
- this._request.onabort = this._handleAbortProxy;
- this._request.onerror = this._handleErrorProxy;
- this._request.ontimeout = this._handleTimeoutProxy;
-
- // Note: We don't get onload in all browsers (earlier FF and IE). onReadyStateChange handles these.
- this._request.onload = this._handleLoadProxy;
- this._request.onreadystatechange = this._handleReadyStateChangeProxy;
- }
-
- // Set up a timeout if we don't have XHR2
- if (this._xhrLevel == 1) {
- this._loadTimeout = setTimeout(createjs.proxy(this._handleTimeout, this), this._item.loadTimeout);
- }
-
- // Sometimes we get back 404s immediately, particularly when there is a cross origin request. // note this does not catch in Chrome
- try {
- if (!this._item.values || this._item.method == createjs.AbstractLoader.GET) {
- this._request.send();
- } else if (this._item.method == createjs.AbstractLoader.POST) {
- this._request.send(createjs.RequestUtils.formatQueryString(this._item.values));
- }
- } catch (error) {
- this.dispatchEvent(new createjs.ErrorEvent("XHR_SEND", null, error));
- }
- };
-
- p.setResponseType = function (type) {
- // Some old browsers doesn't support blob, so we convert arraybuffer to blob after response is downloaded
- if (type === 'blob') {
- type = window.URL ? 'blob' : 'arraybuffer';
- this._responseType = type;
- }
- this._request.responseType = type;
- };
-
- /**
- * Get all the response headers from the XmlHttpRequest.
- *
- * From the docs: Return all the HTTP headers, excluding headers that are a case-insensitive match
- * for Set-Cookie or Set-Cookie2, as a single string, with each header line separated by a U+000D CR U+000A LF pair,
- * excluding the status line, and with each header name and header value separated by a U+003A COLON U+0020 SPACE
- * pair.
- * @method getAllResponseHeaders
- * @return {String}
- * @since 0.4.1
- */
- p.getAllResponseHeaders = function () {
- if (this._request.getAllResponseHeaders instanceof Function) {
- return this._request.getAllResponseHeaders();
- } else {
- return null;
- }
- };
-
- /**
- * Get a specific response header from the XmlHttpRequest.
- *
- * From the docs: Returns the header field value from the response of which the field name matches
- * header, unless the field name is Set-Cookie or Set-Cookie2.
- * @method getResponseHeader
- * @param {String} header The header name to retrieve.
- * @return {String}
- * @since 0.4.1
- */
- p.getResponseHeader = function (header) {
- if (this._request.getResponseHeader instanceof Function) {
- return this._request.getResponseHeader(header);
- } else {
- return null;
- }
- };
-
-// protected methods
- /**
- * The XHR request has reported progress.
- * @method _handleProgress
- * @param {Object} event The XHR progress event.
- * @private
- */
- p._handleProgress = function (event) {
- if (!event || event.loaded > 0 && event.total == 0) {
- return; // Sometimes we get no "total", so just ignore the progress event.
- }
-
- var newEvent = new createjs.ProgressEvent(event.loaded, event.total);
- this.dispatchEvent(newEvent);
- };
-
- /**
- * The XHR request has reported a load start.
- * @method _handleLoadStart
- * @param {Object} event The XHR loadStart event.
- * @private
- */
- p._handleLoadStart = function (event) {
- clearTimeout(this._loadTimeout);
- this.dispatchEvent("loadstart");
- };
-
- /**
- * The XHR request has reported an abort event.
- * @method handleAbort
- * @param {Object} event The XHR abort event.
- * @private
- */
- p._handleAbort = function (event) {
- this._clean();
- this.dispatchEvent(new createjs.ErrorEvent("XHR_ABORTED", null, event));
- };
-
- /**
- * The XHR request has reported an error event.
- * @method _handleError
- * @param {Object} event The XHR error event.
- * @private
- */
- p._handleError = function (event) {
- this._clean();
- this.dispatchEvent(new createjs.ErrorEvent(event.message));
- };
-
- /**
- * The XHR request has reported a readyState change. Note that older browsers (IE 7 & 8) do not provide an onload
- * event, so we must monitor the readyStateChange to determine if the file is loaded.
- * @method _handleReadyStateChange
- * @param {Object} event The XHR readyStateChange event.
- * @private
- */
- p._handleReadyStateChange = function (event) {
- if (this._request.readyState == 4) {
- this._handleLoad();
- }
- };
-
- /**
- * The XHR request has completed. This is called by the XHR request directly, or by a readyStateChange that has
- * request.readyState == 4. Only the first call to this method will be processed.
- * @method _handleLoad
- * @param {Object} event The XHR load event.
- * @private
- */
- p._handleLoad = function (event) {
- if (this.loaded) {
- return;
- }
- this.loaded = true;
-
- var error = this._checkError();
- if (error) {
- this._handleError(error);
- return;
- }
-
- this._response = this._getResponse();
- // Convert arraybuffer back to blob
- if (this._responseType === 'arraybuffer') {
- try {
- this._response = new Blob([this._response]);
- } catch (e) {
- // Fallback to use BlobBuilder if Blob constructor is not supported
- // Tested on Android 2.3 ~ 4.2 and iOS5 safari
- window.BlobBuilder = window.BlobBuilder || window.WebKitBlobBuilder || window.MozBlobBuilder || window.MSBlobBuilder;
- if (e.name === 'TypeError' && window.BlobBuilder) {
- var builder = new BlobBuilder();
- builder.append(this._response);
- this._response = builder.getBlob();
- }
- }
- }
- this._clean();
-
- this.dispatchEvent(new createjs.Event("complete"));
- };
-
- /**
- * The XHR request has timed out. This is called by the XHR request directly, or via a setTimeout
- * callback.
- * @method _handleTimeout
- * @param {Object} [event] The XHR timeout event. This is occasionally null when called by the backup setTimeout.
- * @private
- */
- p._handleTimeout = function (event) {
- this._clean();
-
- this.dispatchEvent(new createjs.ErrorEvent("PRELOAD_TIMEOUT", null, event));
- };
-
-// Protected
- /**
- * Determine if there is an error in the current load. This checks the status of the request for problem codes. Note
- * that this does not check for an actual response. Currently, it only checks for 404 or 0 error code.
- * @method _checkError
- * @return {int} If the request status returns an error code.
- * @private
- */
- p._checkError = function () {
- //LM: Probably need additional handlers here, maybe 501
- var status = parseInt(this._request.status);
-
- switch (status) {
- case 404: // Not Found
- case 0: // Not Loaded
- return new Error(status);
- }
- return null;
- };
-
- /**
- * Validate the response. Different browsers have different approaches, some of which throw errors when accessed
- * in other browsers. If there is no response, the _response property will remain null.
- * @method _getResponse
- * @private
- */
- p._getResponse = function () {
- if (this._response != null) {
- return this._response;
- }
-
- if (this._request.response != null) {
- return this._request.response;
- }
-
- // Android 2.2 uses .responseText
- try {
- if (this._request.responseText != null) {
- return this._request.responseText;
- }
- } catch (e) {
- }
-
- // When loading XML, IE9 does not return .response, instead it returns responseXML.xml
- try {
- if (this._request.responseXML != null) {
- return this._request.responseXML;
- }
- } catch (e) {
- }
-
- return null;
- };
-
- /**
- * Create an XHR request. Depending on a number of factors, we get totally different results.
- *
Some browsers get an XDomainRequest when loading cross-domain.
- *
XMLHttpRequest are created when available.
- *
ActiveX.XMLHTTP objects are used in older IE browsers.
- *
Text requests override the mime type if possible
- *
Origin headers are sent for crossdomain requests in some browsers.
- *
Binary loads set the response type to "arraybuffer"
- * @method _createXHR
- * @param {Object} item The requested item that is being loaded.
- * @return {Boolean} If an XHR request or equivalent was successfully created.
- * @private
- */
- p._createXHR = function (item) {
- // Check for cross-domain loads. We can't fully support them, but we can try.
- var crossdomain = createjs.RequestUtils.isCrossDomain(item);
- var headers = {};
-
- // Create the request. Fallback to whatever support we have.
- var req = null;
- if (window.XMLHttpRequest) {
- req = new XMLHttpRequest();
- // This is 8 or 9, so use XDomainRequest instead.
- if (crossdomain && req.withCredentials === undefined && window.XDomainRequest) {
- req = new XDomainRequest();
- }
- } else { // Old IE versions use a different approach
- for (var i = 0, l = s.ACTIVEX_VERSIONS.length; i < l; i++) {
- var axVersion = s.ACTIVEX_VERSIONS[i];
- try {
- req = new ActiveXObject(axVersion);
- break;
- } catch (e) {
- }
- }
- if (req == null) {
- return false;
- }
- }
-
- // Default to utf-8 for Text requests.
- if (item.mimeType == null && createjs.RequestUtils.isText(item.type)) {
- item.mimeType = "text/plain; charset=utf-8";
- }
-
- // IE9 doesn't support overrideMimeType(), so we need to check for it.
- if (item.mimeType && req.overrideMimeType) {
- req.overrideMimeType(item.mimeType);
- }
-
- // Determine the XHR level
- this._xhrLevel = (typeof req.responseType === "string") ? 2 : 1;
-
- var src = null;
- if (item.method == createjs.AbstractLoader.GET) {
- src = createjs.RequestUtils.buildPath(item.src, item.values);
- } else {
- src = item.src;
- }
-
- // Open the request. Set cross-domain flags if it is supported (XHR level 1 only)
- req.open(item.method || createjs.AbstractLoader.GET, src, true);
-
- if (crossdomain && req instanceof XMLHttpRequest && this._xhrLevel == 1) {
- headers["Origin"] = location.origin;
- }
-
- // To send data we need to set the Content-type header)
- if (item.values && item.method == createjs.AbstractLoader.POST) {
- headers["Content-Type"] = "application/x-www-form-urlencoded";
- }
-
- if (!crossdomain && !headers["X-Requested-With"]) {
- headers["X-Requested-With"] = "XMLHttpRequest";
- }
-
- if (item.headers) {
- for (var n in item.headers) {
- headers[n] = item.headers[n];
- }
- }
-
- for (n in headers) {
- req.setRequestHeader(n, headers[n])
- }
-
- if (req instanceof XMLHttpRequest && item.withCredentials !== undefined) {
- req.withCredentials = item.withCredentials;
- }
-
- this._request = req;
-
- return true;
- };
-
- /**
- * A request has completed (or failed or canceled), and needs to be disposed.
- * @method _clean
- * @private
- */
- p._clean = function () {
- clearTimeout(this._loadTimeout);
-
- if (this._request.removeEventListener != null) {
- this._request.removeEventListener("loadstart", this._handleLoadStartProxy);
- this._request.removeEventListener("progress", this._handleProgressProxy);
- this._request.removeEventListener("abort", this._handleAbortProxy);
- this._request.removeEventListener("error", this._handleErrorProxy);
- this._request.removeEventListener("timeout", this._handleTimeoutProxy);
- this._request.removeEventListener("load", this._handleLoadProxy);
- this._request.removeEventListener("readystatechange", this._handleReadyStateChangeProxy);
- } else {
- this._request.onloadstart = null;
- this._request.onprogress = null;
- this._request.onabort = null;
- this._request.onerror = null;
- this._request.ontimeout = null;
- this._request.onload = null;
- this._request.onreadystatechange = null;
- }
- };
-
- p.toString = function () {
- return "[PreloadJS XHRRequest]";
- };
-
- createjs.XHRRequest = createjs.promote(XHRRequest, "AbstractRequest");
-
-}());
-
-//##############################################################################
-// SoundLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- // constructor
- /**
- * A loader for HTML audio files. PreloadJS can not load WebAudio files, as a WebAudio context is required, which
- * should be created by either a library playing the sound (such as SoundJS, or an
- * external framework that handles audio playback. To load content that can be played by WebAudio, use the
- * {{#crossLink "BinaryLoader"}}{{/crossLink}}, and handle the audio context decoding manually.
- * @class SoundLoader
- * @param {LoadItem|Object} loadItem
- * @param {Boolean} preferXHR
- * @extends AbstractMediaLoader
- * @constructor
- */
- function SoundLoader(loadItem, preferXHR) {
- this.AbstractMediaLoader_constructor(loadItem, preferXHR, createjs.AbstractLoader.SOUND);
-
- // protected properties
- if (createjs.RequestUtils.isAudioTag(loadItem)) {
- this._tag = loadItem;
- } else if (createjs.RequestUtils.isAudioTag(loadItem.src)) {
- this._tag = loadItem;
- } else if (createjs.RequestUtils.isAudioTag(loadItem.tag)) {
- this._tag = createjs.RequestUtils.isAudioTag(loadItem) ? loadItem : loadItem.src;
- }
-
- if (this._tag != null) {
- this._preferXHR = false;
- }
- };
-
- var p = createjs.extend(SoundLoader, createjs.AbstractMediaLoader);
- var s = SoundLoader;
-
- // static methods
- /**
- * Determines if the loader can load a specific item. This loader can only load items that are of type
- * {{#crossLink "AbstractLoader/SOUND:property"}}{{/crossLink}}.
- * @method canLoadItem
- * @param {LoadItem|Object} item The LoadItem that a LoadQueue is trying to load.
- * @returns {Boolean} Whether the loader can load the item.
- * @static
- */
- s.canLoadItem = function (item) {
- return item.type == createjs.AbstractLoader.SOUND;
- };
-
- // protected methods
- p._createTag = function (src) {
- var tag = document.createElement("audio");
- tag.autoplay = false;
- tag.preload = "none";
-
- //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works.
- tag.src = src;
- return tag;
- };
-
- createjs.SoundLoader = createjs.promote(SoundLoader, "AbstractMediaLoader");
-
-}());
-
-//##############################################################################
-// AudioSprite.js
-//##############################################################################
-
-// NOTE this is "Class" is purely to document audioSprite Setup and usage.
-
-
-/**
- * Note: AudioSprite is not a class, but its usage is easily lost in the documentation, so it has been called
- * out here for quick reference.
- *
- * Audio sprites are much like CSS sprites or image sprite sheets: multiple audio assets grouped into a single file.
- * Audio sprites work around limitations in certain browsers, where only a single sound can be loaded and played at a
- * time. We recommend at least 300ms of silence between audio clips to deal with HTML audio tag inaccuracy, and to prevent
- * accidentally playing bits of the neighbouring clips.
- *
- * Benefits of Audio Sprites:
- *
- *
More robust support for older browsers and devices that only allow a single audio instance, such as iOS 5.
- *
They provide a work around for the Internet Explorer 9 audio tag limit, which restricts how many different
- * sounds that could be loaded at once.
- *
Faster loading by only requiring a single network request for several sounds, especially on mobile devices
- * where the network round trip for each file can add significant latency.
- *
- *
- * Drawbacks of Audio Sprites
- *
- *
No guarantee of smooth looping when using HTML or Flash audio. If you have a track that needs to loop
- * smoothly and you are supporting non-web audio browsers, do not use audio sprites for that sound if you can avoid
- * it.
- *
No guarantee that HTML audio will play back immediately, especially the first time. In some browsers
- * (Chrome!), HTML audio will only load enough to play through at the current download speed – so we rely on the
- * `canplaythrough` event to determine if the audio is loaded. Since audio sprites must jump ahead to play specific
- * sounds, the audio may not yet have downloaded fully.
- *
Audio sprites share the same core source, so if you have a sprite with 5 sounds and are limited to 2
- * concurrently playing instances, you can only play 2 of the sounds at the same time.
- *
- *
- *
Example
- *
- * createjs.Sound.initializeDefaultPlugins();
- * var assetsPath = "./assets/";
- * var sounds = [{
- * src:"MyAudioSprite.ogg", data: {
- * audioSprite: [
- * {id:"sound1", startTime:0, duration:500},
- * {id:"sound2", startTime:1000, duration:400},
- * {id:"sound3", startTime:1700, duration: 1000}
- * ]}
- * }
- * ];
- * createjs.Sound.alternateExtensions = ["mp3"];
- * createjs.Sound.on("fileload", loadSound);
- * createjs.Sound.registerSounds(sounds, assetsPath);
- * // after load is complete
- * createjs.Sound.play("sound2");
- *
- * You can also create audio sprites on the fly by setting the startTime and duration when creating an new AbstractSoundInstance.
- *
- * createjs.Sound.play("MyAudioSprite", {startTime: 1000, duration: 400});
- *
- * The excellent CreateJS community has created a tool to create audio sprites, available at
- * https://github.com/tonistiigi/audiosprite,
- * as well as a jsfiddle to convert the output
- * to SoundJS format.
- *
- * @class AudioSprite
- * @since 0.6.0
- */
-
-//##############################################################################
-// PlayPropsConfig.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
- /**
- * A class to store the optional play properties passed in {{#crossLink "Sound/play"}}{{/crossLink}} and
- * {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} calls.
- *
- * Optional Play Properties Include:
- *
- *
interrupt - How to interrupt any currently playing instances of audio with the same source,
- * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE
- * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
- *
delay - The amount of time to delay the start of audio playback, in milliseconds.
- *
offset - The offset from the start of the audio to begin playback, in milliseconds.
- *
loop - How many times the audio loops when it reaches the end of playback. The default is 0 (no
- * loops), and -1 can be used for infinite playback.
- *
volume - The volume of the sound, between 0 and 1. Note that the master volume is applied
- * against the individual volume.
- *
pan - The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
- *
startTime - To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
- *
duration - To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
- *
- *
- *
Example
- *
- * var ppc = new createjs.PlayPropsConfig().set({interrupt: createjs.Sound.INTERRUPT_ANY, loop: -1, volume: 0.5})
- * createjs.Sound.play("mySound", ppc);
- * mySoundInstance.play(ppc);
- *
- * @class PlayPropsConfig
- * @constructor
- * @since 0.6.1
- */
- // TODO think of a better name for this class
- var PlayPropsConfig = function () {
-// Public Properties
- /**
- * How to interrupt any currently playing instances of audio with the same source,
- * if the maximum number of instances of the sound are already playing. Values are defined as
- * INTERRUPT_TYPE constants on the Sound class, with the default defined by
- * {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
- * @property interrupt
- * @type {string}
- * @default null
- */
- this.interrupt = null;
-
- /**
- * The amount of time to delay the start of audio playback, in milliseconds.
- * @property delay
- * @type {Number}
- * @default null
- */
- this.delay = null;
-
- /**
- * The offset from the start of the audio to begin playback, in milliseconds.
- * @property offset
- * @type {number}
- * @default null
- */
- this.offset = null;
-
- /**
- * How many times the audio loops when it reaches the end of playback. The default is 0 (no
- * loops), and -1 can be used for infinite playback.
- * @property loop
- * @type {number}
- * @default null
- */
- this.loop = null;
-
- /**
- * The volume of the sound, between 0 and 1. Note that the master volume is applied
- * against the individual volume.
- * @property volume
- * @type {number}
- * @default null
- */
- this.volume = null;
-
- /**
- * The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
- * @property pan
- * @type {number}
- * @default null
- */
- this.pan = null;
-
- /**
- * Used to create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
- * @property startTime
- * @type {number}
- * @default null
- */
- this.startTime = null;
-
- /**
- * Used to create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
- * @property duration
- * @type {number}
- * @default null
- */
- this.duration = null;
- };
- var p = PlayPropsConfig.prototype = {};
- var s = PlayPropsConfig;
-
-
-// Static Methods
- /**
- * Creates a PlayPropsConfig from another PlayPropsConfig or an Object.
- *
- * @method create
- * @param {PlayPropsConfig|Object} value The play properties
- * @returns {PlayPropsConfig}
- * @static
- */
- s.create = function (value) {
- if (value instanceof s || value instanceof Object) {
- var ppc = new createjs.PlayPropsConfig();
- ppc.set(value);
- return ppc;
- } else {
- throw new Error("Type not recognized.");
- }
- };
-
-// Public Methods
- /**
- * Provides a chainable shortcut method for setting a number of properties on the instance.
- *
- *
Example
- *
- * var PlayPropsConfig = new createjs.PlayPropsConfig().set({loop:-1, volume:0.7});
- *
- * @method set
- * @param {Object} props A generic object containing properties to copy to the PlayPropsConfig instance.
- * @return {PlayPropsConfig} Returns the instance the method is called on (useful for chaining calls.)
- */
- p.set = function(props) {
- for (var n in props) { this[n] = props[n]; }
- return this;
- };
-
- p.toString = function() {
- return "[PlayPropsConfig]";
- };
-
- createjs.PlayPropsConfig = s;
-
-}());
-
-//##############################################################################
-// Sound.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-
-
-(function () {
- "use strict";
-
- /**
- * The Sound class is the public API for creating sounds, controlling the overall sound levels, and managing plugins.
- * All Sound APIs on this class are static.
- *
- * Registering and Preloading
- * Before you can play a sound, it must be registered. You can do this with {{#crossLink "Sound/registerSound"}}{{/crossLink}},
- * or register multiple sounds using {{#crossLink "Sound/registerSounds"}}{{/crossLink}}. If you don't register a
- * sound prior to attempting to play it using {{#crossLink "Sound/play"}}{{/crossLink}} or create it using {{#crossLink "Sound/createInstance"}}{{/crossLink}},
- * the sound source will be automatically registered but playback will fail as the source will not be ready. If you use
- * PreloadJS, registration is handled for you when the sound is
- * preloaded. It is recommended to preload sounds either internally using the register functions or externally using
- * PreloadJS so they are ready when you want to use them.
- *
- * Playback
- * To play a sound once it's been registered and preloaded, use the {{#crossLink "Sound/play"}}{{/crossLink}} method.
- * This method returns a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} which can be paused, resumed, muted, etc.
- * Please see the {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} documentation for more on the instance control APIs.
- *
- * Plugins
- * By default, the {{#crossLink "WebAudioPlugin"}}{{/crossLink}} or the {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}
- * are used (when available), although developers can change plugin priority or add new plugins (such as the
- * provided {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}). Please see the {{#crossLink "Sound"}}{{/crossLink}} API
- * methods for more on the playback and plugin APIs. To install plugins, or specify a different plugin order, see
- * {{#crossLink "Sound/installPlugins"}}{{/crossLink}}.
- *
- *
Example
- *
- * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio";
- * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.FlashAudioPlugin]);
- * createjs.Sound.alternateExtensions = ["mp3"];
- * createjs.Sound.on("fileload", this.loadHandler, this);
- * createjs.Sound.registerSound("path/to/mySound.ogg", "sound");
- * function loadHandler(event) {
- * // This is fired for each sound that is registered.
- * var instance = createjs.Sound.play("sound"); // play using id. Could also use full source path or event.src.
- * instance.on("complete", this.handleComplete, this);
- * instance.volume = 0.5;
- * }
- *
- * The maximum number of concurrently playing instances of the same sound can be specified in the "data" argument
- * of {{#crossLink "Sound/registerSound"}}{{/crossLink}}. Note that if not specified, the active plugin will apply
- * a default limit. Currently HTMLAudioPlugin sets a default limit of 2, while WebAudioPlugin and FlashAudioPlugin set a
- * default limit of 100.
- *
- * createjs.Sound.registerSound("sound.mp3", "soundId", 4);
- *
- * Sound can be used as a plugin with PreloadJS to help preload audio properly. Audio preloaded with PreloadJS is
- * automatically registered with the Sound class. When audio is not preloaded, Sound will do an automatic internal
- * load. As a result, it may fail to play the first time play is called if the audio is not finished loading. Use
- * the {{#crossLink "Sound/fileload:event"}}{{/crossLink}} event to determine when a sound has finished internally
- * preloading. It is recommended that all audio is preloaded before it is played.
- *
- * var queue = new createjs.LoadQueue();
- * queue.installPlugin(createjs.Sound);
- *
- * Audio Sprites
- * SoundJS has added support for {{#crossLink "AudioSprite"}}{{/crossLink}}, available as of version 0.6.0.
- * For those unfamiliar with audio sprites, they are much like CSS sprites or sprite sheets: multiple audio assets
- * grouped into a single file.
- *
- *
Example
- *
- * var assetsPath = "./assets/";
- * var sounds = [{
- * src:"MyAudioSprite.ogg", data: {
- * audioSprite: [
- * {id:"sound1", startTime:0, duration:500},
- * {id:"sound2", startTime:1000, duration:400},
- * {id:"sound3", startTime:1700, duration: 1000}
- * ]}
- * }
- * ];
- * createjs.Sound.alternateExtensions = ["mp3"];
- * createjs.Sound.on("fileload", loadSound);
- * createjs.Sound.registerSounds(sounds, assetsPath);
- * // after load is complete
- * createjs.Sound.play("sound2");
- *
- * Mobile Playback
- * Devices running iOS require the WebAudio context to be "unlocked" by playing at least one sound inside of a user-
- * initiated event (such as touch/click). Earlier versions of SoundJS included a "MobileSafe" sample, but this is no
- * longer necessary as of SoundJS 0.6.2.
- *
- *
- * In SoundJS 0.4.1 and above, you can either initialize plugins or use the {{#crossLink "WebAudioPlugin/playEmptySound"}}{{/crossLink}}
- * method in the call stack of a user input event to manually unlock the audio context.
- *
- *
- * In SoundJS 0.6.2 and above, SoundJS will automatically listen for the first document-level "mousedown"
- * and "touchend" event, and unlock WebAudio. This will continue to check these events until the WebAudio
- * context becomes "unlocked" (changes from "suspended" to "running")
- *
- *
- * Both the "mousedown" and "touchend" events can be used to unlock audio in iOS9+, the "touchstart" event
- * will work in iOS8 and below. The "touchend" event will only work in iOS9 when the gesture is interpreted
- * as a "click", so if the user long-presses the button, it will no longer work.
- *
- *
- * When using the EaselJS Touch class,
- * the "mousedown" event will not fire when a canvas is clicked, since MouseEvents are prevented, to ensure
- * only touch events fire. To get around this, you can either rely on "touchend", or:
- *
- *
Set the `allowDefault` property on the Touch class constructor to `true` (defaults to `false`).
- *
Set the `preventSelection` property on the EaselJS `Stage` to `false`.
- *
- * These settings may change how your application behaves, and are not recommended.
- *
- *
- *
- * Loading Alternate Paths and Extension-less Files
- * SoundJS supports loading alternate paths and extension-less files by passing an object instead of a string for
- * the `src` property, which is a hash using the format `{extension:"path", extension2:"path2"}`. These labels are
- * how SoundJS determines if the browser will support the sound. This also enables multiple formats to live in
- * different folders, or on CDNs, which often has completely different filenames for each file.
- *
- * Priority is determined by the property order (first property is tried first). This is supported by both internal loading
- * and loading with PreloadJS.
- *
- * Note: an id is required for playback.
- *
- *
There is a delay in applying volume changes to tags that occurs once playback is started. So if you have
- * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of
- * when or how you apply the volume change, as the tag seems to need to play to apply it.
- *
MP3 encoding will not always work for audio tags, particularly in Internet Explorer. We've found default
- * encoding with 64kbps works.
- *
Occasionally very short samples will get cut off.
- *
There is a limit to how many audio tags you can load and play at once, which appears to be determined by
- * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe
- * estimate.
- *
- * Firefox 25 Web Audio limitations
- *
mp3 audio files do not load properly on all windows machines, reported
- * here.
- * For this reason it is recommended to pass another FF supported type (ie ogg) first until this bug is resolved, if
- * possible.
-
- * Safari limitations
- *
Safari requires Quicktime to be installed for audio playback.
- *
- * iOS 6 Web Audio limitations
- *
Sound is initially locked, and must be unlocked via a user-initiated event. Please see the section on
- * Mobile Playback above.
- *
A bug exists that will distort un-cached web audio when a video element is present in the DOM that has audio
- * at a different sampleRate.
- *
- *
- * Android HTML Audio limitations
- *
We have no control over audio volume. Only the user can set volume on their device.
- *
We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use
- * a delay.
- *
- * Web Audio and PreloadJS
- *
Web Audio must be loaded through XHR, therefore when used with PreloadJS, tag loading is not possible.
- * This means that tag loading can not be used to avoid cross domain issues.
- *
- * @class Sound
- * @static
- * @uses EventDispatcher
- */
- function Sound() {
- throw "Sound cannot be instantiated";
- }
-
- var s = Sound;
-
-
-// Static Properties
- /**
- * The interrupt value to interrupt any currently playing instance with the same source, if the maximum number of
- * instances of the sound are already playing.
- * @property INTERRUPT_ANY
- * @type {String}
- * @default any
- * @static
- */
- s.INTERRUPT_ANY = "any";
-
- /**
- * The interrupt value to interrupt the earliest currently playing instance with the same source that progressed the
- * least distance in the audio track, if the maximum number of instances of the sound are already playing.
- * @property INTERRUPT_EARLY
- * @type {String}
- * @default early
- * @static
- */
- s.INTERRUPT_EARLY = "early";
-
- /**
- * The interrupt value to interrupt the currently playing instance with the same source that progressed the most
- * distance in the audio track, if the maximum number of instances of the sound are already playing.
- * @property INTERRUPT_LATE
- * @type {String}
- * @default late
- * @static
- */
- s.INTERRUPT_LATE = "late";
-
- /**
- * The interrupt value to not interrupt any currently playing instances with the same source, if the maximum number of
- * instances of the sound are already playing.
- * @property INTERRUPT_NONE
- * @type {String}
- * @default none
- * @static
- */
- s.INTERRUPT_NONE = "none";
-
- /**
- * Defines the playState of an instance that is still initializing.
- * @property PLAY_INITED
- * @type {String}
- * @default playInited
- * @static
- */
- s.PLAY_INITED = "playInited";
-
- /**
- * Defines the playState of an instance that is currently playing or paused.
- * @property PLAY_SUCCEEDED
- * @type {String}
- * @default playSucceeded
- * @static
- */
- s.PLAY_SUCCEEDED = "playSucceeded";
-
- /**
- * Defines the playState of an instance that was interrupted by another instance.
- * @property PLAY_INTERRUPTED
- * @type {String}
- * @default playInterrupted
- * @static
- */
- s.PLAY_INTERRUPTED = "playInterrupted";
-
- /**
- * Defines the playState of an instance that completed playback.
- * @property PLAY_FINISHED
- * @type {String}
- * @default playFinished
- * @static
- */
- s.PLAY_FINISHED = "playFinished";
-
- /**
- * Defines the playState of an instance that failed to play. This is usually caused by a lack of available channels
- * when the interrupt mode was "INTERRUPT_NONE", the playback stalled, or the sound could not be found.
- * @property PLAY_FAILED
- * @type {String}
- * @default playFailed
- * @static
- */
- s.PLAY_FAILED = "playFailed";
-
- /**
- * A list of the default supported extensions that Sound will try to play. Plugins will check if the browser
- * can play these types, so modifying this list before a plugin is initialized will allow the plugins to try to
- * support additional media types.
- *
- * NOTE this does not currently work for {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}.
- *
- * More details on file formats can be found at http://en.wikipedia.org/wiki/Audio_file_format.
- * A very detailed list of file formats can be found at http://www.fileinfo.com/filetypes/audio.
- * @property SUPPORTED_EXTENSIONS
- * @type {Array[String]}
- * @default ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"]
- * @since 0.4.0
- * @static
- */
- s.SUPPORTED_EXTENSIONS = ["mp3", "ogg", "opus", "mpeg", "wav", "m4a", "mp4", "aiff", "wma", "mid"];
-
- /**
- * Some extensions use another type of extension support to play (one of them is a codex). This allows you to map
- * that support so plugins can accurately determine if an extension is supported. Adding to this list can help
- * plugins determine more accurately if an extension is supported.
- *
- * A useful list of extensions for each format can be found at http://html5doctor.com/html5-audio-the-state-of-play/.
- * @property EXTENSION_MAP
- * @type {Object}
- * @since 0.4.0
- * @default {m4a:"mp4"}
- * @static
- */
- s.EXTENSION_MAP = {
- m4a:"mp4"
- };
-
- /**
- * The RegExp pattern used to parse file URIs. This supports simple file names, as well as full domain URIs with
- * query strings. The resulting match is: protocol:$1 domain:$2 path:$3 file:$4 extension:$5 query:$6.
- * @property FILE_PATTERN
- * @type {RegExp}
- * @static
- * @protected
- */
- s.FILE_PATTERN = /^(?:(\w+:)\/{2}(\w+(?:\.\w+)*\/?))?([/.]*?(?:[^?]+)?\/)?((?:[^/?]+)\.(\w+))(?:\?(\S+)?)?$/;
-
-
-// Class Public properties
- /**
- * Determines the default behavior for interrupting other currently playing instances with the same source, if the
- * maximum number of instances of the sound are already playing. Currently the default is {{#crossLink "Sound/INTERRUPT_NONE:property"}}{{/crossLink}}
- * but this can be set and will change playback behavior accordingly. This is only used when {{#crossLink "Sound/play"}}{{/crossLink}}
- * is called without passing a value for interrupt.
- * @property defaultInterruptBehavior
- * @type {String}
- * @default Sound.INTERRUPT_NONE, or "none"
- * @static
- * @since 0.4.0
- */
- s.defaultInterruptBehavior = s.INTERRUPT_NONE; // OJR does s.INTERRUPT_ANY make more sense as default? Needs game dev testing to see which case makes more sense.
-
- /**
- * An array of extensions to attempt to use when loading sound, if the default is unsupported by the active plugin.
- * These are applied in order, so if you try to Load Thunder.ogg in a browser that does not support ogg, and your
- * extensions array is ["mp3", "m4a", "wav"] it will check mp3 support, then m4a, then wav. The audio files need
- * to exist in the same location, as only the extension is altered.
- *
- * Note that regardless of which file is loaded, you can call {{#crossLink "Sound/createInstance"}}{{/crossLink}}
- * and {{#crossLink "Sound/play"}}{{/crossLink}} using the same id or full source path passed for loading.
- *
- *
Example
- *
- * var sounds = [
- * {src:"myPath/mySound.ogg", id:"example"},
- * ];
- * createjs.Sound.alternateExtensions = ["mp3"]; // now if ogg is not supported, SoundJS will try asset0.mp3
- * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads
- * createjs.Sound.registerSounds(sounds, assetPath);
- * // ...
- * createjs.Sound.play("myPath/mySound.ogg"); // works regardless of what extension is supported. Note calling with ID is a better approach
- *
- * @property alternateExtensions
- * @type {Array}
- * @since 0.5.2
- * @static
- */
- s.alternateExtensions = [];
-
- /**
- * The currently active plugin. If this is null, then no plugin could be initialized. If no plugin was specified,
- * Sound attempts to apply the default plugins: {{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by
- * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.
- * @property activePlugin
- * @type {Object}
- * @static
- */
- s.activePlugin = null;
-
-
-// class getter / setter properties
- /**
- * Set the master volume of Sound. The master volume is multiplied against each sound's individual volume. For
- * example, if master volume is 0.5 and a sound's volume is 0.5, the resulting volume is 0.25. To set individual
- * sound volume, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} instead.
- *
- *
Example
- *
- * createjs.Sound.volume = 0.5;
- *
- *
- * @property volume
- * @type {Number}
- * @default 1
- * @since 0.6.1
- */
- s._masterVolume = 1;
- Object.defineProperty(s, "volume", {
- get: function () {return this._masterVolume;},
- set: function (value) {
- if (Number(value) == null) {return false;}
- value = Math.max(0, Math.min(1, value));
- s._masterVolume = value;
- if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) {
- var instances = this._instances;
- for (var i = 0, l = instances.length; i < l; i++) {
- instances[i].setMasterVolume(value);
- }
- }
- }
- });
-
- /**
- * Mute/Unmute all audio. Note that muted audio still plays at 0 volume. This global mute value is maintained
- * separately and when set will override, but not change the mute property of individual instances. To mute an individual
- * instance, use AbstractSoundInstance {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} instead.
- *
- *
Example
- *
- * createjs.Sound.muted = true;
- *
- *
- * @property muted
- * @type {Boolean}
- * @default false
- * @since 0.6.1
- */
- s._masterMute = false;
- // OJR references to the methods were not working, so the code had to be duplicated here
- Object.defineProperty(s, "muted", {
- get: function () {return this._masterMute;},
- set: function (value) {
- if (value == null) {return false;}
-
- this._masterMute = value;
- if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) {
- var instances = this._instances;
- for (var i = 0, l = instances.length; i < l; i++) {
- instances[i].setMasterMute(value);
- }
- }
- return true;
- }
- });
-
- /**
- * Get the active plugins capabilities, which help determine if a plugin can be used in the current environment,
- * or if the plugin supports a specific feature. Capabilities include:
- *
- *
panning: If the plugin can pan audio from left to right
- *
volume; If the plugin can control audio volume.
- *
tracks: The maximum number of audio tracks that can be played back at a time. This will be -1
- * if there is no known limit.
- * An entry for each file type in {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}:
- *
mp3: If MP3 audio is supported.
- *
ogg: If OGG audio is supported.
- *
wav: If WAV audio is supported.
- *
mpeg: If MPEG audio is supported.
- *
m4a: If M4A audio is supported.
- *
mp4: If MP4 audio is supported.
- *
aiff: If aiff audio is supported.
- *
wma: If wma audio is supported.
- *
mid: If mid audio is supported.
- *
- *
- * You can get a specific capability of the active plugin using standard object notation
- *
- *
Example
- *
- * var mp3 = createjs.Sound.capabilities.mp3;
- *
- * Note this property is read only.
- *
- * @property capabilities
- * @type {Object}
- * @static
- * @readOnly
- * @since 0.6.1
- */
- Object.defineProperty(s, "capabilities", {
- get: function () {
- if (s.activePlugin == null) {return null;}
- return s.activePlugin._capabilities;
- },
- set: function (value) { return false;}
- });
-
-
-// Class Private properties
- /**
- * Determines if the plugins have been registered. If false, the first call to play() will instantiate the default
- * plugins ({{#crossLink "WebAudioPlugin"}}{{/crossLink}}, followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}).
- * If plugins have been registered, but none are applicable, then sound playback will fail.
- * @property _pluginsRegistered
- * @type {Boolean}
- * @default false
- * @static
- * @protected
- */
- s._pluginsRegistered = false;
-
- /**
- * Used internally to assign unique IDs to each AbstractSoundInstance.
- * @property _lastID
- * @type {Number}
- * @static
- * @protected
- */
- s._lastID = 0;
-
- /**
- * An array containing all currently playing instances. This allows Sound to control the volume, mute, and playback of
- * all instances when using static APIs like {{#crossLink "Sound/stop"}}{{/crossLink}} and {{#crossLink "Sound/setVolume"}}{{/crossLink}}.
- * When an instance has finished playback, it gets removed via the {{#crossLink "Sound/finishedPlaying"}}{{/crossLink}}
- * method. If the user replays an instance, it gets added back in via the {{#crossLink "Sound/_beginPlaying"}}{{/crossLink}}
- * method.
- * @property _instances
- * @type {Array}
- * @protected
- * @static
- */
- s._instances = [];
-
- /**
- * An object hash storing objects with sound sources, startTime, and duration via there corresponding ID.
- * @property _idHash
- * @type {Object}
- * @protected
- * @static
- */
- s._idHash = {};
-
- /**
- * An object hash that stores preloading sound sources via the parsed source that is passed to the plugin. Contains the
- * source, id, and data that was passed in by the user. Parsed sources can contain multiple instances of source, id,
- * and data.
- * @property _preloadHash
- * @type {Object}
- * @protected
- * @static
- */
- s._preloadHash = {};
-
- /**
- * An object hash storing {{#crossLink "PlayPropsConfig"}}{{/crossLink}} via the parsed source that is passed as defaultPlayProps in
- * {{#crossLink "Sound/registerSound"}}{{/crossLink}} and {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.
- * @property _defaultPlayPropsHash
- * @type {Object}
- * @protected
- * @static
- * @since 0.6.1
- */
- s._defaultPlayPropsHash = {};
-
-
-// EventDispatcher methods:
- s.addEventListener = null;
- s.removeEventListener = null;
- s.removeAllEventListeners = null;
- s.dispatchEvent = null;
- s.hasEventListener = null;
- s._listeners = null;
-
- createjs.EventDispatcher.initialize(s); // inject EventDispatcher methods.
-
-
-// Events
- /**
- * This event is fired when a file finishes loading internally. This event is fired for each loaded sound,
- * so any handler methods should look up the event.src to handle a particular sound.
- * @event fileload
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {String} src The source of the sound that was loaded.
- * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null.
- * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined.
- * @since 0.4.1
- */
-
- /**
- * This event is fired when a file fails loading internally. This event is fired for each loaded sound,
- * so any handler methods should look up the event.src to handle a particular sound.
- * @event fileerror
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @param {String} src The source of the sound that was loaded.
- * @param {String} [id] The id passed in when the sound was registered. If one was not provided, it will be null.
- * @param {Number|Object} [data] Any additional data associated with the item. If not provided, it will be undefined.
- * @since 0.6.0
- */
-
-
-// Class Public Methods
- /**
- * Get the preload rules to allow Sound to be used as a plugin by PreloadJS.
- * Any load calls that have the matching type or extension will fire the callback method, and use the resulting
- * object, which is potentially modified by Sound. This helps when determining the correct path, as well as
- * registering the audio instance(s) with Sound. This method should not be called, except by PreloadJS.
- * @method getPreloadHandlers
- * @return {Object} An object containing:
- *
callback: A preload callback that is fired when a file is added to PreloadJS, which provides
- * Sound a mechanism to modify the load parameters, select the correct file format, register the sound, etc.
- *
types: A list of file types that are supported by Sound (currently supports "sound").
- *
extensions: A list of file extensions that are supported by Sound (see {{#crossLink "Sound/SUPPORTED_EXTENSIONS:property"}}{{/crossLink}}).
- * @static
- * @protected
- */
- s.getPreloadHandlers = function () {
- return {
- callback:createjs.proxy(s.initLoad, s),
- types:["sound"],
- extensions:s.SUPPORTED_EXTENSIONS
- };
- };
-
- /**
- * Used to dispatch fileload events from internal loading.
- * @method _handleLoadComplete
- * @param event A loader event.
- * @protected
- * @static
- * @since 0.6.0
- */
- s._handleLoadComplete = function(event) {
- var src = event.target.getItem().src;
- if (!s._preloadHash[src]) {return;}
-
- for (var i = 0, l = s._preloadHash[src].length; i < l; i++) {
- var item = s._preloadHash[src][i];
- s._preloadHash[src][i] = true;
-
- if (!s.hasEventListener("fileload")) { continue; }
-
- var event = new createjs.Event("fileload");
- event.src = item.src;
- event.id = item.id;
- event.data = item.data;
- event.sprite = item.sprite;
-
- s.dispatchEvent(event);
- }
- };
-
- /**
- * Used to dispatch error events from internal preloading.
- * @param event
- * @protected
- * @since 0.6.0
- * @static
- */
- s._handleLoadError = function(event) {
- var src = event.target.getItem().src;
- if (!s._preloadHash[src]) {return;}
-
- for (var i = 0, l = s._preloadHash[src].length; i < l; i++) {
- var item = s._preloadHash[src][i];
- s._preloadHash[src][i] = false;
-
- if (!s.hasEventListener("fileerror")) { continue; }
-
- var event = new createjs.Event("fileerror");
- event.src = item.src;
- event.id = item.id;
- event.data = item.data;
- event.sprite = item.sprite;
-
- s.dispatchEvent(event);
- }
- };
-
- /**
- * Used by {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} to register a Sound plugin.
- *
- * @method _registerPlugin
- * @param {Object} plugin The plugin class to install.
- * @return {Boolean} Whether the plugin was successfully initialized.
- * @static
- * @private
- */
- s._registerPlugin = function (plugin) {
- // Note: Each plugin is passed in as a class reference, but we store the activePlugin as an instance
- if (plugin.isSupported()) {
- s.activePlugin = new plugin();
- return true;
- }
- return false;
- };
-
- /**
- * Register a list of Sound plugins, in order of precedence. To register a single plugin, pass a single element in the array.
- *
- *
Example
- *
- * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/";
- * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]);
- *
- * @method registerPlugins
- * @param {Array} plugins An array of plugins classes to install.
- * @return {Boolean} Whether a plugin was successfully initialized.
- * @static
- */
- s.registerPlugins = function (plugins) {
- s._pluginsRegistered = true;
- for (var i = 0, l = plugins.length; i < l; i++) {
- if (s._registerPlugin(plugins[i])) {
- return true;
- }
- }
- return false;
- };
-
- /**
- * Initialize the default plugins. This method is automatically called when any audio is played or registered before
- * the user has manually registered plugins, and enables Sound to work without manual plugin setup. Currently, the
- * default plugins are {{#crossLink "WebAudioPlugin"}}{{/crossLink}} followed by {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.
- *
- *
Example
- *
- * if (!createjs.initializeDefaultPlugins()) { return; }
- *
- * @method initializeDefaultPlugins
- * @returns {Boolean} True if a plugin was initialized, false otherwise.
- * @since 0.4.0
- * @static
- */
- s.initializeDefaultPlugins = function () {
- if (s.activePlugin != null) {return true;}
- if (s._pluginsRegistered) {return false;}
- if (s.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin])) {return true;}
- return false;
- };
-
- /**
- * Determines if Sound has been initialized, and a plugin has been activated.
- *
- *
Example
- * This example sets up a Flash fallback, but only if there is no plugin specified yet.
- *
- * if (!createjs.Sound.isReady()) {
- * createjs.FlashAudioPlugin.swfPath = "../src/soundjs/flashaudio/";
- * createjs.Sound.registerPlugins([createjs.WebAudioPlugin, createjs.HTMLAudioPlugin, createjs.FlashAudioPlugin]);
- * }
- *
- * @method isReady
- * @return {Boolean} If Sound has initialized a plugin.
- * @static
- */
- s.isReady = function () {
- return (s.activePlugin != null);
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead.
- *
- * @method getCapabilities
- * @return {Object} An object containing the capabilities of the active plugin.
- * @static
- * @deprecated
- */
- s.getCapabilities = function () {
- if (s.activePlugin == null) {return null;}
- return s.activePlugin._capabilities;
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/capabilities:property"}}{{/crossLink}} instead.
- *
- * @method getCapability
- * @param {String} key The capability to retrieve
- * @return {Number|Boolean} The value of the capability.
- * @static
- * @see getCapabilities
- * @deprecated
- */
- s.getCapability = function (key) {
- if (s.activePlugin == null) {return null;}
- return s.activePlugin._capabilities[key];
- };
-
- /**
- * Process manifest items from PreloadJS. This method is intended
- * for usage by a plugin, and not for direct interaction.
- * @method initLoad
- * @param {Object} src The object to load.
- * @return {Object|AbstractLoader} An instance of AbstractLoader.
- * @protected
- * @static
- */
- s.initLoad = function (loadItem) {
- return s._registerSound(loadItem);
- };
-
- /**
- * Internal method for loading sounds. This should not be called directly.
- *
- * @method _registerSound
- * @param {Object} src The object to load, containing src property and optionally containing id and data.
- * @return {Object} An object with the modified values that were passed in, which defines the sound.
- * Returns false if the source cannot be parsed or no plugins can be initialized.
- * Returns true if the source is already loaded.
- * @static
- * @private
- * @since 0.6.0
- */
-
- s._registerSound = function (loadItem) {
- if (!s.initializeDefaultPlugins()) {return false;}
-
- var details;
- if (loadItem.src instanceof Object) {
- details = s._parseSrc(loadItem.src);
- details.src = loadItem.path + details.src;
- } else {
- details = s._parsePath(loadItem.src);
- }
- if (details == null) {return false;}
- loadItem.src = details.src;
- loadItem.type = "sound";
-
- var data = loadItem.data;
- var numChannels = null;
- if (data != null) {
- if (!isNaN(data.channels)) {
- numChannels = parseInt(data.channels);
- } else if (!isNaN(data)) {
- numChannels = parseInt(data);
- }
-
- if(data.audioSprite) {
- var sp;
- for(var i = data.audioSprite.length; i--; ) {
- sp = data.audioSprite[i];
- s._idHash[sp.id] = {src: loadItem.src, startTime: parseInt(sp.startTime), duration: parseInt(sp.duration)};
-
- if (sp.defaultPlayProps) {
- s._defaultPlayPropsHash[sp.id] = createjs.PlayPropsConfig.create(sp.defaultPlayProps);
- }
- }
- }
- }
- if (loadItem.id != null) {s._idHash[loadItem.id] = {src: loadItem.src}};
- var loader = s.activePlugin.register(loadItem);
-
- SoundChannel.create(loadItem.src, numChannels);
-
- // return the number of instances to the user. This will also be returned in the load event.
- if (data == null || !isNaN(data)) {
- loadItem.data = numChannels || SoundChannel.maxPerChannel();
- } else {
- loadItem.data.channels = numChannels || SoundChannel.maxPerChannel();
- }
-
- if (loader.type) {loadItem.type = loader.type;}
-
- if (loadItem.defaultPlayProps) {
- s._defaultPlayPropsHash[loadItem.src] = createjs.PlayPropsConfig.create(loadItem.defaultPlayProps);
- }
- return loader;
- };
-
- /**
- * Register an audio file for loading and future playback in Sound. This is automatically called when using
- * PreloadJS. It is recommended to register all sounds that
- * need to be played back in order to properly prepare and preload them. Sound does internal preloading when required.
- *
- *
Example
- *
- * createjs.Sound.alternateExtensions = ["mp3"];
- * createjs.Sound.on("fileload", handleLoad); // add an event listener for when load is completed
- * createjs.Sound.registerSound("myAudioPath/mySound.ogg", "myID", 3);
- * createjs.Sound.registerSound({ogg:"path1/mySound.ogg", mp3:"path2/mySoundNoExtension"}, "myID", 3);
- *
- *
- * @method registerSound
- * @param {String | Object} src The source or an Object with a "src" property or an Object with multiple extension labeled src properties.
- * @param {String} [id] An id specified by the user to play the sound later. Note id is required for when src is multiple extension labeled src properties.
- * @param {Number | Object} [data] Data associated with the item. Sound uses the data parameter as the number of
- * channels for an audio instance, however a "channels" property can be appended to the data object if it is used
- * for other information. The audio channels will set a default based on plugin if no value is found.
- * Sound also uses the data property to hold an {{#crossLink "AudioSprite"}}{{/crossLink}} array of objects in the following format {id, startTime, duration}.
- * id used to play the sound later, in the same manner as a sound src with an id.
- * startTime is the initial offset to start playback and loop from, in milliseconds.
- * duration is the amount of time to play the clip for, in milliseconds.
- * This allows Sound to support audio sprites that are played back by id.
- * @param {string} basePath Set a path that will be prepended to src for loading.
- * @param {Object | PlayPropsConfig} defaultPlayProps Optional Playback properties that will be set as the defaults on any new AbstractSoundInstance.
- * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for options.
- * @return {Object} An object with the modified values that were passed in, which defines the sound.
- * Returns false if the source cannot be parsed or no plugins can be initialized.
- * Returns true if the source is already loaded.
- * @static
- * @since 0.4.0
- */
- s.registerSound = function (src, id, data, basePath, defaultPlayProps) {
- var loadItem = {src: src, id: id, data:data, defaultPlayProps:defaultPlayProps};
- if (src instanceof Object && src.src) {
- basePath = id;
- loadItem = src;
- }
- loadItem = createjs.LoadItem.create(loadItem);
- loadItem.path = basePath;
-
- if (basePath != null && !(loadItem.src instanceof Object)) {loadItem.src = basePath + src;}
-
- var loader = s._registerSound(loadItem);
- if(!loader) {return false;}
-
- if (!s._preloadHash[loadItem.src]) { s._preloadHash[loadItem.src] = [];}
- s._preloadHash[loadItem.src].push(loadItem);
- if (s._preloadHash[loadItem.src].length == 1) {
- // OJR note this will disallow reloading a sound if loading fails or the source changes
- loader.on("complete", createjs.proxy(this._handleLoadComplete, this));
- loader.on("error", createjs.proxy(this._handleLoadError, this));
- s.activePlugin.preload(loader);
- } else {
- if (s._preloadHash[loadItem.src][0] == true) {return true;}
- }
-
- return loadItem;
- };
-
- /**
- * Register an array of audio files for loading and future playback in Sound. It is recommended to register all
- * sounds that need to be played back in order to properly prepare and preload them. Sound does internal preloading
- * when required.
- *
- *
Example
- *
- * var assetPath = "./myAudioPath/";
- * var sounds = [
- * {src:"asset0.ogg", id:"example"},
- * {src:"asset1.ogg", id:"1", data:6},
- * {src:"asset2.mp3", id:"works"}
- * {src:{mp3:"path1/asset3.mp3", ogg:"path2/asset3NoExtension"}, id:"better"}
- * ];
- * createjs.Sound.alternateExtensions = ["mp3"]; // if the passed extension is not supported, try this extension
- * createjs.Sound.on("fileload", handleLoad); // call handleLoad when each sound loads
- * createjs.Sound.registerSounds(sounds, assetPath);
- *
- * @method registerSounds
- * @param {Array} sounds An array of objects to load. Objects are expected to be in the format needed for
- * {{#crossLink "Sound/registerSound"}}{{/crossLink}}: {src:srcURI, id:ID, data:Data}
- * with "id" and "data" being optional.
- * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to load.
- * Note id is required if src is an object with extension labeled src properties.
- * @param {string} basePath Set a path that will be prepended to each src when loading. When creating, playing, or removing
- * audio that was loaded with a basePath by src, the basePath must be included.
- * @return {Object} An array of objects with the modified values that were passed in, which defines each sound.
- * Like registerSound, it will return false for any values when the source cannot be parsed or if no plugins can be initialized.
- * Also, it will return true for any values when the source is already loaded.
- * @static
- * @since 0.6.0
- */
- s.registerSounds = function (sounds, basePath) {
- var returnValues = [];
- if (sounds.path) {
- if (!basePath) {
- basePath = sounds.path;
- } else {
- basePath = basePath + sounds.path;
- }
- sounds = sounds.manifest;
- // TODO document this feature
- }
- for (var i = 0, l = sounds.length; i < l; i++) {
- returnValues[i] = createjs.Sound.registerSound(sounds[i].src, sounds[i].id, sounds[i].data, basePath, sounds[i].defaultPlayProps);
- }
- return returnValues;
- };
-
- /**
- * Remove a sound that has been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or
- * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.
- * Note this will stop playback on active instances playing this sound before deleting them.
- * Note if you passed in a basePath, you need to pass it or prepend it to the src here.
- *
- *
Example
- *
- * createjs.Sound.removeSound("myID");
- * createjs.Sound.removeSound("myAudioBasePath/mySound.ogg");
- * createjs.Sound.removeSound("myPath/myOtherSound.mp3", "myBasePath/");
- * createjs.Sound.removeSound({mp3:"musicNoExtension", ogg:"music.ogg"}, "myBasePath/");
- *
- * @method removeSound
- * @param {String | Object} src The src or ID of the audio, or an Object with a "src" property, or an Object with multiple extension labeled src properties.
- * @param {string} basePath Set a path that will be prepended to each src when removing.
- * @return {Boolean} True if sound is successfully removed.
- * @static
- * @since 0.4.1
- */
- s.removeSound = function(src, basePath) {
- if (s.activePlugin == null) {return false;}
-
- if (src instanceof Object && src.src) {src = src.src;}
-
- var details;
- if (src instanceof Object) {
- details = s._parseSrc(src);
- } else {
- src = s._getSrcById(src).src;
- details = s._parsePath(src);
- }
- if (details == null) {return false;}
- src = details.src;
- if (basePath != null) {src = basePath + src;}
-
- for(var prop in s._idHash){
- if(s._idHash[prop].src == src) {
- delete(s._idHash[prop]);
- }
- }
-
- // clear from SoundChannel, which also stops and deletes all instances
- SoundChannel.removeSrc(src);
-
- delete(s._preloadHash[src]);
-
- s.activePlugin.removeSound(src);
-
- return true;
- };
-
- /**
- * Remove an array of audio files that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or
- * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.
- * Note this will stop playback on active instances playing this audio before deleting them.
- * Note if you passed in a basePath, you need to pass it or prepend it to the src here.
- *
- *
Example
- *
- * assetPath = "./myPath/";
- * var sounds = [
- * {src:"asset0.ogg", id:"example"},
- * {src:"asset1.ogg", id:"1", data:6},
- * {src:"asset2.mp3", id:"works"}
- * ];
- * createjs.Sound.removeSounds(sounds, assetPath);
- *
- * @method removeSounds
- * @param {Array} sounds An array of objects to remove. Objects are expected to be in the format needed for
- * {{#crossLink "Sound/removeSound"}}{{/crossLink}}: {srcOrID:srcURIorID}.
- * You can also pass an object with path and manifest properties, where path is a basePath and manifest is an array of objects to remove.
- * @param {string} basePath Set a path that will be prepended to each src when removing.
- * @return {Object} An array of Boolean values representing if the sounds with the same array index were
- * successfully removed.
- * @static
- * @since 0.4.1
- */
- s.removeSounds = function (sounds, basePath) {
- var returnValues = [];
- if (sounds.path) {
- if (!basePath) {
- basePath = sounds.path;
- } else {
- basePath = basePath + sounds.path;
- }
- sounds = sounds.manifest;
- }
- for (var i = 0, l = sounds.length; i < l; i++) {
- returnValues[i] = createjs.Sound.removeSound(sounds[i].src, basePath);
- }
- return returnValues;
- };
-
- /**
- * Remove all sounds that have been registered with {{#crossLink "Sound/registerSound"}}{{/crossLink}} or
- * {{#crossLink "Sound/registerSounds"}}{{/crossLink}}.
- * Note this will stop playback on all active sound instances before deleting them.
- *
- *
Example
- *
- * createjs.Sound.removeAllSounds();
- *
- * @method removeAllSounds
- * @static
- * @since 0.4.1
- */
- s.removeAllSounds = function() {
- s._idHash = {};
- s._preloadHash = {};
- SoundChannel.removeAll();
- if (s.activePlugin) {s.activePlugin.removeAllSounds();}
- };
-
- /**
- * Check if a source has been loaded by internal preloaders. This is necessary to ensure that sounds that are
- * not completed preloading will not kick off a new internal preload if they are played.
- *
- *
Example
- *
- * var mySound = "assetPath/asset0.ogg";
- * if(createjs.Sound.loadComplete(mySound) {
- * createjs.Sound.play(mySound);
- * }
- *
- * @method loadComplete
- * @param {String} src The src or id that is being loaded.
- * @return {Boolean} If the src is already loaded.
- * @since 0.4.0
- * @static
- */
- s.loadComplete = function (src) {
- if (!s.isReady()) { return false; }
- var details = s._parsePath(src);
- if (details) {
- src = s._getSrcById(details.src).src;
- } else {
- src = s._getSrcById(src).src;
- }
- if(s._preloadHash[src] == undefined) {return false;}
- return (s._preloadHash[src][0] == true); // src only loads once, so if it's true for the first it's true for all
- };
-
- /**
- * Parse the path of a sound. Alternate extensions will be attempted in order if the
- * current extension is not supported
- * @method _parsePath
- * @param {String} value The path to an audio source.
- * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}}
- * and returned to a preloader like PreloadJS.
- * @protected
- * @static
- */
- s._parsePath = function (value) {
- if (typeof(value) != "string") {value = value.toString();}
-
- var match = value.match(s.FILE_PATTERN);
- if (match == null) {return false;}
-
- var name = match[4];
- var ext = match[5];
- var c = s.capabilities;
- var i = 0;
- while (!c[ext]) {
- ext = s.alternateExtensions[i++];
- if (i > s.alternateExtensions.length) { return null;} // no extensions are supported
- }
- value = value.replace("."+match[5], "."+ext);
-
- var ret = {name:name, src:value, extension:ext};
- return ret;
- };
-
- /**
- * Parse the path of a sound based on properties of src matching with supported extensions.
- * Returns false if none of the properties are supported
- * @method _parseSrc
- * @param {Object} value The paths to an audio source, indexed by extension type.
- * @return {Object} A formatted object that can be registered with the {{#crossLink "Sound/activePlugin:property"}}{{/crossLink}}
- * and returned to a preloader like PreloadJS.
- * @protected
- * @static
- */
- s._parseSrc = function (value) {
- var ret = {name:undefined, src:undefined, extension:undefined};
- var c = s.capabilities;
-
- for (var prop in value) {
- if(value.hasOwnProperty(prop) && c[prop]) {
- ret.src = value[prop];
- ret.extension = prop;
- break;
- }
- }
- if (!ret.src) {return false;} // no matches
-
- var i = ret.src.lastIndexOf("/");
- if (i != -1) {
- ret.name = ret.src.slice(i+1);
- } else {
- ret.name = ret.src;
- }
-
- return ret;
- };
-
- /* ---------------
- Static API.
- --------------- */
- /**
- * Play a sound and get a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to control. If the sound fails to play, a
- * AbstractSoundInstance will still be returned, and have a playState of {{#crossLink "Sound/PLAY_FAILED:property"}}{{/crossLink}}.
- * Note that even on sounds with failed playback, you may still be able to call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}},
- * since the failure could be due to lack of available channels. If the src does not have a supported extension or
- * if there is no available plugin, a default AbstractSoundInstance will be returned which will not play any audio, but will not generate errors.
- *
- *
Example
- *
- * createjs.Sound.on("fileload", handleLoad);
- * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3);
- * function handleLoad(event) {
- * createjs.Sound.play("myID");
- * // store off AbstractSoundInstance for controlling
- * var myInstance = createjs.Sound.play("myID", {interrupt: createjs.Sound.INTERRUPT_ANY, loop:-1});
- * }
- *
- * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set.
- * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite.
- *
- * Parameters Deprecated
- * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}.
- *
- * @method play
- * @param {String} src The src or ID of the audio.
- * @param {String | Object} [interrupt="none"|options] This parameter will be renamed playProps in the next release.
- * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name,
- * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample).
- * OR
- * Deprecated How to interrupt any currently playing instances of audio with the same source,
- * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE
- * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
- * @param {Number} [delay=0] Deprecated The amount of time to delay the start of audio playback, in milliseconds.
- * @param {Number} [offset=0] Deprecated The offset from the start of the audio to begin playback, in milliseconds.
- * @param {Number} [loop=0] Deprecated How many times the audio loops when it reaches the end of playback. The default is 0 (no
- * loops), and -1 can be used for infinite playback.
- * @param {Number} [volume=1] Deprecated The volume of the sound, between 0 and 1. Note that the master volume is applied
- * against the individual volume.
- * @param {Number} [pan=0] Deprecated The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
- * @param {Number} [startTime=null] Deprecated To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
- * @param {Number} [duration=null] Deprecated To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
- * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created.
- * @static
- */
- s.play = function (src, interrupt, delay, offset, loop, volume, pan, startTime, duration) {
- var playProps;
- if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) {
- playProps = createjs.PlayPropsConfig.create(interrupt);
- } else {
- playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan, startTime:startTime, duration:duration});
- }
- var instance = s.createInstance(src, playProps.startTime, playProps.duration);
- var ok = s._playInstance(instance, playProps);
- if (!ok) {instance._playFailed();}
- return instance;
- };
-
- /**
- * Creates a {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} using the passed in src. If the src does not have a
- * supported extension or if there is no available plugin, a default AbstractSoundInstance will be returned that can be
- * called safely but does nothing.
- *
- *
Example
- *
- * var myInstance = null;
- * createjs.Sound.on("fileload", handleLoad);
- * createjs.Sound.registerSound("myAudioPath/mySound.mp3", "myID", 3);
- * function handleLoad(event) {
- * myInstance = createjs.Sound.createInstance("myID");
- * // alternately we could call the following
- * myInstance = createjs.Sound.createInstance("myAudioPath/mySound.mp3");
- * }
- *
- * NOTE to create an audio sprite that has not already been registered, both startTime and duration need to be set.
- * This is only when creating a new audio sprite, not when playing using the id of an already registered audio sprite.
- *
- * @method createInstance
- * @param {String} src The src or ID of the audio.
- * @param {Number} [startTime=null] To create an audio sprite (with duration), the initial offset to start playback and loop from, in milliseconds.
- * @param {Number} [duration=null] To create an audio sprite (with startTime), the amount of time to play the clip for, in milliseconds.
- * @return {AbstractSoundInstance} A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} that can be controlled after it is created.
- * Unsupported extensions will return the default AbstractSoundInstance.
- * @since 0.4.0
- * @static
- */
- s.createInstance = function (src, startTime, duration) {
- if (!s.initializeDefaultPlugins()) {return new createjs.DefaultSoundInstance(src, startTime, duration);}
-
- var defaultPlayProps = s._defaultPlayPropsHash[src]; // for audio sprites, which create and store defaults by id
- src = s._getSrcById(src);
-
- var details = s._parsePath(src.src);
-
- var instance = null;
- if (details != null && details.src != null) {
- SoundChannel.create(details.src);
- if (startTime == null) {startTime = src.startTime;}
- instance = s.activePlugin.create(details.src, startTime, duration || src.duration);
-
- defaultPlayProps = defaultPlayProps || s._defaultPlayPropsHash[details.src];
- if(defaultPlayProps) {
- instance.applyPlayProps(defaultPlayProps);
- }
- } else {
- instance = new createjs.DefaultSoundInstance(src, startTime, duration);
- }
-
- instance.uniqueId = s._lastID++;
-
- return instance;
- };
-
- /**
- * Stop all audio (global stop). Stopped audio is reset, and not paused. To play audio that has been stopped,
- * call AbstractSoundInstance {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}.
- *
- *
Example
- *
- * createjs.Sound.stop();
- *
- * @method stop
- * @static
- */
- s.stop = function () {
- var instances = this._instances;
- for (var i = instances.length; i--; ) {
- instances[i].stop(); // NOTE stop removes instance from this._instances
- }
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead.
- *
- * @method setVolume
- * @param {Number} value The master volume value. The acceptable range is 0-1.
- * @static
- * @deprecated
- */
- s.setVolume = function (value) {
- if (Number(value) == null) {return false;}
- value = Math.max(0, Math.min(1, value));
- s._masterVolume = value;
- if (!this.activePlugin || !this.activePlugin.setVolume || !this.activePlugin.setVolume(value)) {
- var instances = this._instances;
- for (var i = 0, l = instances.length; i < l; i++) {
- instances[i].setMasterVolume(value);
- }
- }
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/volume:property"}}{{/crossLink}} instead.
- *
- * @method getVolume
- * @return {Number} The master volume, in a range of 0-1.
- * @static
- * @deprecated
- */
- s.getVolume = function () {
- return this._masterVolume;
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead.
- *
- * @method setMute
- * @param {Boolean} value Whether the audio should be muted or not.
- * @return {Boolean} If the mute was set.
- * @static
- * @since 0.4.0
- * @deprecated
- */
- s.setMute = function (value) {
- if (value == null) {return false;}
-
- this._masterMute = value;
- if (!this.activePlugin || !this.activePlugin.setMute || !this.activePlugin.setMute(value)) {
- var instances = this._instances;
- for (var i = 0, l = instances.length; i < l; i++) {
- instances[i].setMasterMute(value);
- }
- }
- return true;
- };
-
- /**
- * Deprecated, please use {{#crossLink "Sound/muted:property"}}{{/crossLink}} instead.
- *
- * @method getMute
- * @return {Boolean} The mute value of Sound.
- * @static
- * @since 0.4.0
- * @deprecated
- */
- s.getMute = function () {
- return this._masterMute;
- };
-
- /**
- * Set the default playback properties for all new SoundInstances of the passed in src or ID.
- * See {{#crossLink "PlayPropsConfig"}}{{/crossLink}} for available properties.
- *
- * @method setDefaultPlayProps
- * @param {String} src The src or ID used to register the audio.
- * @param {Object | PlayPropsConfig} playProps The playback properties you would like to set.
- * @since 0.6.1
- */
- s.setDefaultPlayProps = function(src, playProps) {
- src = s._getSrcById(src);
- s._defaultPlayPropsHash[s._parsePath(src.src).src] = createjs.PlayPropsConfig.create(playProps);
- };
-
- /**
- * Get the default playback properties for the passed in src or ID. These properties are applied to all
- * new SoundInstances. Returns null if default does not exist.
- *
- * @method getDefaultPlayProps
- * @param {String} src The src or ID used to register the audio.
- * @returns {PlayPropsConfig} returns an existing PlayPropsConfig or null if one does not exist
- * @since 0.6.1
- */
- s.getDefaultPlayProps = function(src) {
- src = s._getSrcById(src);
- return s._defaultPlayPropsHash[s._parsePath(src.src).src];
- };
-
-
- /* ---------------
- Internal methods
- --------------- */
- /**
- * Play an instance. This is called by the static API, as well as from plugins. This allows the core class to
- * control delays.
- * @method _playInstance
- * @param {AbstractSoundInstance} instance The {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to start playing.
- * @param {PlayPropsConfig} playProps A PlayPropsConfig object.
- * @return {Boolean} If the sound can start playing. Sounds that fail immediately will return false. Sounds that
- * have a delay will return true, but may still fail to play.
- * @protected
- * @static
- */
- s._playInstance = function (instance, playProps) {
- var defaultPlayProps = s._defaultPlayPropsHash[instance.src] || {};
- if (playProps.interrupt == null) {playProps.interrupt = defaultPlayProps.interrupt || s.defaultInterruptBehavior};
- if (playProps.delay == null) {playProps.delay = defaultPlayProps.delay || 0;}
- if (playProps.offset == null) {playProps.offset = instance.getPosition();}
- if (playProps.loop == null) {playProps.loop = instance.loop;}
- if (playProps.volume == null) {playProps.volume = instance.volume;}
- if (playProps.pan == null) {playProps.pan = instance.pan;}
-
- if (playProps.delay == 0) {
- var ok = s._beginPlaying(instance, playProps);
- if (!ok) {return false;}
- } else {
- //Note that we can't pass arguments to proxy OR setTimeout (IE only), so just wrap the function call.
- // OJR WebAudio may want to handle this differently, so it might make sense to move this functionality into the plugins in the future
- var delayTimeoutId = setTimeout(function () {
- s._beginPlaying(instance, playProps);
- }, playProps.delay);
- instance.delayTimeoutId = delayTimeoutId;
- }
-
- this._instances.push(instance);
-
- return true;
- };
-
- /**
- * Begin playback. This is called immediately or after delay by {{#crossLink "Sound/playInstance"}}{{/crossLink}}.
- * @method _beginPlaying
- * @param {AbstractSoundInstance} instance A {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} to begin playback.
- * @param {PlayPropsConfig} playProps A PlayPropsConfig object.
- * @return {Boolean} If the sound can start playing. If there are no available channels, or the instance fails to
- * start, this will return false.
- * @protected
- * @static
- */
- s._beginPlaying = function (instance, playProps) {
- if (!SoundChannel.add(instance, playProps.interrupt)) {
- return false;
- }
- var result = instance._beginPlaying(playProps);
- if (!result) {
- var index = createjs.indexOf(this._instances, instance);
- if (index > -1) {this._instances.splice(index, 1);}
- return false;
- }
- return true;
- };
-
- /**
- * Get the source of a sound via the ID passed in with a register call. If no ID is found the value is returned
- * instead.
- * @method _getSrcById
- * @param {String} value The ID the sound was registered with.
- * @return {String} The source of the sound if it has been registered with this ID or the value that was passed in.
- * @protected
- * @static
- */
- s._getSrcById = function (value) {
- return s._idHash[value] || {src: value};
- };
-
- /**
- * A sound has completed playback, been interrupted, failed, or been stopped. This method removes the instance from
- * Sound management. It will be added again, if the sound re-plays. Note that this method is called from the
- * instances themselves.
- * @method _playFinished
- * @param {AbstractSoundInstance} instance The instance that finished playback.
- * @protected
- * @static
- */
- s._playFinished = function (instance) {
- SoundChannel.remove(instance);
- var index = createjs.indexOf(this._instances, instance);
- if (index > -1) {this._instances.splice(index, 1);} // OJR this will always be > -1, there is no way for an instance to exist without being added to this._instances
- };
-
- createjs.Sound = Sound;
-
- /**
- * An internal class that manages the number of active {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} instances for
- * each sound type. This method is only used internally by the {{#crossLink "Sound"}}{{/crossLink}} class.
- *
- * The number of sounds is artificially limited by Sound in order to prevent over-saturation of a
- * single sound, as well as to stay within hardware limitations, although the latter may disappear with better
- * browser support.
- *
- * When a sound is played, this class ensures that there is an available instance, or interrupts an appropriate
- * sound that is already playing.
- * #class SoundChannel
- * @param {String} src The source of the instances
- * @param {Number} [max=1] The number of instances allowed
- * @constructor
- * @protected
- */
- function SoundChannel(src, max) {
- this.init(src, max);
- }
-
- /* ------------
- Static API
- ------------ */
- /**
- * A hash of channel instances indexed by source.
- * #property channels
- * @type {Object}
- * @static
- */
- SoundChannel.channels = {};
-
- /**
- * Create a sound channel. Note that if the sound channel already exists, this will fail.
- * #method create
- * @param {String} src The source for the channel
- * @param {Number} max The maximum amount this channel holds. The default is {{#crossLink "SoundChannel.maxDefault"}}{{/crossLink}}.
- * @return {Boolean} If the channels were created.
- * @static
- */
- SoundChannel.create = function (src, max) {
- var channel = SoundChannel.get(src);
- if (channel == null) {
- SoundChannel.channels[src] = new SoundChannel(src, max);
- return true;
- }
- return false;
- };
- /**
- * Delete a sound channel, stop and delete all related instances. Note that if the sound channel does not exist, this will fail.
- * #method remove
- * @param {String} src The source for the channel
- * @return {Boolean} If the channels were deleted.
- * @static
- */
- SoundChannel.removeSrc = function (src) {
- var channel = SoundChannel.get(src);
- if (channel == null) {return false;}
- channel._removeAll(); // this stops and removes all active instances
- delete(SoundChannel.channels[src]);
- return true;
- };
- /**
- * Delete all sound channels, stop and delete all related instances.
- * #method removeAll
- * @static
- */
- SoundChannel.removeAll = function () {
- for(var channel in SoundChannel.channels) {
- SoundChannel.channels[channel]._removeAll(); // this stops and removes all active instances
- }
- SoundChannel.channels = {};
- };
- /**
- * Add an instance to a sound channel.
- * #method add
- * @param {AbstractSoundInstance} instance The instance to add to the channel
- * @param {String} interrupt The interrupt value to use. Please see the {{#crossLink "Sound/play"}}{{/crossLink}}
- * for details on interrupt modes.
- * @return {Boolean} The success of the method call. If the channel is full, it will return false.
- * @static
- */
- SoundChannel.add = function (instance, interrupt) {
- var channel = SoundChannel.get(instance.src);
- if (channel == null) {return false;}
- return channel._add(instance, interrupt);
- };
- /**
- * Remove an instance from the channel.
- * #method remove
- * @param {AbstractSoundInstance} instance The instance to remove from the channel
- * @return The success of the method call. If there is no channel, it will return false.
- * @static
- */
- SoundChannel.remove = function (instance) {
- var channel = SoundChannel.get(instance.src);
- if (channel == null) {return false;}
- channel._remove(instance);
- return true;
- };
- /**
- * Get the maximum number of sounds you can have in a channel.
- * #method maxPerChannel
- * @return {Number} The maximum number of sounds you can have in a channel.
- */
- SoundChannel.maxPerChannel = function () {
- return p.maxDefault;
- };
- /**
- * Get a channel instance by its src.
- * #method get
- * @param {String} src The src to use to look up the channel
- * @static
- */
- SoundChannel.get = function (src) {
- return SoundChannel.channels[src];
- };
-
- var p = SoundChannel.prototype;
- p.constructor = SoundChannel;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
- /**
- * The source of the channel.
- * #property src
- * @type {String}
- */
- p.src = null;
-
- /**
- * The maximum number of instances in this channel. -1 indicates no limit
- * #property max
- * @type {Number}
- */
- p.max = null;
-
- /**
- * The default value to set for max, if it isn't passed in. Also used if -1 is passed.
- * #property maxDefault
- * @type {Number}
- * @default 100
- * @since 0.4.0
- */
- p.maxDefault = 100;
-
- /**
- * The current number of active instances.
- * #property length
- * @type {Number}
- */
- p.length = 0;
-
- /**
- * Initialize the channel.
- * #method init
- * @param {String} src The source of the channel
- * @param {Number} max The maximum number of instances in the channel
- * @protected
- */
- p.init = function (src, max) {
- this.src = src;
- this.max = max || this.maxDefault;
- if (this.max == -1) {this.max = this.maxDefault;}
- this._instances = [];
- };
-
- /**
- * Get an instance by index.
- * #method get
- * @param {Number} index The index to return.
- * @return {AbstractSoundInstance} The AbstractSoundInstance at a specific instance.
- */
- p._get = function (index) {
- return this._instances[index];
- };
-
- /**
- * Add a new instance to the channel.
- * #method add
- * @param {AbstractSoundInstance} instance The instance to add.
- * @return {Boolean} The success of the method call. If the channel is full, it will return false.
- */
- p._add = function (instance, interrupt) {
- if (!this._getSlot(interrupt, instance)) {return false;}
- this._instances.push(instance);
- this.length++;
- return true;
- };
-
- /**
- * Remove an instance from the channel, either when it has finished playing, or it has been interrupted.
- * #method remove
- * @param {AbstractSoundInstance} instance The instance to remove
- * @return {Boolean} The success of the remove call. If the instance is not found in this channel, it will
- * return false.
- */
- p._remove = function (instance) {
- var index = createjs.indexOf(this._instances, instance);
- if (index == -1) {return false;}
- this._instances.splice(index, 1);
- this.length--;
- return true;
- };
-
- /**
- * Stop playback and remove all instances from the channel. Usually in response to a delete call.
- * #method removeAll
- */
- p._removeAll = function () {
- // Note that stop() removes the item from the list
- for (var i=this.length-1; i>=0; i--) {
- this._instances[i].stop();
- }
- };
-
- /**
- * Get an available slot depending on interrupt value and if slots are available.
- * #method getSlot
- * @param {String} interrupt The interrupt value to use.
- * @param {AbstractSoundInstance} instance The sound instance that will go in the channel if successful.
- * @return {Boolean} Determines if there is an available slot. Depending on the interrupt mode, if there are no slots,
- * an existing AbstractSoundInstance may be interrupted. If there are no slots, this method returns false.
- */
- p._getSlot = function (interrupt, instance) {
- var target, replacement;
-
- if (interrupt != Sound.INTERRUPT_NONE) {
- // First replacement candidate
- replacement = this._get(0);
- if (replacement == null) {
- return true;
- }
- }
-
- for (var i = 0, l = this.max; i < l; i++) {
- target = this._get(i);
-
- // Available Space
- if (target == null) {
- return true;
- }
-
- // Audio is complete or not playing
- if (target.playState == Sound.PLAY_FINISHED ||
- target.playState == Sound.PLAY_INTERRUPTED ||
- target.playState == Sound.PLAY_FAILED) {
- replacement = target;
- break;
- }
-
- if (interrupt == Sound.INTERRUPT_NONE) {
- continue;
- }
-
- // Audio is a better candidate than the current target, according to playhead
- if ((interrupt == Sound.INTERRUPT_EARLY && target.getPosition() < replacement.getPosition()) ||
- (interrupt == Sound.INTERRUPT_LATE && target.getPosition() > replacement.getPosition())) {
- replacement = target;
- }
- }
-
- if (replacement != null) {
- replacement._interrupt();
- this._remove(replacement);
- return true;
- }
- return false;
- };
-
- p.toString = function () {
- return "[Sound SoundChannel]";
- };
- // do not add SoundChannel to namespace
-
-}());
-
-//##############################################################################
-// AbstractSoundInstance.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-/**
- * A AbstractSoundInstance is created when any calls to the Sound API method {{#crossLink "Sound/play"}}{{/crossLink}} or
- * {{#crossLink "Sound/createInstance"}}{{/crossLink}} are made. The AbstractSoundInstance is returned by the active plugin
- * for control by the user.
- *
- *
Example
- *
- * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3");
- *
- * A number of additional parameters provide a quick way to determine how a sound is played. Please see the Sound
- * API method {{#crossLink "Sound/play"}}{{/crossLink}} for a list of arguments.
- *
- * Once a AbstractSoundInstance is created, a reference can be stored that can be used to control the audio directly through
- * the AbstractSoundInstance. If the reference is not stored, the AbstractSoundInstance will play out its audio (and any loops), and
- * is then de-referenced from the {{#crossLink "Sound"}}{{/crossLink}} class so that it can be cleaned up. If audio
- * playback has completed, a simple call to the {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}} instance method
- * will rebuild the references the Sound class need to control it.
- *
- * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3", {loop:2});
- * myInstance.on("loop", handleLoop);
- * function handleLoop(event) {
- * myInstance.volume = myInstance.volume * 0.5;
- * }
- *
- * Events are dispatched from the instance to notify when the sound has completed, looped, or when playback fails
- *
- * var myInstance = createjs.Sound.play("myAssetPath/mySrcFile.mp3");
- * myInstance.on("complete", handleComplete);
- * myInstance.on("loop", handleLoop);
- * myInstance.on("failed", handleFailed);
- *
- *
- * @class AbstractSoundInstance
- * @param {String} src The path to and file name of the sound.
- * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.
- * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.
- * @param {Object} playbackResource Any resource needed by plugin to support audio playback.
- * @extends EventDispatcher
- * @constructor
- */
-
-(function () {
- "use strict";
-
-
-// Constructor:
- var AbstractSoundInstance = function (src, startTime, duration, playbackResource) {
- this.EventDispatcher_constructor();
-
-
- // public properties:
- /**
- * The source of the sound.
- * @property src
- * @type {String}
- * @default null
- */
- this.src = src;
-
- /**
- * The unique ID of the instance. This is set by {{#crossLink "Sound"}}{{/crossLink}}.
- * @property uniqueId
- * @type {String} | Number
- * @default -1
- */
- this.uniqueId = -1;
-
- /**
- * The play state of the sound. Play states are defined as constants on {{#crossLink "Sound"}}{{/crossLink}}.
- * @property playState
- * @type {String}
- * @default null
- */
- this.playState = null;
-
- /**
- * A Timeout created by {{#crossLink "Sound"}}{{/crossLink}} when this AbstractSoundInstance is played with a delay.
- * This allows AbstractSoundInstance to remove the delay if stop, pause, or cleanup are called before playback begins.
- * @property delayTimeoutId
- * @type {timeoutVariable}
- * @default null
- * @protected
- * @since 0.4.0
- */
- this.delayTimeoutId = null;
- // TODO consider moving delay into AbstractSoundInstance so it can be handled by plugins
-
-
- // private properties
- // Getter / Setter Properties
- // OJR TODO find original reason that we didn't use defined functions. I think it was performance related
- /**
- * The volume of the sound, between 0 and 1.
- *
- * The actual output volume of a sound can be calculated using:
- * myInstance.volume * createjs.Sound.getVolume();
- *
- * @property volume
- * @type {Number}
- * @default 1
- */
- this._volume = 1;
- Object.defineProperty(this, "volume", {
- get: this.getVolume,
- set: this.setVolume
- });
-
- /**
- * The pan of the sound, between -1 (left) and 1 (right). Note that pan is not supported by HTML Audio.
- *
- * Note in WebAudioPlugin this only gives us the "x" value of what is actually 3D audio.
- *
- * @property pan
- * @type {Number}
- * @default 0
- */
- this._pan = 0;
- Object.defineProperty(this, "pan", {
- get: this.getPan,
- set: this.setPan
- });
-
- /**
- * Audio sprite property used to determine the starting offset.
- * @property startTime
- * @type {Number}
- * @default 0
- * @since 0.6.1
- */
- this._startTime = Math.max(0, startTime || 0);
- Object.defineProperty(this, "startTime", {
- get: this.getStartTime,
- set: this.setStartTime
- });
-
- /**
- * Sets or gets the length of the audio clip, value is in milliseconds.
- *
- * @property duration
- * @type {Number}
- * @default 0
- * @since 0.6.0
- */
- this._duration = Math.max(0, duration || 0);
- Object.defineProperty(this, "duration", {
- get: this.getDuration,
- set: this.setDuration
- });
-
- /**
- * Object that holds plugin specific resource need for audio playback.
- * This is set internally by the plugin. For example, WebAudioPlugin will set an array buffer,
- * HTMLAudioPlugin will set a tag, FlashAudioPlugin will set a flash reference.
- *
- * @property playbackResource
- * @type {Object}
- * @default null
- */
- this._playbackResource = null;
- Object.defineProperty(this, "playbackResource", {
- get: this.getPlaybackResource,
- set: this.setPlaybackResource
- });
- if(playbackResource !== false && playbackResource !== true) { this.setPlaybackResource(playbackResource); }
-
- /**
- * The position of the playhead in milliseconds. This can be set while a sound is playing, paused, or stopped.
- *
- * @property position
- * @type {Number}
- * @default 0
- * @since 0.6.0
- */
- this._position = 0;
- Object.defineProperty(this, "position", {
- get: this.getPosition,
- set: this.setPosition
- });
-
- /**
- * The number of play loops remaining. Negative values will loop infinitely.
- *
- * @property loop
- * @type {Number}
- * @default 0
- * @public
- * @since 0.6.0
- */
- this._loop = 0;
- Object.defineProperty(this, "loop", {
- get: this.getLoop,
- set: this.setLoop
- });
-
- /**
- * Mutes or unmutes the current audio instance.
- *
- * @property muted
- * @type {Boolean}
- * @default false
- * @since 0.6.0
- */
- this._muted = false;
- Object.defineProperty(this, "muted", {
- get: this.getMuted,
- set: this.setMuted
- });
-
- /**
- * Pauses or resumes the current audio instance.
- *
- * @property paused
- * @type {Boolean}
- */
- this._paused = false;
- Object.defineProperty(this, "paused", {
- get: this.getPaused,
- set: this.setPaused
- });
-
-
- // Events
- /**
- * The event that is fired when playback has started successfully.
- * @event succeeded
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.4.0
- */
-
- /**
- * The event that is fired when playback is interrupted. This happens when another sound with the same
- * src property is played using an interrupt value that causes this instance to stop playing.
- * @event interrupted
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.4.0
- */
-
- /**
- * The event that is fired when playback has failed. This happens when there are too many channels with the same
- * src property already playing (and the interrupt value doesn't cause an interrupt of another instance), or
- * the sound could not be played, perhaps due to a 404 error.
- * @event failed
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.4.0
- */
-
- /**
- * The event that is fired when a sound has completed playing but has loops remaining.
- * @event loop
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.4.0
- */
-
- /**
- * The event that is fired when playback completes. This means that the sound has finished playing in its
- * entirety, including its loop iterations.
- * @event complete
- * @param {Object} target The object that dispatched the event.
- * @param {String} type The event type.
- * @since 0.4.0
- */
- };
-
- var p = createjs.extend(AbstractSoundInstance, createjs.EventDispatcher);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// Public Methods:
- /**
- * Play an instance. This method is intended to be called on SoundInstances that already exist (created
- * with the Sound API {{#crossLink "Sound/createInstance"}}{{/crossLink}} or {{#crossLink "Sound/play"}}{{/crossLink}}).
- *
- *
Example
- *
- * var myInstance = createjs.Sound.createInstance(mySrc);
- * myInstance.play({interrupt:createjs.Sound.INTERRUPT_ANY, loop:2, pan:0.5});
- *
- * Note that if this sound is already playing, this call will still set the passed in parameters.
-
- * Parameters Deprecated
- * The parameters for this method are deprecated in favor of a single parameter that is an Object or {{#crossLink "PlayPropsConfig"}}{{/crossLink}}.
- *
- * @method play
- * @param {String | Object} [interrupt="none"|options] This parameter will be renamed playProps in the next release.
- * This parameter can be an instance of {{#crossLink "PlayPropsConfig"}}{{/crossLink}} or an Object that contains any or all optional properties by name,
- * including: interrupt, delay, offset, loop, volume, pan, startTime, and duration (see the above code sample).
- * OR
- * Deprecated How to interrupt any currently playing instances of audio with the same source,
- * if the maximum number of instances of the sound are already playing. Values are defined as INTERRUPT_TYPE
- * constants on the Sound class, with the default defined by {{#crossLink "Sound/defaultInterruptBehavior:property"}}{{/crossLink}}.
- * @param {Number} [delay=0] Deprecated The amount of time to delay the start of audio playback, in milliseconds.
- * @param {Number} [offset=0] Deprecated The offset from the start of the audio to begin playback, in milliseconds.
- * @param {Number} [loop=0] Deprecated How many times the audio loops when it reaches the end of playback. The default is 0 (no
- * loops), and -1 can be used for infinite playback.
- * @param {Number} [volume=1] Deprecated The volume of the sound, between 0 and 1. Note that the master volume is applied
- * against the individual volume.
- * @param {Number} [pan=0] Deprecated The left-right pan of the sound (if supported), between -1 (left) and 1 (right).
- * Note that pan is not supported for HTML Audio.
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- */
- p.play = function (interrupt, delay, offset, loop, volume, pan) {
- var playProps;
- if (interrupt instanceof Object || interrupt instanceof createjs.PlayPropsConfig) {
- playProps = createjs.PlayPropsConfig.create(interrupt);
- } else {
- playProps = createjs.PlayPropsConfig.create({interrupt:interrupt, delay:delay, offset:offset, loop:loop, volume:volume, pan:pan});
- }
-
- if (this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this.applyPlayProps(playProps);
- if (this._paused) { this.setPaused(false); }
- return;
- }
- this._cleanUp();
- createjs.Sound._playInstance(this, playProps); // make this an event dispatch??
- return this;
- };
-
- /**
- * Stop playback of the instance. Stopped sounds will reset their position to 0, and calls to {{#crossLink "AbstractSoundInstance/resume"}}{{/crossLink}}
- * will fail. To start playback again, call {{#crossLink "AbstractSoundInstance/play"}}{{/crossLink}}.
- *
- * If you don't want to lose your position use yourSoundInstance.paused = true instead. {{#crossLink "AbstractSoundInstance/paused"}}{{/crossLink}}.
- *
- *
Example
- *
- * myInstance.stop();
- *
- * @method stop
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- */
- p.stop = function () {
- this._position = 0;
- this._paused = false;
- this._handleStop();
- this._cleanUp();
- this.playState = createjs.Sound.PLAY_FINISHED;
- return this;
- };
-
- /**
- * Remove all external references and resources from AbstractSoundInstance. Note this is irreversible and AbstractSoundInstance will no longer work
- * @method destroy
- * @since 0.6.0
- */
- p.destroy = function() {
- this._cleanUp();
- this.src = null;
- this.playbackResource = null;
-
- this.removeAllEventListeners();
- };
-
- /**
- * Takes an PlayPropsConfig or Object with the same properties and sets them on this instance.
- * @method applyPlayProps
- * @param {PlayPropsConfig | Object} playProps A PlayPropsConfig or object containing the same properties.
- * @since 0.6.1
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- */
- p.applyPlayProps = function(playProps) {
- if (playProps.offset != null) { this.setPosition(playProps.offset) }
- if (playProps.loop != null) { this.setLoop(playProps.loop); }
- if (playProps.volume != null) { this.setVolume(playProps.volume); }
- if (playProps.pan != null) { this.setPan(playProps.pan); }
- if (playProps.startTime != null) {
- this.setStartTime(playProps.startTime);
- this.setDuration(playProps.duration);
- }
- return this;
- };
-
- p.toString = function () {
- return "[AbstractSoundInstance]";
- };
-
-// get/set methods that allow support for IE8
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property,
- *
- * @deprecated
- * @method getPaused
- * @returns {boolean} If the instance is currently paused
- * @since 0.6.0
- */
- p.getPaused = function() {
- return this._paused;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/paused:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setPaused
- * @param {boolean} value
- * @since 0.6.0
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- */
- p.setPaused = function (value) {
- if ((value !== true && value !== false) || this._paused == value) {return;}
- if (value == true && this.playState != createjs.Sound.PLAY_SUCCEEDED) {return;}
- this._paused = value;
- if(value) {
- this._pause();
- } else {
- this._resume();
- }
- clearTimeout(this.delayTimeoutId);
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setVolume
- * @param {Number} value The volume to set, between 0 and 1.
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- */
- p.setVolume = function (value) {
- if (value == this._volume) { return this; }
- this._volume = Math.max(0, Math.min(1, value));
- if (!this._muted) {
- this._updateVolume();
- }
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/volume:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getVolume
- * @return {Number} The current volume of the sound instance.
- */
- p.getVolume = function () {
- return this._volume;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setMuted
- * @param {Boolean} value If the sound should be muted.
- * @return {AbstractSoundInstance} A reference to itself, intended for chaining calls.
- * @since 0.6.0
- */
- p.setMuted = function (value) {
- if (value !== true && value !== false) {return;}
- this._muted = value;
- this._updateVolume();
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/muted:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getMuted
- * @return {Boolean} If the sound is muted.
- * @since 0.6.0
- */
- p.getMuted = function () {
- return this._muted;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setPan
- * @param {Number} value The pan value, between -1 (left) and 1 (right).
- * @return {AbstractSoundInstance} Returns reference to itself for chaining calls
- */
- p.setPan = function (value) {
- if(value == this._pan) { return this; }
- this._pan = Math.max(-1, Math.min(1, value));
- this._updatePan();
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/pan:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getPan
- * @return {Number} The value of the pan, between -1 (left) and 1 (right).
- */
- p.getPan = function () {
- return this._pan;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getPosition
- * @return {Number} The position of the playhead in the sound, in milliseconds.
- */
- p.getPosition = function () {
- if (!this._paused && this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this._position = this._calculateCurrentPosition();
- }
- return this._position;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/position:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setPosition
- * @param {Number} value The position to place the playhead, in milliseconds.
- * @return {AbstractSoundInstance} Returns reference to itself for chaining calls
- */
- p.setPosition = function (value) {
- this._position = Math.max(0, value);
- if (this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this._updatePosition();
- }
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getStartTime
- * @return {Number} The startTime of the sound instance in milliseconds.
- */
- p.getStartTime = function () {
- return this._startTime;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/startTime:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setStartTime
- * @param {number} value The new startTime time in milli seconds.
- * @return {AbstractSoundInstance} Returns reference to itself for chaining calls
- */
- p.setStartTime = function (value) {
- if (value == this._startTime) { return this; }
- this._startTime = Math.max(0, value || 0);
- this._updateStartTime();
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getDuration
- * @return {Number} The duration of the sound instance in milliseconds.
- */
- p.getDuration = function () {
- return this._duration;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/duration:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setDuration
- * @param {number} value The new duration time in milli seconds.
- * @return {AbstractSoundInstance} Returns reference to itself for chaining calls
- * @since 0.6.0
- */
- p.setDuration = function (value) {
- if (value == this._duration) { return this; }
- this._duration = Math.max(0, value || 0);
- this._updateDuration();
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setPlayback
- * @param {Object} value The new playback resource.
- * @return {AbstractSoundInstance} Returns reference to itself for chaining calls
- * @since 0.6.0
- **/
- p.setPlaybackResource = function (value) {
- this._playbackResource = value;
- if (this._duration == 0) { this._setDurationFromSource(); }
- return this;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/playbackResource:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method setPlayback
- * @param {Object} value The new playback resource.
- * @return {Object} playback resource used for playing audio
- * @since 0.6.0
- **/
- p.getPlaybackResource = function () {
- return this._playbackResource;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property
- *
- * @deprecated
- * @method getLoop
- * @return {number}
- * @since 0.6.0
- **/
- p.getLoop = function () {
- return this._loop;
- };
-
- /**
- * DEPRECATED, please use {{#crossLink "AbstractSoundInstance/loop:property"}}{{/crossLink}} directly as a property,
- *
- * @deprecated
- * @method setLoop
- * @param {number} value The number of times to loop after play.
- * @since 0.6.0
- */
- p.setLoop = function (value) {
- if(this._playbackResource != null) {
- // remove looping
- if (this._loop != 0 && value == 0) {
- this._removeLooping(value);
- }
- // add looping
- else if (this._loop == 0 && value != 0) {
- this._addLooping(value);
- }
- }
- this._loop = value;
- };
-
-
-// Private Methods:
- /**
- * A helper method that dispatches all events for AbstractSoundInstance.
- * @method _sendEvent
- * @param {String} type The event type
- * @protected
- */
- p._sendEvent = function (type) {
- var event = new createjs.Event(type);
- this.dispatchEvent(event);
- };
-
- /**
- * Clean up the instance. Remove references and clean up any additional properties such as timers.
- * @method _cleanUp
- * @protected
- */
- p._cleanUp = function () {
- clearTimeout(this.delayTimeoutId); // clear timeout that plays delayed sound
- this._handleCleanUp();
- this._paused = false;
-
- createjs.Sound._playFinished(this); // TODO change to an event
- };
-
- /**
- * The sound has been interrupted.
- * @method _interrupt
- * @protected
- */
- p._interrupt = function () {
- this._cleanUp();
- this.playState = createjs.Sound.PLAY_INTERRUPTED;
- this._sendEvent("interrupted");
- };
-
- /**
- * Called by the Sound class when the audio is ready to play (delay has completed). Starts sound playing if the
- * src is loaded, otherwise playback will fail.
- * @method _beginPlaying
- * @param {PlayPropsConfig} playProps A PlayPropsConfig object.
- * @return {Boolean} If playback succeeded.
- * @protected
- */
- // OJR FlashAudioSoundInstance overwrites
- p._beginPlaying = function (playProps) {
- this.setPosition(playProps.offset);
- this.setLoop(playProps.loop);
- this.setVolume(playProps.volume);
- this.setPan(playProps.pan);
- if (playProps.startTime != null) {
- this.setStartTime(playProps.startTime);
- this.setDuration(playProps.duration);
- }
-
- if (this._playbackResource != null && this._position < this._duration) {
- this._paused = false;
- this._handleSoundReady();
- this.playState = createjs.Sound.PLAY_SUCCEEDED;
- this._sendEvent("succeeded");
- return true;
- } else {
- this._playFailed();
- return false;
- }
- };
-
- /**
- * Play has failed, which can happen for a variety of reasons.
- * Cleans up instance and dispatches failed event
- * @method _playFailed
- * @private
- */
- p._playFailed = function () {
- this._cleanUp();
- this.playState = createjs.Sound.PLAY_FAILED;
- this._sendEvent("failed");
- };
-
- /**
- * Audio has finished playing. Manually loop it if required.
- * @method _handleSoundComplete
- * @param event
- * @protected
- */
- p._handleSoundComplete = function (event) {
- this._position = 0; // have to set this as it can be set by pause during playback
-
- if (this._loop != 0) {
- this._loop--; // NOTE this introduces a theoretical limit on loops = float max size x 2 - 1
- this._handleLoop();
- this._sendEvent("loop");
- return;
- }
-
- this._cleanUp();
- this.playState = createjs.Sound.PLAY_FINISHED;
- this._sendEvent("complete");
- };
-
-// Plugin specific code
- /**
- * Handles starting playback when the sound is ready for playing.
- * @method _handleSoundReady
- * @protected
- */
- p._handleSoundReady = function () {
- // plugin specific code
- };
-
- /**
- * Internal function used to update the volume based on the instance volume, master volume, instance mute value,
- * and master mute value.
- * @method _updateVolume
- * @protected
- */
- p._updateVolume = function () {
- // plugin specific code
- };
-
- /**
- * Internal function used to update the pan
- * @method _updatePan
- * @protected
- * @since 0.6.0
- */
- p._updatePan = function () {
- // plugin specific code
- };
-
- /**
- * Internal function used to update the startTime of the audio.
- * @method _updateStartTime
- * @protected
- * @since 0.6.1
- */
- p._updateStartTime = function () {
- // plugin specific code
- };
-
- /**
- * Internal function used to update the duration of the audio.
- * @method _updateDuration
- * @protected
- * @since 0.6.0
- */
- p._updateDuration = function () {
- // plugin specific code
- };
-
- /**
- * Internal function used to get the duration of the audio from the source we'll be playing.
- * @method _updateDuration
- * @protected
- * @since 0.6.0
- */
- p._setDurationFromSource = function () {
- // plugin specific code
- };
-
- /**
- * Internal function that calculates the current position of the playhead and sets this._position to that value
- * @method _calculateCurrentPosition
- * @protected
- * @since 0.6.0
- */
- p._calculateCurrentPosition = function () {
- // plugin specific code that sets this.position
- };
-
- /**
- * Internal function used to update the position of the playhead.
- * @method _updatePosition
- * @protected
- * @since 0.6.0
- */
- p._updatePosition = function () {
- // plugin specific code
- };
-
- /**
- * Internal function called when looping is removed during playback.
- * @method _removeLooping
- * @param {number} value The number of times to loop after play.
- * @protected
- * @since 0.6.0
- */
- p._removeLooping = function (value) {
- // plugin specific code
- };
-
- /**
- * Internal function called when looping is added during playback.
- * @method _addLooping
- * @param {number} value The number of times to loop after play.
- * @protected
- * @since 0.6.0
- */
- p._addLooping = function (value) {
- // plugin specific code
- };
-
- /**
- * Internal function called when pausing playback
- * @method _pause
- * @protected
- * @since 0.6.0
- */
- p._pause = function () {
- // plugin specific code
- };
-
- /**
- * Internal function called when resuming playback
- * @method _resume
- * @protected
- * @since 0.6.0
- */
- p._resume = function () {
- // plugin specific code
- };
-
- /**
- * Internal function called when stopping playback
- * @method _handleStop
- * @protected
- * @since 0.6.0
- */
- p._handleStop = function() {
- // plugin specific code
- };
-
- /**
- * Internal function called when AbstractSoundInstance is being cleaned up
- * @method _handleCleanUp
- * @protected
- * @since 0.6.0
- */
- p._handleCleanUp = function() {
- // plugin specific code
- };
-
- /**
- * Internal function called when AbstractSoundInstance has played to end and is looping
- * @method _handleLoop
- * @protected
- * @since 0.6.0
- */
- p._handleLoop = function () {
- // plugin specific code
- };
-
- createjs.AbstractSoundInstance = createjs.promote(AbstractSoundInstance, "EventDispatcher");
- createjs.DefaultSoundInstance = createjs.AbstractSoundInstance; // used when no plugin is supported
-}());
-
-//##############################################################################
-// AbstractPlugin.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
-
-// constructor:
- /**
- * A default plugin class used as a base for all other plugins.
- * @class AbstractPlugin
- * @constructor
- * @since 0.6.0
- */
-
- var AbstractPlugin = function () {
- // private properties:
- /**
- * The capabilities of the plugin.
- * method and is used internally.
- * @property _capabilities
- * @type {Object}
- * @default null
- * @protected
- * @static
- */
- this._capabilities = null;
-
- /**
- * Object hash indexed by the source URI of all created loaders, used to properly destroy them if sources are removed.
- * @type {Object}
- * @protected
- */
- this._loaders = {};
-
- /**
- * Object hash indexed by the source URI of each file to indicate if an audio source has begun loading,
- * is currently loading, or has completed loading. Can be used to store non boolean data after loading
- * is complete (for example arrayBuffers for web audio).
- * @property _audioSources
- * @type {Object}
- * @protected
- */
- this._audioSources = {};
-
- /**
- * Object hash indexed by the source URI of all created SoundInstances, updates the playbackResource if it loads after they are created,
- * and properly destroy them if sources are removed
- * @type {Object}
- * @protected
- */
- this._soundInstances = {};
-
- /**
- * The internal master volume value of the plugin.
- * @property _volume
- * @type {Number}
- * @default 1
- * @protected
- */
- this._volume = 1;
-
- /**
- * A reference to a loader class used by a plugin that must be set.
- * @type {Object}
- * @protected
- */
- this._loaderClass;
-
- /**
- * A reference to an AbstractSoundInstance class used by a plugin that must be set.
- * @type {Object}
- * @protected;
- */
- this._soundInstanceClass;
- };
- var p = AbstractPlugin.prototype;
-
- /**
- * REMOVED. Removed in favor of using `MySuperClass_constructor`.
- * See {{#crossLink "Utility Methods/extend"}}{{/crossLink}} and {{#crossLink "Utility Methods/promote"}}{{/crossLink}}
- * for details.
- *
- * There is an inheritance tutorial distributed with EaselJS in /tutorials/Inheritance.
- *
- * @method initialize
- * @protected
- * @deprecated
- */
- // p.initialize = function() {}; // searchable for devs wondering where it is.
-
-
-// Static Properties:
-// NOTE THESE PROPERTIES NEED TO BE ADDED TO EACH PLUGIN
- /**
- * The capabilities of the plugin. This is generated via the _generateCapabilities method and is used internally.
- * @property _capabilities
- * @type {Object}
- * @default null
- * @protected
- * @static
- */
- AbstractPlugin._capabilities = null;
-
- /**
- * Determine if the plugin can be used in the current browser/OS.
- * @method isSupported
- * @return {Boolean} If the plugin can be initialized.
- * @static
- */
- AbstractPlugin.isSupported = function () {
- return true;
- };
-
-
-// public methods:
- /**
- * Pre-register a sound for preloading and setup. This is called by {{#crossLink "Sound"}}{{/crossLink}}.
- * Note all plugins provide a Loader instance, which PreloadJS
- * can use to assist with preloading.
- * @method register
- * @param {String} loadItem An Object containing the source of the audio
- * Note that not every plugin will manage this value.
- * @return {Object} A result object, containing a "tag" for preloading purposes.
- */
- p.register = function (loadItem) {
- var loader = this._loaders[loadItem.src];
- if(loader && !loader.canceled) {return this._loaders[loadItem.src];} // already loading/loaded this, so don't load twice
- // OJR potential issue that we won't be firing loaded event, might need to trigger if this is already loaded?
- this._audioSources[loadItem.src] = true;
- this._soundInstances[loadItem.src] = [];
- loader = new this._loaderClass(loadItem);
- loader.on("complete", this._handlePreloadComplete, this);
- this._loaders[loadItem.src] = loader;
- return loader;
- };
-
- // note sound calls register before calling preload
- /**
- * Internally preload a sound.
- * @method preload
- * @param {Loader} loader The sound URI to load.
- */
- p.preload = function (loader) {
- loader.on("error", this._handlePreloadError, this);
- loader.load();
- };
-
- /**
- * Checks if preloading has started for a specific source. If the source is found, we can assume it is loading,
- * or has already finished loading.
- * @method isPreloadStarted
- * @param {String} src The sound URI to check.
- * @return {Boolean}
- */
- p.isPreloadStarted = function (src) {
- return (this._audioSources[src] != null);
- };
-
- /**
- * Checks if preloading has finished for a specific source.
- * @method isPreloadComplete
- * @param {String} src The sound URI to load.
- * @return {Boolean}
- */
- p.isPreloadComplete = function (src) {
- return (!(this._audioSources[src] == null || this._audioSources[src] == true));
- };
-
- /**
- * Remove a sound added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload.
- * @method removeSound
- * @param {String} src The sound URI to unload.
- */
- p.removeSound = function (src) {
- if (!this._soundInstances[src]) { return; }
- for (var i = this._soundInstances[src].length; i--; ) {
- var item = this._soundInstances[src][i];
- item.destroy();
- }
- delete(this._soundInstances[src]);
- delete(this._audioSources[src]);
- if(this._loaders[src]) { this._loaders[src].destroy(); }
- delete(this._loaders[src]);
- };
-
- /**
- * Remove all sounds added using {{#crossLink "WebAudioPlugin/register"}}{{/crossLink}}. Note this does not cancel a preload.
- * @method removeAllSounds
- * @param {String} src The sound URI to unload.
- */
- p.removeAllSounds = function () {
- for(var key in this._audioSources) {
- this.removeSound(key);
- }
- };
-
- /**
- * Create a sound instance. If the sound has not been preloaded, it is internally preloaded here.
- * @method create
- * @param {String} src The sound source to use.
- * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.
- * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.
- * @return {AbstractSoundInstance} A sound instance for playback and control.
- */
- p.create = function (src, startTime, duration) {
- if (!this.isPreloadStarted(src)) {
- this.preload(this.register(src));
- }
- var si = new this._soundInstanceClass(src, startTime, duration, this._audioSources[src]);
- this._soundInstances[src].push(si);
- return si;
- };
-
- // if a plugin does not support volume and mute, it should set these to null
- /**
- * Set the master volume of the plugin, which affects all SoundInstances.
- * @method setVolume
- * @param {Number} value The volume to set, between 0 and 1.
- * @return {Boolean} If the plugin processes the setVolume call (true). The Sound class will affect all the
- * instances manually otherwise.
- */
- p.setVolume = function (value) {
- this._volume = value;
- this._updateVolume();
- return true;
- };
-
- /**
- * Get the master volume of the plugin, which affects all SoundInstances.
- * @method getVolume
- * @return {Number} The volume level, between 0 and 1.
- */
- p.getVolume = function () {
- return this._volume;
- };
-
- /**
- * Mute all sounds via the plugin.
- * @method setMute
- * @param {Boolean} value If all sound should be muted or not. Note that plugin-level muting just looks up
- * the mute value of Sound {{#crossLink "Sound/getMute"}}{{/crossLink}}, so this property is not used here.
- * @return {Boolean} If the mute call succeeds.
- */
- p.setMute = function (value) {
- this._updateVolume();
- return true;
- };
-
- // plugins should overwrite this method
- p.toString = function () {
- return "[AbstractPlugin]";
- };
-
-
-// private methods:
- /**
- * Handles internal preload completion.
- * @method _handlePreloadComplete
- * @protected
- */
- p._handlePreloadComplete = function (event) {
- var src = event.target.getItem().src;
- this._audioSources[src] = event.result;
- for (var i = 0, l = this._soundInstances[src].length; i < l; i++) {
- var item = this._soundInstances[src][i];
- item.setPlaybackResource(this._audioSources[src]);
- // ToDo consider adding play call here if playstate == playfailed
- }
- };
-
- /**
- * Handles internal preload erros
- * @method _handlePreloadError
- * @param event
- * @protected
- */
- p._handlePreloadError = function(event) {
- //delete(this._audioSources[src]);
- };
-
- /**
- * Set the gain value for master audio. Should not be called externally.
- * @method _updateVolume
- * @protected
- */
- p._updateVolume = function () {
- // Plugin Specific code
- };
-
- createjs.AbstractPlugin = AbstractPlugin;
-}());
-
-//##############################################################################
-// WebAudioLoader.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * Loader provides a mechanism to preload Web Audio content via PreloadJS or internally. Instances are returned to
- * the preloader, and the load method is called when the asset needs to be requested.
- *
- * @class WebAudioLoader
- * @param {String} loadItem The item to be loaded
- * @extends XHRRequest
- * @protected
- */
- function Loader(loadItem) {
- this.AbstractLoader_constructor(loadItem, true, createjs.AbstractLoader.SOUND);
-
- };
- var p = createjs.extend(Loader, createjs.AbstractLoader);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
- /**
- * web audio context required for decoding audio
- * @property context
- * @type {AudioContext}
- * @static
- */
- Loader.context = null;
-
-
-// public methods
- p.toString = function () {
- return "[WebAudioLoader]";
- };
-
-
-// private methods
- p._createRequest = function() {
- this._request = new createjs.XHRRequest(this._item, false);
- this._request.setResponseType("arraybuffer");
- };
-
- p._sendComplete = function (event) {
- // OJR we leave this wrapped in Loader because we need to reference src and the handler only receives a single argument, the decodedAudio
- Loader.context.decodeAudioData(this._rawResult,
- createjs.proxy(this._handleAudioDecoded, this),
- createjs.proxy(this._sendError, this));
- };
-
-
- /**
- * The audio has been decoded.
- * @method handleAudioDecoded
- * @param decoded
- * @protected
- */
- p._handleAudioDecoded = function (decodedAudio) {
- this._result = decodedAudio;
- this.AbstractLoader__sendComplete();
- };
-
- createjs.WebAudioLoader = createjs.promote(Loader, "AbstractLoader");
-}());
-
-//##############################################################################
-// WebAudioSoundInstance.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-/**
- * WebAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by
- * {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.
- *
- * WebAudioSoundInstance exposes audioNodes for advanced users.
- *
- * @param {String} src The path to and file name of the sound.
- * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.
- * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.
- * @param {Object} playbackResource Any resource needed by plugin to support audio playback.
- * @class WebAudioSoundInstance
- * @extends AbstractSoundInstance
- * @constructor
- */
-(function () {
- "use strict";
-
- function WebAudioSoundInstance(src, startTime, duration, playbackResource) {
- this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource);
-
-
-// public properties
- /**
- * NOTE this is only intended for use by advanced users.
- * GainNode for controlling WebAudioSoundInstance volume. Connected to the {{#crossLink "WebAudioSoundInstance/destinationNode:property"}}{{/crossLink}}.
- * @property gainNode
- * @type {AudioGainNode}
- * @since 0.4.0
- *
- */
- this.gainNode = s.context.createGain();
-
- /**
- * NOTE this is only intended for use by advanced users.
- * A panNode allowing left and right audio channel panning only. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}.
- * @property panNode
- * @type {AudioPannerNode}
- * @since 0.4.0
- */
- this.panNode = s.context.createPanner();
- this.panNode.panningModel = s._panningModel;
- this.panNode.connect(this.gainNode);
- this._updatePan();
-
- /**
- * NOTE this is only intended for use by advanced users.
- * sourceNode is the audio source. Connected to WebAudioSoundInstance {{#crossLink "WebAudioSoundInstance/panNode:property"}}{{/crossLink}}.
- * @property sourceNode
- * @type {AudioNode}
- * @since 0.4.0
- *
- */
- this.sourceNode = null;
-
-
-// private properties
- /**
- * Timeout that is created internally to handle sound playing to completion.
- * Stored so we can remove it when stop, pause, or cleanup are called
- * @property _soundCompleteTimeout
- * @type {timeoutVariable}
- * @default null
- * @protected
- * @since 0.4.0
- */
- this._soundCompleteTimeout = null;
-
- /**
- * NOTE this is only intended for use by very advanced users.
- * _sourceNodeNext is the audio source for the next loop, inserted in a look ahead approach to allow for smooth
- * looping. Connected to {{#crossLink "WebAudioSoundInstance/gainNode:property"}}{{/crossLink}}.
- * @property _sourceNodeNext
- * @type {AudioNode}
- * @default null
- * @protected
- * @since 0.4.1
- *
- */
- this._sourceNodeNext = null;
-
- /**
- * Time audio started playback, in seconds. Used to handle set position, get position, and resuming from paused.
- * @property _playbackStartTime
- * @type {Number}
- * @default 0
- * @protected
- * @since 0.4.0
- */
- this._playbackStartTime = 0;
-
- // Proxies, make removing listeners easier.
- this._endedHandler = createjs.proxy(this._handleSoundComplete, this);
- };
- var p = createjs.extend(WebAudioSoundInstance, createjs.AbstractSoundInstance);
- var s = WebAudioSoundInstance;
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
- /**
- * Note this is only intended for use by advanced users.
- * Audio context used to create nodes. This is and needs to be the same context used by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.
- * @property context
- * @type {AudioContext}
- * @static
- * @since 0.6.0
- */
- s.context = null;
-
- /**
- * Note this is only intended for use by advanced users.
- * The scratch buffer that will be assigned to the buffer property of a source node on close.
- * This is and should be the same scratch buffer referenced by {{#crossLink "WebAudioPlugin"}}{{/crossLink}}.
- * @property _scratchBuffer
- * @type {AudioBufferSourceNode}
- * @static
- */
- s._scratchBuffer = null;
-
- /**
- * Note this is only intended for use by advanced users.
- * Audio node from WebAudioPlugin that sequences to context.destination
- * @property destinationNode
- * @type {AudioNode}
- * @static
- * @since 0.6.0
- */
- s.destinationNode = null;
-
- /**
- * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.
- * @property _panningModel
- * @type {Number / String}
- * @protected
- * @static
- * @since 0.6.0
- */
- s._panningModel = "equalpower";
-
-
-// Public methods
- p.destroy = function() {
- this.AbstractSoundInstance_destroy();
-
- this.panNode.disconnect(0);
- this.panNode = null;
- this.gainNode.disconnect(0);
- this.gainNode = null;
- };
-
- p.toString = function () {
- return "[WebAudioSoundInstance]";
- };
-
-
-// Private Methods
- p._updatePan = function() {
- this.panNode.setPosition(this._pan, 0, -0.5);
- // z need to be -0.5 otherwise the sound only plays in left, right, or center
- };
-
- p._removeLooping = function(value) {
- this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);
- };
-
- p._addLooping = function(value) {
- if (this.playState != createjs.Sound.PLAY_SUCCEEDED) { return; }
- this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);
- };
-
- p._setDurationFromSource = function () {
- this._duration = this.playbackResource.duration * 1000;
- };
-
- p._handleCleanUp = function () {
- if (this.sourceNode && this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this.sourceNode = this._cleanUpAudioNode(this.sourceNode);
- this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);
- }
-
- if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);}
- // OJR there appears to be a bug that this doesn't always work in webkit (Chrome and Safari). According to the documentation, this should work.
-
- clearTimeout(this._soundCompleteTimeout);
-
- this._playbackStartTime = 0; // This is used by getPosition
- };
-
- /**
- * Turn off and disconnect an audioNode, then set reference to null to release it for garbage collection
- * @method _cleanUpAudioNode
- * @param audioNode
- * @return {audioNode}
- * @protected
- * @since 0.4.1
- */
- p._cleanUpAudioNode = function(audioNode) {
- if(audioNode) {
- audioNode.stop(0);
- audioNode.disconnect(0);
- // necessary to prevent leak on iOS Safari 7-9. will throw in almost all other
- // browser implementations.
- try { audioNode.buffer = s._scratchBuffer; } catch(e) {}
- audioNode = null;
- }
- return audioNode;
- };
-
- p._handleSoundReady = function (event) {
- this.gainNode.connect(s.destinationNode); // this line can cause a memory leak. Nodes need to be disconnected from the audioDestination or any sequence that leads to it.
-
- var dur = this._duration * 0.001;
- var pos = this._position * 0.001;
- if (pos > dur) {pos = dur;}
- this.sourceNode = this._createAndPlayAudioNode((s.context.currentTime - dur), pos);
- this._playbackStartTime = this.sourceNode.startTime - pos;
-
- this._soundCompleteTimeout = setTimeout(this._endedHandler, (dur - pos) * 1000);
-
- if(this._loop != 0) {
- this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);
- }
- };
-
- /**
- * Creates an audio node using the current src and context, connects it to the gain node, and starts playback.
- * @method _createAndPlayAudioNode
- * @param {Number} startTime The time to add this to the web audio context, in seconds.
- * @param {Number} offset The amount of time into the src audio to start playback, in seconds.
- * @return {audioNode}
- * @protected
- * @since 0.4.1
- */
- p._createAndPlayAudioNode = function(startTime, offset) {
- var audioNode = s.context.createBufferSource();
- audioNode.buffer = this.playbackResource;
- audioNode.connect(this.panNode);
- var dur = this._duration * 0.001;
- audioNode.startTime = startTime + dur;
- audioNode.start(audioNode.startTime, offset+(this._startTime*0.001), dur - offset);
- return audioNode;
- };
-
- p._pause = function () {
- this._position = (s.context.currentTime - this._playbackStartTime) * 1000; // * 1000 to give milliseconds, lets us restart at same point
- this.sourceNode = this._cleanUpAudioNode(this.sourceNode);
- this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);
-
- if (this.gainNode.numberOfOutputs != 0) {this.gainNode.disconnect(0);}
-
- clearTimeout(this._soundCompleteTimeout);
- };
-
- p._resume = function () {
- this._handleSoundReady();
- };
-
- /*
- p._handleStop = function () {
- // web audio does not need to do anything extra
- };
- */
-
- p._updateVolume = function () {
- var newVolume = this._muted ? 0 : this._volume;
- if (newVolume != this.gainNode.gain.value) {
- this.gainNode.gain.value = newVolume;
- }
- };
-
- p._calculateCurrentPosition = function () {
- return ((s.context.currentTime - this._playbackStartTime) * 1000); // pos in seconds * 1000 to give milliseconds
- };
-
- p._updatePosition = function () {
- this.sourceNode = this._cleanUpAudioNode(this.sourceNode);
- this._sourceNodeNext = this._cleanUpAudioNode(this._sourceNodeNext);
- clearTimeout(this._soundCompleteTimeout);
-
- if (!this._paused) {this._handleSoundReady();}
- };
-
- // OJR we are using a look ahead approach to ensure smooth looping.
- // We add _sourceNodeNext to the audio context so that it starts playing even if this callback is delayed.
- // This technique is described here: http://www.html5rocks.com/en/tutorials/audio/scheduling/
- // NOTE the cost of this is that our audio loop may not always match the loop event timing precisely.
- p._handleLoop = function () {
- this._cleanUpAudioNode(this.sourceNode);
- this.sourceNode = this._sourceNodeNext;
- this._playbackStartTime = this.sourceNode.startTime;
- this._sourceNodeNext = this._createAndPlayAudioNode(this._playbackStartTime, 0);
- this._soundCompleteTimeout = setTimeout(this._endedHandler, this._duration);
- };
-
- p._updateDuration = function () {
- if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this._pause();
- this._resume();
- }
- };
-
- createjs.WebAudioSoundInstance = createjs.promote(WebAudioSoundInstance, "AbstractSoundInstance");
-}());
-
-//##############################################################################
-// WebAudioPlugin.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
-
- "use strict";
-
- /**
- * Play sounds using Web Audio in the browser. The WebAudioPlugin is currently the default plugin, and will be used
- * anywhere that it is supported. To change plugin priority, check out the Sound API
- * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} method.
-
- *
Known Browser and OS issues for Web Audio
- * Firefox 25
- *
- * mp3 audio files do not load properly on all windows machines, reported here.
- * For this reason it is recommended to pass another FireFox-supported type (i.e. ogg) as the default
- * extension, until this bug is resolved
- *
- *
- * Webkit (Chrome and Safari)
- *
- * AudioNode.disconnect does not always seem to work. This can cause the file size to grow over time if you
- * are playing a lot of audio files.
- *
- *
- * iOS 6 limitations
- *
- *
- * Sound is initially muted and will only unmute through play being called inside a user initiated event
- * (touch/click). Please read the mobile playback notes in the the {{#crossLink "Sound"}}{{/crossLink}}
- * class for a full overview of the limitations, and how to get around them.
- *
- *
- * A bug exists that will distort un-cached audio when a video element is present in the DOM. You can avoid
- * this bug by ensuring the audio and video audio share the same sample rate.
- *
- *
- * @class WebAudioPlugin
- * @extends AbstractPlugin
- * @constructor
- * @since 0.4.0
- */
- function WebAudioPlugin() {
- this.AbstractPlugin_constructor();
-
-
-// Private Properties
- /**
- * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.
- * @property _panningModel
- * @type {Number / String}
- * @protected
- */
- this._panningModel = s._panningModel;;
-
- /**
- * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin
- * need to be created within this context.
- * @property context
- * @type {AudioContext}
- */
- this.context = s.context;
-
- /**
- * A DynamicsCompressorNode, which is used to improve sound quality and prevent audio distortion.
- * It is connected to context.destination.
- *
- * Can be accessed by advanced users through createjs.Sound.activePlugin.dynamicsCompressorNode.
- * @property dynamicsCompressorNode
- * @type {AudioNode}
- */
- this.dynamicsCompressorNode = this.context.createDynamicsCompressor();
- this.dynamicsCompressorNode.connect(this.context.destination);
-
- /**
- * A GainNode for controlling master volume. It is connected to {{#crossLink "WebAudioPlugin/dynamicsCompressorNode:property"}}{{/crossLink}}.
- *
- * Can be accessed by advanced users through createjs.Sound.activePlugin.gainNode.
- * @property gainNode
- * @type {AudioGainNode}
- */
- this.gainNode = this.context.createGain();
- this.gainNode.connect(this.dynamicsCompressorNode);
- createjs.WebAudioSoundInstance.destinationNode = this.gainNode;
-
- this._capabilities = s._capabilities;
-
- this._loaderClass = createjs.WebAudioLoader;
- this._soundInstanceClass = createjs.WebAudioSoundInstance;
-
- this._addPropsToClasses();
- }
- var p = createjs.extend(WebAudioPlugin, createjs.AbstractPlugin);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// Static Properties
- var s = WebAudioPlugin;
- /**
- * The capabilities of the plugin. This is generated via the {{#crossLink "WebAudioPlugin/_generateCapabilities:method"}}{{/crossLink}}
- * method and is used internally.
- * @property _capabilities
- * @type {Object}
- * @default null
- * @protected
- * @static
- */
- s._capabilities = null;
-
- /**
- * Value to set panning model to equal power for WebAudioSoundInstance. Can be "equalpower" or 0 depending on browser implementation.
- * @property _panningModel
- * @type {Number / String}
- * @protected
- * @static
- */
- s._panningModel = "equalpower";
-
- /**
- * The web audio context, which WebAudio uses to play audio. All nodes that interact with the WebAudioPlugin
- * need to be created within this context.
- *
- * Advanced users can set this to an existing context, but must do so before they call
- * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}.
- *
- * @property context
- * @type {AudioContext}
- * @static
- */
- s.context = null;
-
- /**
- * The scratch buffer that will be assigned to the buffer property of a source node on close.
- * Works around an iOS Safari bug: https://github.com/CreateJS/SoundJS/issues/102
- *
- * Advanced users can set this to an existing source node, but must do so before they call
- * {{#crossLink "Sound/registerPlugins"}}{{/crossLink}} or {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}.
- *
- * @property _scratchBuffer
- * @type {AudioBuffer}
- * @protected
- * @static
- */
- s._scratchBuffer = null;
-
- /**
- * Indicated whether audio on iOS has been unlocked, which requires a touchend/mousedown event that plays an
- * empty sound.
- * @property _unlocked
- * @type {boolean}
- * @since 0.6.2
- * @private
- */
- s._unlocked = false;
-
-
-// Static Public Methods
- /**
- * Determine if the plugin can be used in the current browser/OS.
- * @method isSupported
- * @return {Boolean} If the plugin can be initialized.
- * @static
- */
- s.isSupported = function () {
- // check if this is some kind of mobile device, Web Audio works with local protocol under PhoneGap and it is unlikely someone is trying to run a local file
- var isMobilePhoneGap = createjs.BrowserDetect.isIOS || createjs.BrowserDetect.isAndroid || createjs.BrowserDetect.isBlackberry;
- // OJR isMobile may be redundant with _isFileXHRSupported available. Consider removing.
- if (location.protocol == "file:" && !isMobilePhoneGap && !this._isFileXHRSupported()) { return false; } // Web Audio requires XHR, which is not usually available locally
- s._generateCapabilities();
- if (s.context == null) {return false;}
- return true;
- };
-
- /**
- * Plays an empty sound in the web audio context. This is used to enable web audio on iOS devices, as they
- * require the first sound to be played inside of a user initiated event (touch/click). This is called when
- * {{#crossLink "WebAudioPlugin"}}{{/crossLink}} is initialized (by Sound {{#crossLink "Sound/initializeDefaultPlugins"}}{{/crossLink}}
- * for example).
- *
- *
Example
- *
- * function handleTouch(event) {
- * createjs.WebAudioPlugin.playEmptySound();
- * }
- *
- * @method playEmptySound
- * @static
- * @since 0.4.1
- */
- s.playEmptySound = function() {
- if (s.context == null) {return;}
- var source = s.context.createBufferSource();
- source.buffer = s._scratchBuffer;
- source.connect(s.context.destination);
- source.start(0, 0, 0);
- };
-
-
-// Static Private Methods
- /**
- * Determine if XHR is supported, which is necessary for web audio.
- * @method _isFileXHRSupported
- * @return {Boolean} If XHR is supported.
- * @since 0.4.2
- * @protected
- * @static
- */
- s._isFileXHRSupported = function() {
- // it's much easier to detect when something goes wrong, so let's start optimistically
- var supported = true;
-
- var xhr = new XMLHttpRequest();
- try {
- xhr.open("GET", "WebAudioPluginTest.fail", false); // loading non-existant file triggers 404 only if it could load (synchronous call)
- } catch (error) {
- // catch errors in cases where the onerror is passed by
- supported = false;
- return supported;
- }
- xhr.onerror = function() { supported = false; }; // cause irrelevant
- // with security turned off, we can get empty success results, which is actually a failed read (status code 0?)
- xhr.onload = function() { supported = this.status == 404 || (this.status == 200 || (this.status == 0 && this.response != "")); };
- try {
- xhr.send();
- } catch (error) {
- // catch errors in cases where the onerror is passed by
- supported = false;
- }
-
- return supported;
- };
-
- /**
- * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}}
- * method for an overview of plugin capabilities.
- * @method _generateCapabilities
- * @static
- * @protected
- */
- s._generateCapabilities = function () {
- if (s._capabilities != null) {return;}
- // Web Audio can be in any formats supported by the audio element, from http://www.w3.org/TR/webaudio/#AudioContext-section
- var t = document.createElement("audio");
- if (t.canPlayType == null) {return null;}
-
- if (s.context == null) {
- if (window.AudioContext) {
- s.context = new AudioContext();
- } else if (window.webkitAudioContext) {
- s.context = new webkitAudioContext();
- } else {
- return null;
- }
- }
- if (s._scratchBuffer == null) {
- s._scratchBuffer = s.context.createBuffer(1, 1, 22050);
- }
-
- s._compatibilitySetUp();
-
- // Listen for document level clicks to unlock WebAudio on iOS. See the _unlock method.
- if ("ontouchstart" in window && s.context.state != "running") {
- s._unlock(); // When played inside of a touch event, this will enable audio on iOS immediately.
- document.addEventListener("mousedown", s._unlock, true);
- document.addEventListener("touchend", s._unlock, true);
- }
-
-
- s._capabilities = {
- panning:true,
- volume:true,
- tracks:-1
- };
-
- // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS
- var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS;
- var extensionMap = createjs.Sound.EXTENSION_MAP;
- for (var i = 0, l = supportedExtensions.length; i < l; i++) {
- var ext = supportedExtensions[i];
- var playType = extensionMap[ext] || ext;
- s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != "");
- } // OJR another way to do this might be canPlayType:"m4a", codex: mp4
-
- // 0=no output, 1=mono, 2=stereo, 4=surround, 6=5.1 surround.
- // See http://www.w3.org/TR/webaudio/#AudioChannelSplitter for more details on channels.
- if (s.context.destination.numberOfChannels < 2) {
- s._capabilities.panning = false;
- }
- };
-
- /**
- * Set up compatibility if only deprecated web audio calls are supported.
- * See http://www.w3.org/TR/webaudio/#DeprecationNotes
- * Needed so we can support new browsers that don't support deprecated calls (Firefox) as well as old browsers that
- * don't support new calls.
- *
- * @method _compatibilitySetUp
- * @static
- * @protected
- * @since 0.4.2
- */
- s._compatibilitySetUp = function() {
- s._panningModel = "equalpower";
- //assume that if one new call is supported, they all are
- if (s.context.createGain) { return; }
-
- // simple name change, functionality the same
- s.context.createGain = s.context.createGainNode;
-
- // source node, add to prototype
- var audioNode = s.context.createBufferSource();
- audioNode.__proto__.start = audioNode.__proto__.noteGrainOn; // note that noteGrainOn requires all 3 parameters
- audioNode.__proto__.stop = audioNode.__proto__.noteOff;
-
- // panningModel
- s._panningModel = 0;
- };
-
- /**
- * Try to unlock audio on iOS. This is triggered from either WebAudio plugin setup (which will work if inside of
- * a `mousedown` or `touchend` event stack), or the first document touchend/mousedown event. If it fails (touchend
- * will fail if the user presses for too long, indicating a scroll event instead of a click event.
- *
- * Note that earlier versions of iOS supported `touchstart` for this, but iOS9 removed this functionality. Adding
- * a `touchstart` event to support older platforms may preclude a `mousedown` even from getting fired on iOS9, so we
- * stick with `mousedown` and `touchend`.
- * @method _unlock
- * @since 0.6.2
- * @private
- */
- s._unlock = function() {
- if (s._unlocked) { return; }
- s.playEmptySound();
- if (s.context.state == "running") {
- document.removeEventListener("mousedown", s._unlock, true);
- document.removeEventListener("touchend", s._unlock, true);
- s._unlocked = true;
- }
- };
-
-
-// Public Methods
- p.toString = function () {
- return "[WebAudioPlugin]";
- };
-
-
-// Private Methods
- /**
- * Set up needed properties on supported classes WebAudioSoundInstance and WebAudioLoader.
- * @method _addPropsToClasses
- * @static
- * @protected
- * @since 0.6.0
- */
- p._addPropsToClasses = function() {
- var c = this._soundInstanceClass;
- c.context = this.context;
- c._scratchBuffer = s._scratchBuffer;
- c.destinationNode = this.gainNode;
- c._panningModel = this._panningModel;
-
- this._loaderClass.context = this.context;
- };
-
-
- /**
- * Set the gain value for master audio. Should not be called externally.
- * @method _updateVolume
- * @protected
- */
- p._updateVolume = function () {
- var newVolume = createjs.Sound._masterMute ? 0 : this._volume;
- if (newVolume != this.gainNode.gain.value) {
- this.gainNode.gain.value = newVolume;
- }
- };
-
- createjs.WebAudioPlugin = createjs.promote(WebAudioPlugin, "AbstractPlugin");
-}());
-
-//##############################################################################
-// HTMLAudioTagPool.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * HTMLAudioTagPool is an object pool for HTMLAudio tag instances.
- * @class HTMLAudioTagPool
- * @param {String} src The source of the channel.
- * @protected
- */
- function HTMLAudioTagPool() {
- throw "HTMLAudioTagPool cannot be instantiated";
- }
-
- var s = HTMLAudioTagPool;
-
-// Static Properties
- /**
- * A hash lookup of each base audio tag, indexed by the audio source.
- * @property _tags
- * @type {{}}
- * @static
- * @protected
- */
- s._tags = {};
-
- /**
- * An object pool for html audio tags
- * @property _tagPool
- * @type {TagPool}
- * @static
- * @protected
- */
- s._tagPool = new TagPool();
-
- /**
- * A hash lookup of if a base audio tag is available, indexed by the audio source
- * @property _tagsUsed
- * @type {{}}
- * @protected
- * @static
- */
- s._tagUsed = {};
-
-// Static Methods
- /**
- * Get an audio tag with the given source.
- * @method get
- * @param {String} src The source file used by the audio tag.
- * @static
- */
- s.get = function (src) {
- var t = s._tags[src];
- if (t == null) {
- // create new base tag
- t = s._tags[src] = s._tagPool.get();
- t.src = src;
- } else {
- // get base or pool
- if (s._tagUsed[src]) {
- t = s._tagPool.get();
- t.src = src;
- } else {
- s._tagUsed[src] = true;
- }
- }
- return t;
- };
-
- /**
- * Return an audio tag to the pool.
- * @method set
- * @param {String} src The source file used by the audio tag.
- * @param {HTMLElement} tag Audio tag to set.
- * @static
- */
- s.set = function (src, tag) {
- // check if this is base, if yes set boolean if not return to pool
- if(tag == s._tags[src]) {
- s._tagUsed[src] = false;
- } else {
- s._tagPool.set(tag);
- }
- };
-
- /**
- * Delete stored tag reference and return them to pool. Note that if the tag reference does not exist, this will fail.
- * @method remove
- * @param {String} src The source for the tag
- * @return {Boolean} If the TagPool was deleted.
- * @static
- */
- s.remove = function (src) {
- var tag = s._tags[src];
- if (tag == null) {return false;}
- s._tagPool.set(tag);
- delete(s._tags[src]);
- delete(s._tagUsed[src]);
- return true;
- };
-
- /**
- * Gets the duration of the src audio in milliseconds
- * @method getDuration
- * @param {String} src The source file used by the audio tag.
- * @return {Number} Duration of src in milliseconds
- * @static
- */
- s.getDuration= function (src) {
- var t = s._tags[src];
- if (t == null || !t.duration) {return 0;} // OJR duration is NaN if loading has not completed
- return t.duration * 1000;
- };
-
- createjs.HTMLAudioTagPool = HTMLAudioTagPool;
-
-
-// ************************************************************************************************************
- /**
- * The TagPool is an object pool for HTMLAudio tag instances.
- * #class TagPool
- * @param {String} src The source of the channel.
- * @protected
- */
- function TagPool(src) {
-
-// Public Properties
- /**
- * A list of all available tags in the pool.
- * #property tags
- * @type {Array}
- * @protected
- */
- this._tags = [];
- };
-
- var p = TagPool.prototype;
- p.constructor = TagPool;
-
-
-// Public Methods
- /**
- * Get an HTMLAudioElement for immediate playback. This takes it out of the pool.
- * #method get
- * @return {HTMLAudioElement} An HTML audio tag.
- */
- p.get = function () {
- var tag;
- if (this._tags.length == 0) {
- tag = this._createTag();
- } else {
- tag = this._tags.pop();
- }
- if (tag.parentNode == null) {document.body.appendChild(tag);}
- return tag;
- };
-
- /**
- * Put an HTMLAudioElement back in the pool for use.
- * #method set
- * @param {HTMLAudioElement} tag HTML audio tag
- */
- p.set = function (tag) {
- // OJR this first step seems unnecessary
- var index = createjs.indexOf(this._tags, tag);
- if (index == -1) {
- this._tags.src = null;
- this._tags.push(tag);
- }
- };
-
- p.toString = function () {
- return "[TagPool]";
- };
-
-
-// Private Methods
- /**
- * Create an HTML audio tag.
- * #method _createTag
- * @param {String} src The source file to set for the audio tag.
- * @return {HTMLElement} Returns an HTML audio tag.
- * @protected
- */
- p._createTag = function () {
- var tag = document.createElement("audio");
- tag.autoplay = false;
- tag.preload = "none";
- //LM: Firefox fails when this the preload="none" for other tags, but it needs to be "none" to ensure PreloadJS works.
- return tag;
- };
-
-}());
-
-//##############################################################################
-// HTMLAudioSoundInstance.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
- "use strict";
-
- /**
- * HTMLAudioSoundInstance extends the base api of {{#crossLink "AbstractSoundInstance"}}{{/crossLink}} and is used by
- * {{#crossLink "HTMLAudioPlugin"}}{{/crossLink}}.
- *
- * @param {String} src The path to and file name of the sound.
- * @param {Number} startTime Audio sprite property used to apply an offset, in milliseconds.
- * @param {Number} duration Audio sprite property used to set the time the clip plays for, in milliseconds.
- * @param {Object} playbackResource Any resource needed by plugin to support audio playback.
- * @class HTMLAudioSoundInstance
- * @extends AbstractSoundInstance
- * @constructor
- */
- function HTMLAudioSoundInstance(src, startTime, duration, playbackResource) {
- this.AbstractSoundInstance_constructor(src, startTime, duration, playbackResource);
-
-
-// Private Properties
- this._audioSpriteStopTime = null;
- this._delayTimeoutId = null;
-
- // Proxies, make removing listeners easier.
- this._endedHandler = createjs.proxy(this._handleSoundComplete, this);
- this._readyHandler = createjs.proxy(this._handleTagReady, this);
- this._stalledHandler = createjs.proxy(this._playFailed, this);
- this._audioSpriteEndHandler = createjs.proxy(this._handleAudioSpriteLoop, this);
- this._loopHandler = createjs.proxy(this._handleSoundComplete, this);
-
- if (duration) {
- this._audioSpriteStopTime = (startTime + duration) * 0.001;
- } else {
- this._duration = createjs.HTMLAudioTagPool.getDuration(this.src);
- }
- }
- var p = createjs.extend(HTMLAudioSoundInstance, createjs.AbstractSoundInstance);
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// Public Methods
- /**
- * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master volume.
- * undoc'd because it is not meant to be used outside of Sound
- * #method setMasterVolume
- * @param value
- */
- p.setMasterVolume = function (value) {
- this._updateVolume();
- };
-
- /**
- * Called by {{#crossLink "Sound"}}{{/crossLink}} when plugin does not handle master mute.
- * undoc'd because it is not meant to be used outside of Sound
- * #method setMasterMute
- * @param value
- */
- p.setMasterMute = function (isMuted) {
- this._updateVolume();
- };
-
- p.toString = function () {
- return "[HTMLAudioSoundInstance]";
- };
-
-//Private Methods
- p._removeLooping = function() {
- if(this._playbackResource == null) {return;}
- this._playbackResource.loop = false;
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- };
-
- p._addLooping = function() {
- if(this._playbackResource == null || this._audioSpriteStopTime) {return;}
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- this._playbackResource.loop = true;
- };
-
- p._handleCleanUp = function () {
- var tag = this._playbackResource;
- if (tag != null) {
- tag.pause();
- tag.loop = false;
- tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);
- tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);
- tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);
- tag.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- tag.removeEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);
-
- try {
- tag.currentTime = this._startTime;
- } catch (e) {
- } // Reset Position
- createjs.HTMLAudioTagPool.set(this.src, tag);
- this._playbackResource = null;
- }
- };
-
- p._beginPlaying = function (playProps) {
- this._playbackResource = createjs.HTMLAudioTagPool.get(this.src);
- return this.AbstractSoundInstance__beginPlaying(playProps);
- };
-
- p._handleSoundReady = function (event) {
- if (this._playbackResource.readyState !== 4) {
- var tag = this._playbackResource;
- tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);
- tag.addEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);
- tag.preload = "auto"; // This is necessary for Firefox, as it won't ever "load" until this is set.
- tag.load();
- return;
- }
-
- this._updateVolume();
- this._playbackResource.currentTime = (this._startTime + this._position) * 0.001;
- if (this._audioSpriteStopTime) {
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);
- } else {
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);
- if(this._loop != 0) {
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- this._playbackResource.loop = true;
- }
- }
-
- this._playbackResource.play();
- };
-
- /**
- * Used to handle when a tag is not ready for immediate playback when it is returned from the HTMLAudioTagPool.
- * @method _handleTagReady
- * @param event
- * @protected
- */
- p._handleTagReady = function (event) {
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_READY, this._readyHandler, false);
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_STALLED, this._stalledHandler, false);
-
- this._handleSoundReady();
- };
-
- p._pause = function () {
- this._playbackResource.pause();
- };
-
- p._resume = function () {
- this._playbackResource.play();
- };
-
- p._updateVolume = function () {
- if (this._playbackResource != null) {
- var newVolume = (this._muted || createjs.Sound._masterMute) ? 0 : this._volume * createjs.Sound._masterVolume;
- if (newVolume != this._playbackResource.volume) {this._playbackResource.volume = newVolume;}
- }
- };
-
- p._calculateCurrentPosition = function() {
- return (this._playbackResource.currentTime * 1000) - this._startTime;
- };
-
- p._updatePosition = function() {
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false);
- try {
- this._playbackResource.currentTime = (this._position + this._startTime) * 0.001;
- } catch (error) { // Out of range
- this._handleSetPositionSeek(null);
- }
- };
-
- /**
- * Used to enable setting position, as we need to wait for that seek to be done before we add back our loop handling seek listener
- * @method _handleSetPositionSeek
- * @param event
- * @protected
- */
- p._handleSetPositionSeek = function(event) {
- if (this._playbackResource == null) { return; }
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._handleSetPositionSeek, false);
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- };
-
- /**
- * Timer used to loop audio sprites.
- * NOTE because of the inaccuracies in the timeupdate event (15 - 250ms) and in setting the tag to the desired timed
- * (up to 300ms), it is strongly recommended not to loop audio sprites with HTML Audio if smooth looping is desired
- *
- * @method _handleAudioSpriteLoop
- * @param event
- * @private
- */
- p._handleAudioSpriteLoop = function (event) {
- if(this._playbackResource.currentTime <= this._audioSpriteStopTime) {return;}
- this._playbackResource.pause();
- if(this._loop == 0) {
- this._handleSoundComplete(null);
- } else {
- this._position = 0;
- this._loop--;
- this._playbackResource.currentTime = this._startTime * 0.001;
- if(!this._paused) {this._playbackResource.play();}
- this._sendEvent("loop");
- }
- };
-
- // NOTE with this approach audio will loop as reliably as the browser allows
- // but we could end up sending the loop event after next loop playback begins
- p._handleLoop = function (event) {
- if(this._loop == 0) {
- this._playbackResource.loop = false;
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_SEEKED, this._loopHandler, false);
- }
- };
-
- p._updateStartTime = function () {
- this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001;
-
- if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);
- }
- };
-
- p._updateDuration = function () {
- this._audioSpriteStopTime = (this._startTime + this._duration) * 0.001;
-
- if(this.playState == createjs.Sound.PLAY_SUCCEEDED) {
- this._playbackResource.removeEventListener(createjs.HTMLAudioPlugin._AUDIO_ENDED, this._endedHandler, false);
- this._playbackResource.addEventListener(createjs.HTMLAudioPlugin._TIME_UPDATE, this._audioSpriteEndHandler, false);
- }
- };
-
- p._setDurationFromSource = function () {
- this._duration = createjs.HTMLAudioTagPool.getDuration(this.src);
- this._playbackResource = null;
- };
-
- createjs.HTMLAudioSoundInstance = createjs.promote(HTMLAudioSoundInstance, "AbstractSoundInstance");
-}());
-
-//##############################################################################
-// HTMLAudioPlugin.js
-//##############################################################################
-
-this.createjs = this.createjs || {};
-
-(function () {
-
- "use strict";
-
- /**
- * Play sounds using HTML <audio> tags in the browser. This plugin is the second priority plugin installed
- * by default, after the {{#crossLink "WebAudioPlugin"}}{{/crossLink}}. For older browsers that do not support html
- * audio, include and install the {{#crossLink "FlashAudioPlugin"}}{{/crossLink}}.
- *
- *
Known Browser and OS issues for HTML Audio
- * All browsers
- * Testing has shown in all browsers there is a limit to how many audio tag instances you are allowed. If you exceed
- * this limit, you can expect to see unpredictable results. Please use {{#crossLink "Sound.MAX_INSTANCES"}}{{/crossLink}} as
- * a guide to how many total audio tags you can safely use in all browsers. This issue is primarily limited to IE9.
- *
- * IE html limitations
- *
There is a delay in applying volume changes to tags that occurs once playback is started. So if you have
- * muted all sounds, they will all play during this delay until the mute applies internally. This happens regardless of
- * when or how you apply the volume change, as the tag seems to need to play to apply it.
- *
MP3 encoding will not always work for audio tags if it's not default. We've found default encoding with
- * 64kbps works.
- *
Occasionally very short samples will get cut off.
- *
There is a limit to how many audio tags you can load or play at once, which appears to be determined by
- * hardware and browser settings. See {{#crossLink "HTMLAudioPlugin.MAX_INSTANCES"}}{{/crossLink}} for a safe estimate.
- * Note that audio sprites can be used as a solution to this issue.
- *
- * Safari limitations
- *
Safari requires Quicktime to be installed for audio playback.
- *
- * iOS 6 limitations
- *
can only have one <audio> tag
- *
can not preload or autoplay the audio
- *
can not cache the audio
- *
can not play the audio except inside a user initiated event.
- *
Note it is recommended to use {{#crossLink "WebAudioPlugin"}}{{/crossLink}} for iOS (6+)
- *
audio sprites can be used to mitigate some of these issues and are strongly recommended on iOS
- *
- *
- * Android Native Browser limitations
- *
We have no control over audio volume. Only the user can set volume on their device.
- *
We can only play audio inside a user event (touch/click). This currently means you cannot loop sound or use a delay.
- * Android Chrome 26.0.1410.58 specific limitations
- *
Can only play 1 sound at a time.
- *
Sound is not cached.
- *
Sound can only be loaded in a user initiated touch/click event.
- *
There is a delay before a sound is played, presumably while the src is loaded.
- *
- *
- * See {{#crossLink "Sound"}}{{/crossLink}} for general notes on known issues.
- *
- * @class HTMLAudioPlugin
- * @extends AbstractPlugin
- * @constructor
- */
- function HTMLAudioPlugin() {
- this.AbstractPlugin_constructor();
-
-
- // Public Properties
- /**
- * This is no longer needed as we are now using object pooling for tags.
- *
- * NOTE this property only exists as a limitation of HTML audio.
- * @property defaultNumChannels
- * @type {Number}
- * @default 2
- * @since 0.4.0
- * @deprecated
- */
- this.defaultNumChannels = 2;
-
- this._capabilities = s._capabilities;
-
- this._loaderClass = createjs.SoundLoader;
- this._soundInstanceClass = createjs.HTMLAudioSoundInstance;
- }
-
- var p = createjs.extend(HTMLAudioPlugin, createjs.AbstractPlugin);
- var s = HTMLAudioPlugin;
-
- // TODO: deprecated
- // p.initialize = function() {}; // searchable for devs wondering where it is. REMOVED. See docs for details.
-
-
-// Static Properties
- /**
- * The maximum number of instances that can be loaded or played. This is a browser limitation, primarily limited to IE9.
- * The actual number varies from browser to browser (and is largely hardware dependant), but this is a safe estimate.
- * Audio sprites work around this limitation.
- * @property MAX_INSTANCES
- * @type {Number}
- * @default 30
- * @static
- */
- s.MAX_INSTANCES = 30;
-
- /**
- * Event constant for the "canPlayThrough" event for cleaner code.
- * @property _AUDIO_READY
- * @type {String}
- * @default canplaythrough
- * @static
- * @protected
- */
- s._AUDIO_READY = "canplaythrough";
-
- /**
- * Event constant for the "ended" event for cleaner code.
- * @property _AUDIO_ENDED
- * @type {String}
- * @default ended
- * @static
- * @protected
- */
- s._AUDIO_ENDED = "ended";
-
- /**
- * Event constant for the "seeked" event for cleaner code. We utilize this event for maintaining loop events.
- * @property _AUDIO_SEEKED
- * @type {String}
- * @default seeked
- * @static
- * @protected
- */
- s._AUDIO_SEEKED = "seeked";
-
- /**
- * Event constant for the "stalled" event for cleaner code.
- * @property _AUDIO_STALLED
- * @type {String}
- * @default stalled
- * @static
- * @protected
- */
- s._AUDIO_STALLED = "stalled";
-
- /**
- * Event constant for the "timeupdate" event for cleaner code. Utilized for looping audio sprites.
- * This event callsback ever 15 to 250ms and can be dropped by the browser for performance.
- * @property _TIME_UPDATE
- * @type {String}
- * @default timeupdate
- * @static
- * @protected
- */
- s._TIME_UPDATE = "timeupdate";
-
- /**
- * The capabilities of the plugin. This is generated via the {{#crossLink "HTMLAudioPlugin/_generateCapabilities"}}{{/crossLink}}
- * method. Please see the Sound {{#crossLink "Sound/getCapabilities"}}{{/crossLink}} method for an overview of all
- * of the available properties.
- * @property _capabilities
- * @type {Object}
- * @protected
- * @static
- */
- s._capabilities = null;
-
-
-// Static Methods
- /**
- * Determine if the plugin can be used in the current browser/OS. Note that HTML audio is available in most modern
- * browsers, but is disabled in iOS because of its limitations.
- * @method isSupported
- * @return {Boolean} If the plugin can be initialized.
- * @static
- */
- s.isSupported = function () {
- s._generateCapabilities();
- return (s._capabilities != null);
- };
-
- /**
- * Determine the capabilities of the plugin. Used internally. Please see the Sound API {{#crossLink "Sound/getCapabilities"}}{{/crossLink}}
- * method for an overview of plugin capabilities.
- * @method _generateCapabilities
- * @static
- * @protected
- */
- s._generateCapabilities = function () {
- if (s._capabilities != null) {return;}
- var t = document.createElement("audio");
- if (t.canPlayType == null) {return null;}
-
- s._capabilities = {
- panning:false,
- volume:true,
- tracks:-1
- };
-
- // determine which extensions our browser supports for this plugin by iterating through Sound.SUPPORTED_EXTENSIONS
- var supportedExtensions = createjs.Sound.SUPPORTED_EXTENSIONS;
- var extensionMap = createjs.Sound.EXTENSION_MAP;
- for (var i = 0, l = supportedExtensions.length; i < l; i++) {
- var ext = supportedExtensions[i];
- var playType = extensionMap[ext] || ext;
- s._capabilities[ext] = (t.canPlayType("audio/" + ext) != "no" && t.canPlayType("audio/" + ext) != "") || (t.canPlayType("audio/" + playType) != "no" && t.canPlayType("audio/" + playType) != "");
- } // OJR another way to do this might be canPlayType:"m4a", codex: mp4
- };
-
-
-// public methods
- p.register = function (loadItem) {
- var tag = createjs.HTMLAudioTagPool.get(loadItem.src);
- var loader = this.AbstractPlugin_register(loadItem);
- loader.setTag(tag);
-
- return loader;
- };
-
- p.removeSound = function (src) {
- this.AbstractPlugin_removeSound(src);
- createjs.HTMLAudioTagPool.remove(src);
- };
-
- p.create = function (src, startTime, duration) {
- var si = this.AbstractPlugin_create(src, startTime, duration);
- si.setPlaybackResource(null);
- return si;
- };
-
- p.toString = function () {
- return "[HTMLAudioPlugin]";
- };
-
- // plugin does not support these
- p.setVolume = p.getVolume = p.setMute = null;
-
-
- createjs.HTMLAudioPlugin = createjs.promote(HTMLAudioPlugin, "AbstractPlugin");
-}());
\ No newline at end of file
diff --git a/bomberman/frontend/src/main/webapp/sound/bomb.mp3 b/bomberman/frontend/src/main/webapp/sound/bomb.mp3
deleted file mode 100644
index e419cb6f43..0000000000
Binary files a/bomberman/frontend/src/main/webapp/sound/bomb.mp3 and /dev/null differ
diff --git a/bomberman/frontend/src/main/webapp/sound/bomb.ogg b/bomberman/frontend/src/main/webapp/sound/bomb.ogg
deleted file mode 100644
index 59912972df..0000000000
Binary files a/bomberman/frontend/src/main/webapp/sound/bomb.ogg and /dev/null differ
diff --git a/bomberman/frontend/src/main/webapp/sound/game.mp3 b/bomberman/frontend/src/main/webapp/sound/game.mp3
deleted file mode 100644
index fe931af90a..0000000000
Binary files a/bomberman/frontend/src/main/webapp/sound/game.mp3 and /dev/null differ
diff --git a/bomberman/frontend/src/main/webapp/sound/game.ogg b/bomberman/frontend/src/main/webapp/sound/game.ogg
deleted file mode 100644
index 46a859f37f..0000000000
Binary files a/bomberman/frontend/src/main/webapp/sound/game.ogg and /dev/null differ
diff --git a/lecture04/gradlew b/lecture04/gradlew
index cccdd3d517..af6708ff22 100755
--- a/lecture04/gradlew
+++ b/lecture04/gradlew
@@ -28,7 +28,7 @@ APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-DEFAULT_JVM_OPTS=""
+DEFAULT_JVM_OPTS='"-Xmx64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
diff --git a/lecture04/gradlew.bat b/lecture04/gradlew.bat
index e95643d6a2..0f8d5937c4 100644
--- a/lecture04/gradlew.bat
+++ b/lecture04/gradlew.bat
@@ -14,7 +14,7 @@ set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
-set DEFAULT_JVM_OPTS=
+set DEFAULT_JVM_OPTS="-Xmx64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
diff --git a/lecture05/gradle/wrapper/gradle-wrapper.properties b/lecture05/gradle/wrapper/gradle-wrapper.properties
index 568c50bf3a..577d4c5d62 100644
--- a/lecture05/gradle/wrapper/gradle-wrapper.properties
+++ b/lecture05/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Mon Sep 09 10:32:45 MSK 2019
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-all.zip
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip
+zipStoreBase=GRADLE_USER_HOME
diff --git a/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java b/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java
index 57cc119384..df1a64292b 100644
--- a/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java
+++ b/lecture05/src/main/java/ru/atom/mm/MatchMakerApp.java
@@ -2,6 +2,10 @@
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Scope;
+
+import java.util.Date;
@SpringBootApplication
@@ -9,4 +13,16 @@ public class MatchMakerApp {
public static void main(String[] args) throws Exception {
SpringApplication.run(MatchMakerApp.class, args);
}
+
+ @Bean
+ @Scope("prototype")
+ Date time() {
+ return new Date();
+ }
+
+ @Bean
+ @Scope("prototype")
+ Date timeFirst() {
+ return new Date(0);
+ }
}
diff --git a/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java b/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java
index 17cf04d52a..b17391a79d 100644
--- a/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java
+++ b/lecture05/src/main/java/ru/atom/mm/controller/ConnectionController.java
@@ -4,8 +4,10 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -14,8 +16,12 @@
import ru.atom.mm.model.Connection;
import ru.atom.mm.service.ConnectionQueue;
+import java.util.List;
+import java.util.stream.Collectors;
+
@Controller
+@Scope("singleton")
@RequestMapping("/connection")
public class ConnectionController {
private static final Logger log = LoggerFactory.getLogger(ConnectionController.class);
@@ -47,9 +53,12 @@ public void connect(@RequestParam("id") long id,
*
* curl -i localhost:8080/connection/list'
*/
+ @RequestMapping(
+ path = "list",
+ method = RequestMethod.GET,
+ produces = MediaType.TEXT_PLAIN_VALUE)
public String list() {
- throw new UnsupportedOperationException();
- }
-
-
+ String list = String.join("\n", (List) connectionQueue.getQueue());
+ return list;
+ }
}
diff --git a/lecture05/src/main/java/ru/atom/mm/controller/GameController.java b/lecture05/src/main/java/ru/atom/mm/controller/GameController.java
index a38b1f1f6f..6be886f71f 100644
--- a/lecture05/src/main/java/ru/atom/mm/controller/GameController.java
+++ b/lecture05/src/main/java/ru/atom/mm/controller/GameController.java
@@ -3,6 +3,8 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Scope;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -10,11 +12,14 @@
import org.springframework.web.bind.annotation.ResponseBody;
import ru.atom.mm.service.GameRepository;
+import java.util.Date;
+
/**
* Created by sergey on 3/15/17.
*/
@Controller
+@Scope("request")
@RequestMapping("/game")
public class GameController {
private static final Logger log = LoggerFactory.getLogger(GameController.class);
@@ -23,6 +28,9 @@ public class GameController {
@Autowired
private GameRepository gameRepository;
+ @Autowired
+ @Qualifier("time")
+ private Date now;
/**
* curl test
*
@@ -37,4 +45,13 @@ public String list() {
log.info("Games list request");
return gameRepository.getAll().toString();
}
+
+ @RequestMapping(
+ path = "time",
+ method = RequestMethod.GET,
+ produces = MediaType.TEXT_PLAIN_VALUE)
+ @ResponseBody
+ public String time() {
+ return now.toString();
+ }
}
diff --git a/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java
index b53356ba2d..149c93a6d0 100644
--- a/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java
+++ b/lecture05/src/test/java/ru/atom/mm/ConnectionControllerIntegrationTest.java
@@ -11,6 +11,7 @@
import org.springframework.test.web.servlet.MockMvc;
import static org.junit.Assert.assertTrue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@@ -22,7 +23,6 @@ public class ConnectionControllerIntegrationTest {
MockMvc mockMvc;
@Test
- @Ignore
public void connect() throws Exception {
mockMvc.perform(post("/connection/connect")
.content("id=1&name=a")
@@ -31,9 +31,10 @@ public void connect() throws Exception {
}
@Test
- @Ignore
public void list() throws Exception {
- assertTrue(false);
+ mockMvc.perform(get("/connection/list")
+ .contentType(MediaType.TEXT_PLAIN_VALUE))
+ .andExpect(status().isOk());
}
}
\ No newline at end of file
diff --git a/lecture06/build.gradle b/lecture06/build.gradle
index f522afc734..8cc8bd3b50 100644
--- a/lecture06/build.gradle
+++ b/lecture06/build.gradle
@@ -1,31 +1,38 @@
-dependencies {
- compile rootProject.libraries.spring_boot
- compile rootProject.libraries.log4j
- compile rootProject.libraries.postgres
- compile rootProject.libraries.jetbrainsAnnotations
-
- testCompile rootProject.libraries.junit
- testCompile rootProject.libraries.spring_boot_test
+plugins {
+ id 'org.springframework.boot' version '2.0.0.RELEASE'
}
-configurations {
- compile.exclude group:'ch.qos.logback'
+repositories {
+ mavenCentral()
+ maven {
+ url "http://clojars.org/repo/"
+ }
}
-springBoot {
- mainClass = "ru.atom.lecture06.server.ChatApplication"
-}
+apply plugin: 'java'
+apply plugin: 'checkstyle'
+dependencies {
+ // https://mvnrepository.com/artifact/org.slf4j/slf4j-api
+ compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.25'
+ // https://mvnrepository.com/artifact/org.apache.logging.log4j/log4j-slf4j-impl
+ //compile group: 'org.apache.logging.log4j', name: 'log4j-slf4j-impl', version: '2.10.0'
+ // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web
+ compile group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.0.0.RELEASE'
+ // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-actuator
+ compile group: 'org.springframework.boot', name: 'spring-boot-starter-actuator', version: '2.0.0.RELEASE'
+ // https://mvnrepository.com/artifact/postgresql/postgresql
+ compile group: 'postgresql', name: 'postgresql', version: '9.3-1102.jdbc41'
-sourceSets {
- main {
- java {
- srcDirs = ['src/main/java']
- }
- }
- test {
- java {
- srcDirs = ['src/test/java']
- }
- }
+
+ // https://mvnrepository.com/artifact/junit/junit
+ testCompile group: 'junit', name: 'junit', version: '4.4'
+ // https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test
+ testCompile group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.0.0.RELEASE'
}
+
+checkstyle {
+ ignoreFailures = false
+ toolVersion = '7.5'
+ configFile = new File('../config/checkstyle/checkstyle.xml')
+}
\ No newline at end of file
diff --git a/lecture06/gradle/wrapper/gradle-wrapper.jar b/lecture06/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000000..c44b679acd
Binary files /dev/null and b/lecture06/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/lecture06/gradle/wrapper/gradle-wrapper.properties b/lecture06/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000000..f51202dd25
--- /dev/null
+++ b/lecture06/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.5.1-bin.zip
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStorePath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
diff --git a/lecture06/gradlew b/lecture06/gradlew
new file mode 100755
index 0000000000..cccdd3d517
--- /dev/null
+++ b/lecture06/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/lecture06/gradlew.bat b/lecture06/gradlew.bat
new file mode 100644
index 0000000000..e95643d6a2
--- /dev/null
+++ b/lecture06/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/lecture06/lecture06.iml b/lecture06/lecture06.iml
new file mode 100644
index 0000000000..87da47998c
--- /dev/null
+++ b/lecture06/lecture06.iml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lecture06/presentation/PITCHME.md b/lecture06/presentation/PITCHME.md
index d3bc01d6ac..7f619f2990 100644
--- a/lecture06/presentation/PITCHME.md
+++ b/lecture06/presentation/PITCHME.md
@@ -1,19 +1,21 @@
-#HSLIDE
+---
# Java
lecture 6
## Java + DB
-#HSLIDE
+---
## Отметьтесь на портале
-https://atom.mail.ru/
+https://sphere.mail.ru/
-#HSLIDE
+---
### get ready #1
+[https://github.com/rybalkinsd/atom](https://github.com/rybalkinsd/atom)
```bash
> git fetch upstream
> git checkout -b lecture06 upstream/lecture06
+> cd lecture06
Refresh gradle project
```
@@ -21,13 +23,13 @@ Refresh gradle project
Refresh gradle project
-#HSLIDE
+---
### get ready #2
PostgreSQL client
linux
```bash
-apt-get install postgresql-9.4
+apt-get install postgresql-9.5
```
windows [[Download page]](https://www.postgresql.org/download/windows/)
@@ -38,10 +40,10 @@ mac
> brew install postgres
```
-#HSLIDE
+---
### get ready #3
```bash
-> psql -h 34.229.108.81 -U -d atomN
+> psql -h 54.224.37.210 -U atomN -d chatdb_atomN
> enter your password
>> psql (9.6.2, server 9.2.18)
>> Type "help" for help.
@@ -50,22 +52,35 @@ mac
select * from pg_catalog.pg_tables;
```
-`\q to exit :)`
+---
+### psql commands
+```bash
+#exit
+\q
+#list all schemas
+\dn
+#list all tables in all schemas
+\dt *.
+#describe table
+\d+ tablename
+```
+
-#HSLIDE
+---
### Agenda
-1. Retrospective
1. DB or not DB
1. Database baseline
1. SQL baseline
1. Java + DB
+---
+### Agenda
+1. **[DB or not DB]**
+1. Database baseline
+1. SQL baseline
+1. Java + DB
-#HSLIDE
-
-
-
-#HSLIDE
+---
### Storage comparison
**RAM** vs **File**
- Capacity
@@ -73,7 +88,7 @@ select * from pg_catalog.pg_tables;
- Durability
-#HSLIDE
+---
### Storage comparison
**File** vs **Database**
- Store overhead
@@ -81,7 +96,7 @@ select * from pg_catalog.pg_tables;
- Guarantees
- Speed
-#HSLIDE
+---
### Database (RDBMS)
Is a
@@ -96,14 +111,13 @@ Within
Management system
-#HSLIDE
-### DB types
-- SQL
-- NoSQL
-- In-memory
-- embedded
+---
+### Many different types of DBs
+- SQL/[NoSQL](https://en.wikipedia.org/wiki/NoSQL)
+- In-memory/disk storage
+- stand-alone/embedded
-#HSLIDE
+---
### Transaction
Transaction is a unit of work
@@ -115,17 +129,17 @@ Transaction is a unit of work
- Durability
-#HSLIDE
+---
## All examples below are in PostgreSQL
[[Official doc]](https://www.postgresql.org/docs/9.2/static/index.html)
-#HSLIDE
+---
### Table
```postgresql
create table user (
id serial not null,
- login varchar(20) unique not null,
+ login varchar(20) unique not null
);
```
**There is an error in create query**
@@ -133,7 +147,7 @@ create table user (
[[Read more about `serial`]](https://www.tutorialspoint.com/postgresql/postgresql_using_autoincrement.htm)
-#HSLIDE
+---
### Primary key
Indicates that a column or group of columns can be used as a unique identifier for rows in the table
@@ -147,7 +161,7 @@ create table chat.user (
```
-#HSLIDE
+---
### Schema
A schema is essentially a namespace.
@@ -164,12 +178,12 @@ create table chat.user (
[[Read more]](https://www.postgresql.org/docs/9.3/static/sql-createschema.html)
-#HSLIDE
+---
### First schema
@See resources/sql/schema/schema-1-simple.sql
-#HSLIDE
+---
### CRUD
1. **insert** for create
1. **select** for read
@@ -177,7 +191,7 @@ create table chat.user (
1. **delete** for delete
-#HSLIDE
+---
### select
```postgresql
select *
@@ -187,7 +201,7 @@ where time > '2017-03-25';
[[Read more]](https://www.postgresql.org/docs/9.2/static/sql-select.html)
-#HSLIDE
+---
### insert
```postgresql
insert into chat.user (login)
@@ -196,7 +210,7 @@ values ('admin');
[[Read more]](https://www.postgresql.org/docs/9.2/static/sql-insert.html)
-#HSLIDE
+---
### delete
```postgresql
delete from chat.user
@@ -206,14 +220,14 @@ where login = 'admin';
[[Read more]](https://www.postgresql.org/docs/9.2/static/sql-delete.html)
-#HSLIDE
+---
### Constraints
Imagine a user with lots of messages in history.
What happens when we delete this user?
-#HSLIDE
+---
### Constraints
```postgresql
drop table if exists chat.message;
@@ -232,12 +246,12 @@ What if chat.user has a complex pk?
[[Read more]](https://www.postgresql.org/docs/9.2/static/ddl-constraints.html)
-#HSLIDE
+---
### Second schema
@See resources/sql/schema/schema-2-constraints.sql
-#HSLIDE
+---
### What if one of queries is broken?
```postgresql
create table "user"();
@@ -249,8 +263,8 @@ values ('admin', now(), 'super message')
```
-#HSLIDE
-### Transation
+---
+### Transaction
```postgresql
begin;
{statements}
@@ -258,17 +272,17 @@ commit;
```
-#HSLIDE
+---
### Third schema
@See resources/sql/schema/schema-3-transaction.sql
-#HSLIDE
+---
### Java Database Connectivity
-#HSLIDE
+---
### Connection
```java
import java.sql.*;
@@ -279,7 +293,7 @@ Statement stm = con.createStatement();
ResultSet rs = stm.executeQuery("select * from chat.user");
```
-#HSLIDE
+---
### Dao
@See ru.atom.lecture06.server.model
@See ru.atom.lecture06.server.dao
@@ -289,11 +303,11 @@ ResultSet rs = stm.executeQuery("select * from chat.user");
- dbConnection
-#HSLIDE
+---
### Types mapping
-#HSLIDE
+---
### Practice
0) Check that DbConnector uses right **login**, **password** and **database**
@@ -305,7 +319,7 @@ Implement it using **MessageDao**
**Implement UserDao.getByName(String name)**
-#HSLIDE
+---
### Summary
1. JDBC is simple
1. JDBC leads to tones of boiler plate code
@@ -313,7 +327,7 @@ Implement it using **MessageDao**
1. Use transactions for atomic operations
-#HSLIDE
+---
**Оставьте обратную связь**
(вам на почту придет анкета)
diff --git a/lecture06/presentation/PITCHME.yaml b/lecture06/presentation/PITCHME.yaml
index ea67549844..aa3a413189 100644
--- a/lecture06/presentation/PITCHME.yaml
+++ b/lecture06/presentation/PITCHME.yaml
@@ -1,3 +1,3 @@
theme-override : lecture02/presentation/assets/css/PITCHME.css
-logo : lecture01/presentation/assets/img/atom.png
-slide-number: true
+logo : lecture01/presentation/assets/img/sphere.png
+slide-number: true
\ No newline at end of file
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java b/lecture06/src/main/java/ru/atom/ChatApplication.java
similarity index 89%
rename from lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java
rename to lecture06/src/main/java/ru/atom/ChatApplication.java
index a34cb79822..97a0753dc1 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/ChatApplication.java
+++ b/lecture06/src/main/java/ru/atom/ChatApplication.java
@@ -1,4 +1,4 @@
-package ru.atom.lecture06.server;
+package ru.atom;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java b/lecture06/src/main/java/ru/atom/controller/ChatController.java
similarity index 92%
rename from lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java
rename to lecture06/src/main/java/ru/atom/controller/ChatController.java
index c91a7af219..3ce7296ee4 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/controller/ChatController.java
+++ b/lecture06/src/main/java/ru/atom/controller/ChatController.java
@@ -1,7 +1,7 @@
-package ru.atom.lecture06.server.controller;
+package ru.atom.controller;
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
@@ -10,10 +10,10 @@
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseStatus;
-import ru.atom.lecture06.server.model.Message;
-import ru.atom.lecture06.server.model.User;
-import ru.atom.lecture06.server.dao.MessageDao;
-import ru.atom.lecture06.server.dao.UserDao;
+import ru.atom.dao.MessageDao;
+import ru.atom.dao.UserDao;
+import ru.atom.model.Message;
+import ru.atom.model.User;
import java.util.List;
import java.util.stream.Collectors;
@@ -21,7 +21,7 @@
@Controller
@RequestMapping("chat")
public class ChatController {
- private static final Logger log = LogManager.getLogger(ChatController.class);
+ private static final Logger log = LoggerFactory.getLogger(ChatController.class);
private final UserDao userDao = new UserDao();
private final MessageDao messageDao = new MessageDao();
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java b/lecture06/src/main/java/ru/atom/dao/Dao.java
similarity index 94%
rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java
rename to lecture06/src/main/java/ru/atom/dao/Dao.java
index 84aa019cdf..4ae3c798bd 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/Dao.java
+++ b/lecture06/src/main/java/ru/atom/dao/Dao.java
@@ -1,4 +1,4 @@
-package ru.atom.lecture06.server.dao;
+package ru.atom.dao;
import java.util.List;
import java.util.Optional;
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java b/lecture06/src/main/java/ru/atom/dao/DbConnector.java
similarity index 74%
rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java
rename to lecture06/src/main/java/ru/atom/dao/DbConnector.java
index 3dcfb76ada..90d1c56728 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/DbConnector.java
+++ b/lecture06/src/main/java/ru/atom/dao/DbConnector.java
@@ -1,10 +1,11 @@
-package ru.atom.lecture06.server.dao;
+package ru.atom.dao;
/**
* Created by sergey on 3/25/17.
*/
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -12,13 +13,13 @@
class DbConnector {
- private static final Logger log = LogManager.getLogger(DbConnector.class);
+ private static final Logger log = LoggerFactory.getLogger(DbConnector.class);
private static final String URL_TEMPLATE = "jdbc:postgresql://%s:%d/%s";
private static final String URL;
- private static final String HOST = "34.229.108.81";
+ private static final String HOST = "54.224.37.210";
private static final int PORT = 5432;
- private static final String DB_NAME = "atomN";
+ private static final String DB_NAME = "chatdb_atomN";
private static final String USER = "atomN";
private static final String PASSWORD = "atomN";
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java b/lecture06/src/main/java/ru/atom/dao/MessageDao.java
similarity index 85%
rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java
rename to lecture06/src/main/java/ru/atom/dao/MessageDao.java
index bcf39b5b27..f77766d4ec 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/MessageDao.java
+++ b/lecture06/src/main/java/ru/atom/dao/MessageDao.java
@@ -1,10 +1,9 @@
-package ru.atom.lecture06.server.dao;
+package ru.atom.dao;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.intellij.lang.annotations.Language;
-import ru.atom.lecture06.server.model.Message;
-import ru.atom.lecture06.server.model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.atom.model.Message;
+import ru.atom.model.User;
import java.sql.Connection;
import java.sql.ResultSet;
@@ -18,9 +17,8 @@
* Created by sergey on 3/25/17.
*/
public class MessageDao implements Dao {
- private static final Logger log = LogManager.getLogger(MessageDao.class);
+ private static final Logger log = LoggerFactory.getLogger(MessageDao.class);
- @Language("sql")
private static final String SELECT_ALL_MESSAGES =
"select m.time, m.value, u.* " +
"from chat.message as m " +
@@ -28,7 +26,6 @@ public class MessageDao implements Dao {
" on m.user = u.id " +
"order by m.time";
- @Language("sql")
private static final String INSERT_MESSAGE_TEMPLATE =
"insert into chat.message (\"user\", time, value) " +
"values (%d, now(), '%s')";
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java b/lecture06/src/main/java/ru/atom/dao/UserDao.java
similarity index 87%
rename from lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java
rename to lecture06/src/main/java/ru/atom/dao/UserDao.java
index 70c14133cf..05424d05b9 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/dao/UserDao.java
+++ b/lecture06/src/main/java/ru/atom/dao/UserDao.java
@@ -1,9 +1,8 @@
-package ru.atom.lecture06.server.dao;
+package ru.atom.dao;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.intellij.lang.annotations.Language;
-import ru.atom.lecture06.server.model.User;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import ru.atom.model.User;
import java.sql.Connection;
import java.sql.ResultSet;
@@ -17,20 +16,17 @@
* Created by sergey on 3/25/17.
*/
public class UserDao implements Dao {
- private static final Logger log = LogManager.getLogger(UserDao.class);
+ private static final Logger log = LoggerFactory.getLogger(UserDao.class);
- @Language("sql")
private static final String SELECT_ALL_USERS =
"select * " +
"from chat.user";
- @Language("sql")
private static final String SELECT_ALL_USERS_WHERE =
"select * " +
"from chat.user " +
"where ";
- @Language("sql")
private static final String INSERT_USER_TEMPLATE =
"insert into chat.user (login) " +
"values ('%s');";
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java b/lecture06/src/main/java/ru/atom/model/Message.java
similarity index 95%
rename from lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java
rename to lecture06/src/main/java/ru/atom/model/Message.java
index 413b8b4cb7..55dea52cb0 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/model/Message.java
+++ b/lecture06/src/main/java/ru/atom/model/Message.java
@@ -1,4 +1,4 @@
-package ru.atom.lecture06.server.model;
+package ru.atom.model;
import java.util.Date;
diff --git a/lecture06/src/main/java/ru/atom/lecture06/server/model/User.java b/lecture06/src/main/java/ru/atom/model/User.java
similarity index 93%
rename from lecture06/src/main/java/ru/atom/lecture06/server/model/User.java
rename to lecture06/src/main/java/ru/atom/model/User.java
index e0bbd2393b..19f78e6739 100644
--- a/lecture06/src/main/java/ru/atom/lecture06/server/model/User.java
+++ b/lecture06/src/main/java/ru/atom/model/User.java
@@ -1,4 +1,4 @@
-package ru.atom.lecture06.server.model;
+package ru.atom.model;
/**
* Created by sergey on 3/25/17.
diff --git a/lecture06/src/main/resources/static/index.html b/lecture06/src/main/resources/static/index.html
index 378a9849ae..b5bd89a21b 100644
--- a/lecture06/src/main/resources/static/index.html
+++ b/lecture06/src/main/resources/static/index.html
@@ -1,49 +1,7 @@
-
-
+
+
+
-
-