topical media & game development

talk show tell print

mobile-graphic-enchant-enchant.js / js



  
enchant.js v0.6.3 http://enchantjs.com Copyright Ubiquitous Entertainment Inc. Released under the MIT license.

  
  
  (function(window, undefined){
  
  
ECMA-262 5th edition Functions

  
  if (typeof Object.defineProperty !== 'function') {
      Object.defineProperty = function(obj, prop, desc) {
          if ('value' in desc) {
              obj[prop] = desc.value;
          }
          if ('get' in desc) {
              obj.__defineGetter__(prop, desc.get);
          }
          if ('set' in desc) {
              obj.__defineSetter__(prop, desc.set);
          }
          return obj;
      };
  }
  if (typeof Object.defineProperties !== 'function') {
      Object.defineProperties = function(obj, descs) {
          for (var prop in descs) {
              if (descs.hasOwnProperty(prop)) {
                  Object.defineProperty(obj, prop, descs[prop]);
              }
          }
          return obj;
      };
  }
  if (typeof Object.create !== 'function') {
      Object.create = function(prototype, descs) {
          function F() {
          }
  
          F.prototype = prototype;
          var obj = new F();
          if (descs != null) {
              Object.defineProperties(obj, descs);
          }
          return obj;
      };
  }
  if (typeof Object.getPrototypeOf !== 'function') {
      Object.getPrototypeOf = function(obj) {
          return obj.__proto__;
      };
  }
  
  if (typeof Function.prototype.bind !== 'function') {
      Function.prototype.bind = function(thisObject) {
          var func = this;
          var args = Array.prototype.slice.call(arguments, 1);
          var Nop = function() {
          };
          var bound = function() {
              var a = args.concat(Array.prototype.slice.call(arguments));
              return func.apply(
                  this instanceof Nop ? this : thisObject || window, a);
          };
          Nop.prototype = func.prototype;
          bound.prototype = new Nop();
          return bound;
      };
  }
  
  window.getTime = (function() {
      var origin;
      if (window.performance && window.performance.now) {
          origin = Date.now();
          return function() {
              return origin + window.performance.now();
          };
      } else if (window.performance && window.performance.webkitNow) {
          origin = Date.now();
          return function() {
              return origin + window.performance.webkitNow();
          };
      } else {
          return Date.now;
      }
  }());
  
  
define requestAnimationFrame

  
  window.requestAnimationFrame =
      window.requestAnimationFrame ||
      window.mozRequestAnimationFrame ||
      window.webkitRequestAnimationFrame ||
      window.msRequestAnimationFrame ||
      (function() {
          var lastTime = window.getTime();
          var frame = 1000 / 60;
          return function(func) {
              var currentTime = window.getTime();
              var _id = setTimeout(function() {
                  func(window.getTime());
              }, Math.max(0, lastTime + frame - currentTime));
              lastTime = currentTime;
              return _id;
          };
      }());
  
  
Export the library classes globally. When no arguments are given, all classes defined in enchant.js as well as all classes defined in plugins will be exported. When more than one argument is given, by default only classes defined in enchant.js will be exported. When you wish to export plugin classes you must explicitly deliver the plugin identifiers as arguments. @example enchant(); // All classes will be exported. enchant(''); // Only classes in enchant.js will be exported. enchant('ui'); // enchant.js classes and ui.enchant.js classes will be exported.
parameter: {...String} [modules] Export module. Multiple designations possible. @global @type {Object} @name enchant

  
  var enchant = function(modules) {
      if (modules != null) {
          if (!(modules instanceof Array)) {
              modules = Array.prototype.slice.call(arguments);
          }
          modules = modules.filter(function(module) {
              return [module].join();
          });
      }
      (function include(module, prefix) {
          var submodules = [],
              i, len;
          for (var prop in module) {
              if (module.hasOwnProperty(prop)) {
                  if (typeof module[prop] === 'function') {
                      window[prop] = module[prop];
                  } else if (typeof module[prop] === 'object' && module[prop] !== null && Object.getPrototypeOf(module[prop]) === Object.prototype) {
                      if (modules == null) {
                          submodules.push(prop);
                      } else {
                          i = modules.indexOf(prefix + prop);
                          if (i !== -1) {
                              submodules.push(prop);
                              modules.splice(i, 1);
                          }
                      }
                  }
              }
          }
  
          for (i = 0, len = submodules.length; i < len; i++) {
              include(module[submodules[i]], prefix + submodules[i] + '.');
          }
      }(enchant, ''));
  
      // issue 185
      if (enchant.Class.getInheritanceTree(window.Game).length <= enchant.Class.getInheritanceTree(window.Core).length) {
          window.Game = window.Core;
      }
  
      if (modules != null && modules.length) {
          throw new Error('Cannot load module: ' + modules.join(', '));
      }
  };
  
  
export enchant

  
  window.enchant = enchant;
  
  window.addEventListener("message", function(msg, origin) {
      try {
          var data = JSON.parse(msg.data);
          if (data.type === "event") {
              enchant.Core.instance.dispatchEvent(new enchant.Event(data.value));
          } else if (data.type === "debug") {
              switch (data.value) {
                  case "start":
                      enchant.Core.instance.start();
                      break;
                  case "pause":
                      enchant.Core.instance.pause();
                      break;
                  case "resume":
                      enchant.Core.instance.resume();
                      break;
                  case "tick":
                      enchant.Core.instance._tick();
                      break;
                  default:
                      break;
              }
          }
      } catch (e) {
          // ignore
      }
  }, false);
  
  
@name enchant.Class @class A Class representing a class which supports inheritance.
parameter: {Function} [superclass] The class from which the new class will inherit the class definition.
parameter: {*} definition Class definition. @constructor

  
  enchant.Class = function(superclass, definition) {
      return enchant.Class.create(superclass, definition);
  };
  
  
Create a class. When defining classes that inherit from other classes, the previous class is used as a base with the superclass's constructor as default. When overriding the default constructor, it is necessary to explicitly call the previous constructor to ensure a correct class initialization. @example var Ball = Class.create({ // Creates independent class. initialize: function(radius) { ... }, // Method definition. fall: function() { ... } }); var Ball = Class.create(Sprite); // Creates a class inheriting from "Sprite" var Ball = Class.create(Sprite, { // Creates a class inheriting "Sprite" initialize: function(radius) { // Overwrites constructor Sprite.call(this, radius*2, radius*2); // Applies previous constructor. this.image = core.assets['ball.gif']; } });
parameter: {Function} [superclass] The class from which the new class will inherit the class definition.
parameter: {*} [definition] Class definition. @static

  
  enchant.Class.create = function(superclass, definition) {
      if (superclass == null && definition){
          throw new Error("superclass is undefined (enchant.Class.create)");
      }else if(superclass == null){
          throw new Error("definition is undefined (enchant.Class.create)");
      }
  
      if (arguments.length === 0) {
          return enchant.Class.create(Object, definition);
      } else if (arguments.length === 1 && typeof arguments[0] !== 'function') {
          return enchant.Class.create(Object, arguments[0]);
      }
  
      for (var prop in definition) {
          if (definition.hasOwnProperty(prop)) {
              if (typeof definition[prop] === 'object' && definition[prop] !== null && Object.getPrototypeOf(definition[prop]) === Object.prototype) {
                  if (!('enumerable' in definition[prop])) {
                      definition[prop].enumerable = true;
                  }
              } else {
                  definition[prop] = { value: definition[prop], enumerable: true, writable: true };
              }
          }
      }
      var Constructor = function() {
          if (this instanceof Constructor) {
              Constructor.prototype.initialize.apply(this, arguments);
          } else {
              return new Constructor();
          }
      };
      Constructor.prototype = Object.create(superclass.prototype, definition);
      Constructor.prototype.constructor = Constructor;
      if (Constructor.prototype.initialize == null) {
          Constructor.prototype.initialize = function() {
              superclass.apply(this, arguments);
          };
      }
  
      var tree = this.getInheritanceTree(superclass);
      for (var i = 0, l = tree.length; i < l; i++) {
          if (typeof tree[i]._inherited === 'function') {
              tree[i]._inherited(Constructor);
              break;
          }
      }
  
      return Constructor;
  };
  
  
Get the inheritance tree of this class.
parameter: {ConstructorFunction}
returns: {...ConstructorFunction}

  
  enchant.Class.getInheritanceTree = function(Constructor) {
      var ret = [];
      var C = Constructor;
      var proto = C.prototype;
      while (C !== Object) {
          ret.push(C);
          proto = Object.getPrototypeOf(proto);
          C = proto.constructor;
      }
      return ret;
  };
  
  
@namespace Environment variable. @type {Object}

  
  enchant.ENV = {
      
Version of enchant.js @type {String}

  
      VERSION: "0.6.1",
      
The CSS vendor prefix of the current browser. @type {String}

  
      VENDOR_PREFIX: (function() {
          var ua = navigator.userAgent;
          if (ua.indexOf('Opera') !== -1) {
              return 'O';
          } else if (ua.indexOf('MSIE') !== -1) {
              return 'ms';
          } else if (ua.indexOf('WebKit') !== -1) {
              return 'webkit';
          } else if (navigator.product === 'Gecko') {
              return 'Moz';
          } else {
              return '';
          }
      }()),
      
Determines if the current browser supports touch. @type {Boolean} True, if touch is enabled.

  
      TOUCH_ENABLED: (function() {
          var div = document.createElement('div');
          div.setAttribute('ontouchstart', 'return');
          return typeof div.ontouchstart === 'function';
      }()),
      
Determines if the current browser is an iPhone with a retina display.
returns: {Boolean} True, if this display is a retina display

  
      RETINA_DISPLAY: (function() {
          if (navigator.userAgent.indexOf('iPhone') !== -1 && window.devicePixelRatio === 2) {
              var viewport = document.querySelector('meta[name="viewport"]');
              if (viewport == null) {
                  viewport = document.createElement('meta');
                  document.head.appendChild(viewport);
              }
              viewport.setAttribute('content', 'width=640');
              return true;
          } else {
              return false;
          }
      }()),
      
Determines if for current browser Flash should be used to play sound instead of the native audio class. @type {Boolean} True, if flash should be used.

  
      USE_FLASH_SOUND: (function() {
          var ua = navigator.userAgent;
          var vendor = navigator.vendor || "";
          // non-local access, not on mobile mobile device, not on safari
          return (location.href.indexOf('http') === 0 && ua.indexOf('Mobile') === -1 && vendor.indexOf('Apple') !== -1);
      }()),
      
If click/touch event occure for these tags the setPreventDefault() method will not be called.

  
      USE_DEFAULT_EVENT_TAGS: ['input', 'textarea', 'select', 'area'],
      CANVAS_DRAWING_METHODS: [
          'putImageData', 'drawImage', 'drawFocusRing', 'fill', 'stroke',
          'clearRect', 'fillRect', 'strokeRect', 'fillText', 'strokeText'
      ],
      
Keybind Table. You can use 'left', 'up', 'right', 'down', 'a', 'b' for preset event. @example enchant.ENV.KEY_BIND_TABLE = { 37: 'left', 38: 'up', 39: 'right', 40: 'down', 32: 'a', //-> use 'space' key as 'a button' }

  
      KEY_BIND_TABLE: {
          37: 'left',
          38: 'up',
          39: 'right',
          40: 'down'
      },
      PREVENT_DEFAULT_KEY_CODES: [37, 38, 39, 40, 32],
      
@type {Boolean}

  
      SOUND_ENABLED_ON_MOBILE_SAFARI: false,
      
Determines if WebAudioAPI is enabled. (true: use WebAudioAPI instead of Audio element if possible)

  
      USE_WEBAUDIO: (function(){
          return location.protocol !== 'file:';
      }()),
      
Determines if animation feature is enabled. (true: Timeline instance will be generated in new Node)

  
      USE_ANIMATION: true
  };
  
  
@scope enchant.Event.prototype

  
  enchant.Event = enchant.Class.create({
      
@name enchant.Event @class A class for an independent implementation of events similar to DOM Events. However, it does not include phase concept.
parameter: {String} type Event type. @constructs

  
      initialize: function(type) {
          
The type of the event. @type {String}

  
          this.type = type;
          
The target of the event. @type {*}

  
          this.target = null;
          
The x coordinate of the events occurrence. @type {Number}

  
          this.x = 0;
          
The y coordinate of the events occurrence. @type {Number}

  
          this.y = 0;
          
The event occurrences local coordinate systems x coordinates. @type {Number}

  
          this.localX = 0;
          
The event occurrences local coordinate systems y coordinates. @type {Number}

  
          this.localY = 0;
      },
      _initPosition: function(pageX, pageY) {
          var core = enchant.Core.instance;
          this.x = this.localX = (pageX - core._pageX) / core.scale;
          this.y = this.localY = (pageY - core._pageY) / core.scale;
      }
  });
  
  
An event dispatched upon completion of core loading. It is necessary to wait for loading to finish and to do initial processing when preloading images. Issued object: {gray enchant.Core} @example var core = new Core(320, 320); core.preload('player.gif'); core.onload = function() { ... // Describes initial core processing }; core.start(); @type {String}

  
  enchant.Event.LOAD = 'load';
  
  
Events which are occurring during core loading. Dispatched each time preloaded image is loaded. Issued object: {gray enchant.Core} @type {String}

  
  enchant.Event.PROGRESS = 'progress';
  
  
An event which is occurring when a new frame is beeing processed. Issued object: {gray enchant.Core}, {gray enchant.Node} @type {String}

  
  enchant.Event.ENTER_FRAME = 'enterframe';
  
  
An event which is occurring when the frame processing is about to end. Issued object: {gray enchant.Core} @type {String}

  
  enchant.Event.EXIT_FRAME = 'exitframe';
  
  
Events occurring during Scene beginning. Issued object: {gray enchant.Scene} @type {String}

  
  enchant.Event.ENTER = 'enter';
  
  
Events occurring during Scene end. Issued object: {gray enchant.Scene} @type {String}

  
  enchant.Event.EXIT = 'exit';
  
  
An event which is occurring when a Child is getting added to a Node. Issued object: {gray enchant.Group}, {gray enchant.Scene} @type {String}

  
  enchant.Event.CHILD_ADDED = 'childadded';
  
  
An event which is occurring when the Node is added to a Group. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.ADDED = 'added';
  
  
An event which is occurring when the Node is added to a Scene. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.ADDED_TO_SCENE = 'addedtoscene';
  
  
An event which is occurring when a Child is removed from a Node. Issued object: {gray enchant.Group}, {gray enchant.Scene} @type {String} @type {String}

  
  enchant.Event.CHILD_REMOVED = 'childremoved';
  
  
An event which is occurring when the Node is deleted from a Group. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.REMOVED = 'removed';
  
  
An event which is occurring when the Node is deleted from a Scene. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.REMOVED_FROM_SCENE = 'removedfromscene';
  
  
An event occurring when a touch related to the Node has begun. A click is also treated as touch. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.TOUCH_START = 'touchstart';
  
  
An event occurring when a touch related to the Node has been moved. A click is also treated as touch. Issued object: {gray enchant.Node} @type {String}

  
  enchant.Event.TOUCH_MOVE = 'touchmove';
  
  
An event which is occurring when a touch related to the Node has ended. A Click is also treated as touch. Issued object: enchant.Node @type {String}

  
  enchant.Event.TOUCH_END = 'touchend';
  
  
An event which is occurring when an Entity is rendered. Issued object: {gray enchant.Entity} @type {String}

  
  enchant.Event.RENDER = 'render';
  
  
An event which is occurring when a button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.INPUT_START = 'inputstart';
  
  
An event which is occurring when a button input changes. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.INPUT_CHANGE = 'inputchange';
  
  
An event which is occurring when a button input ends. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.INPUT_END = 'inputend';
  
  
An event which is occurring when the left button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.LEFT_BUTTON_DOWN = 'leftbuttondown';
  
  
An event which is occurring when the left button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.LEFT_BUTTON_UP = 'leftbuttonup';
  
  
An event which is occurring when the right button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.RIGHT_BUTTON_DOWN = 'rightbuttondown';
  
  
An event which is occurring when the right button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.RIGHT_BUTTON_UP = 'rightbuttonup';
  
  
An event which is occurring when the up button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.UP_BUTTON_DOWN = 'upbuttondown';
  
  
An event which is occurring when the up button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.UP_BUTTON_UP = 'upbuttonup';
  
  
An event which is occurring when the down button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.DOWN_BUTTON_DOWN = 'downbuttondown';
  
  
An event which is occurring when the down button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.DOWN_BUTTON_UP = 'downbuttonup';
  
  
An event which is occurring when the a button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.A_BUTTON_DOWN = 'abuttondown';
  
  
An event which is occurring when the a button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.A_BUTTON_UP = 'abuttonup';
  
  
An event which is occurring when the b button is pressed. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.B_BUTTON_DOWN = 'bbuttondown';
  
  
An event which is occurring when the b button is released. Issued object: {gray enchant.Core}, {gray enchant.Scene} @type {String}

  
  enchant.Event.B_BUTTON_UP = 'bbuttonup';
  
  

  
  enchant.Event.ADDED_TO_TIMELINE = "addedtotimeline";
  
  
@type {String}

  
  enchant.Event.REMOVED_FROM_TIMELINE = "removedfromtimeline";
  
  
@type {String}

  
  enchant.Event.ACTION_START = "actionstart";
  
  
@type {String}

  
  enchant.Event.ACTION_END = "actionend";
  
  
@type {String}

  
  enchant.Event.ACTION_TICK = "actiontick";
  
  
@type {String}

  
  enchant.Event.ACTION_ADDED = "actionadded";
  
  
@type {String}

  
  enchant.Event.ACTION_REMOVED = "actionremoved";
  
  
@scope enchant.EventTarget.prototype

  
  enchant.EventTarget = enchant.Class.create({
      
@name enchant.EventTarget @class A class for an independent implementation of events similar to DOM Events. However, it does not include the phase concept. @extends {enchant.Event} @constructs

  
      initialize: function() {
          this._listeners = {};
      },
      
Add a new event listener which will be executed when the event is being dispatched.
parameter: {String} type Type of the events.
parameter: {function(e:enchant.Event)} listener Event listener to be added.

  
      addEventListener: function(type, listener) {
          var listeners = this._listeners[type];
          if (listeners == null) {
              this._listeners[type] = [listener];
          } else if (listeners.indexOf(listener) === -1) {
              listeners.unshift(listener);
  
          }
      },
      
Synonym for addEventListener
see: {enchant.EventTarget#addEventListener}
parameter: {String} type Type of the events.
parameter: {function(e:enchant.Event)} listener Event listener to be added.

  
      on: function() {
          this.addEventListener.apply(this, arguments);
      },
      
Delete an event listener.
parameter: {String} type Type of the events.
parameter: {function(e:enchant.Event)} listener Event listener to be deleted.

  
      removeEventListener: function(type, listener) {
          var listeners = this._listeners[type];
          if (listeners != null) {
              var i = listeners.indexOf(listener);
              if (i !== -1) {
                  listeners.splice(i, 1);
              }
          }
      },
      
Clear all defined event listener for a given type. If no type is given, all listener will be removed.
parameter: [String] type Type of the events.

  
      clearEventListener: function(type) {
          if (type != null) {
              delete this._listeners[type];
          } else {
              this._listeners = {};
          }
      },
      
Issue an event.
parameter: {enchant.Event} e Event to be issued.

  
      dispatchEvent: function(e) {
          e.target = this;
          e.localX = e.x - this._offsetX;
          e.localY = e.y - this._offsetY;
          if (this['on' + e.type] != null){
              this['on' + e.type](e);
          }
          var listeners = this._listeners[e.type];
          if (listeners != null) {
              listeners = listeners.slice();
              for (var i = 0, len = listeners.length; i < len; i++) {
                  listeners[i].call(this, e);
              }
          }
      }
  });
  
  
@scope enchant.Core.prototype

  
  (function() {
      var core;
      
@scope enchant.Core.prototype

  
      enchant.Core = enchant.Class.create(enchant.EventTarget, {
          
@name enchant.Core @class A class which is controlling the cores main loop and scenes. There can be only one instance at a time, when the constructor is executed with an instance present, the existing instance will be overwritten. The existing instance can be accessed from {gray enchant.Core.instance}.
parameter: {Number} width The width of the core screen.
parameter: {Number} height The height of the core screen. @constructs @extends enchant.EventTarget

  
          initialize: function(width, height) {
              if (window.document.body === null) {
                  // @TODO postpone initialization after window.onload
                  throw new Error("document.body is null. Please excute 'new Core()' in window.onload.");
              }
  
              enchant.EventTarget.call(this);
              var initial = true;
              if (core) {
                  initial = false;
                  core.stop();
              }
              core = enchant.Core.instance = this;
  
              
The width of the core screen. @type {Number}

  
              this.width = width || 320;
              
The height of the core screen. @type {Number}

  
              this.height = height || 320;
              
The scaling of the core rendering. @type {Number}

  
              this.scale = 1;
  
              var stage = document.getElementById('enchant-stage');
              if (!stage) {
                  stage = document.createElement('div');
                  stage.id = 'enchant-stage';
  //                stage.style.width = window.innerWidth + 'px';
  //                stage.style.height = window.innerHeight + 'px';
                  stage.style.position = 'absolute';
  
                  if (document.body.firstChild) {
                      document.body.insertBefore(stage, document.body.firstChild);
                  } else {
                      document.body.appendChild(stage);
                  }
                  this.scale = Math.min(
                      window.innerWidth / this.width,
                      window.innerHeight / this.height
                  );
                  this._pageX = 0;
                  this._pageY = 0;
              } else {
                  var style = window.getComputedStyle(stage);
                  width = parseInt(style.width, 10);
                  height = parseInt(style.height, 10);
                  if (width && height) {
                      this.scale = Math.min(
                          width / this.width,
                          height / this.height
                      );
                  } else {
                      stage.style.width = this.width + 'px';
                      stage.style.height = this.height + 'px';
                  }
                  while (stage.firstChild) {
                      stage.removeChild(stage.firstChild);
                  }
                  stage.style.position = 'relative';
  
                  var bounding = stage.getBoundingClientRect();
                  this._pageX = Math.round(window.scrollX || window.pageXOffset + bounding.left);
                  this._pageY = Math.round(window.scrollY || window.pageYOffset + bounding.top);
              }
              if (!this.scale) {
                  this.scale = 1;
              }
              stage.style.fontSize = '12px';
              stage.style.webkitTextSizeAdjust = 'none';
              this._element = stage;
  
              
The frame rate of the core. @type {Number}

  
              this.fps = 30;
              
The amount of frames since the core was started. @type {Number}

  
              this.frame = 0;
              
Indicates if the core can be executed. @type {Boolean}

  
              this.ready = false;
              
Indicates if the core is currently executed. @type {Boolean}

  
              this.running = false;
              
Object which stores loaded objects with the path as key. @type {Object.<String, Surface>}

  
              this.assets = {};
              var assets = this._assets = [];
              (function detectAssets(module) {
                  if (module.assets instanceof Array) {
                      [].push.apply(assets, module.assets);
                  }
                  for (var prop in module) {
                      if (module.hasOwnProperty(prop)) {
                          if (typeof module[prop] === 'object' && module[prop] !== null && Object.getPrototypeOf(module[prop]) === Object.prototype) {
                              detectAssets(module[prop]);
                          }
                      }
                  }
              }(enchant));
  
              this._scenes = [];
              
The Scene which is currently displayed. This Scene is on top of Scene stack. @type {enchant.Scene}

  
              this.currentScene = null;
              
The root Scene. The Scene at bottom of Scene stack. @type {enchant.Scene}

  
              this.rootScene = new enchant.Scene();
              this.pushScene(this.rootScene);
              
The Scene which is getting displayed during loading. @type {enchant.Scene}

  
              this.loadingScene = new enchant.Scene();
              this.loadingScene.backgroundColor = '#000';
              var barWidth = this.width * 0.4 | 0;
              var barHeight = this.width * 0.05 | 0;
              var border = barWidth * 0.03 | 0;
              var bar = new enchant.Sprite(barWidth, barHeight);
  
              bar.x = (this.width - barWidth) / 2;
              bar.y = (this.height - barHeight) / 2;
              var image = new enchant.Surface(barWidth, barHeight);
              image.context.fillStyle = '#fff';
              image.context.fillRect(0, 0, barWidth, barHeight);
              image.context.fillStyle = '#000';
              image.context.fillRect(border, border, barWidth - border * 2, barHeight - border * 2);
              bar.image = image;
              var progress = 0, _progress = 0;
              this.addEventListener('progress', function(e) {
                  // avoid #167 github.com/wise9/enchant.js/issues/177
                  progress = e.loaded / e.total * 1.0;
              });
              bar.addEventListener('enterframe', function() {
                  _progress *= 0.9;
                  _progress += progress * 0.1;
                  image.context.fillStyle = '#fff';
                  image.context.fillRect(border, 0, (barWidth - border * 2) * _progress, barHeight);
              });
              this.loadingScene.addChild(bar);
  
              this._calledTime = 0;
  
              this._mousedownID = 0;
              this._surfaceID = 0;
              this._soundID = 0;
  
              
@type {Boolean} @private

  
              this._activated = false;
  
              this._offsetX = 0;
              this._offsetY = 0;
  
              
Object that saves the current input state for the core. @type {Object.<String, Boolean>}

  
              this.input = {};
              if (!enchant.ENV.KEY_BIND_TABLE) {
                  enchant.ENV.KEY_BIND_TABLE = {};
              }
              this._keybind = enchant.ENV.KEY_BIND_TABLE;
              this.pressedKeysNum = 0;
              this._internalButtondownListeners = {};
              this._internalButtonupListeners = {};
  
              for (var prop in this._keybind) {
                  this.keybind(prop, this._keybind[prop]);
              }
  
              if (initial) {
                  stage = enchant.Core.instance._element;
                  var evt;
                  document.addEventListener('keydown', function(e) {
                      core.dispatchEvent(new enchant.Event('keydown'));
                      if (enchant.ENV.PREVENT_DEFAULT_KEY_CODES.indexOf(e.keyCode) !== -1) {
                          e.preventDefault();
                          e.stopPropagation();
                      }
  
                      if (!core.running) {
                          return;
                      }
                      var button = core._keybind[e.keyCode];
                      if (button) {
                          evt = new enchant.Event(button + 'buttondown');
                          core.dispatchEvent(evt);
                      }
                  }, true);
                  document.addEventListener('keyup', function(e) {
                      if (!core.running) {
                          return;
                      }
                      var button = core._keybind[e.keyCode];
                      if (button) {
                          evt = new enchant.Event(button + 'buttonup');
                          core.dispatchEvent(evt);
                      }
                  }, true);
  
                  if (enchant.ENV.TOUCH_ENABLED) {
                      stage.addEventListener('touchstart', function(e) {
                          var tagName = (e.target.tagName).toLowerCase();
                          if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                              e.preventDefault();
                              if (!core.running) {
                                  e.stopPropagation();
                              }
                          }
                      }, true);
                      stage.addEventListener('touchmove', function(e) {
                          var tagName = (e.target.tagName).toLowerCase();
                          if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                              e.preventDefault();
                              if (!core.running) {
                                  e.stopPropagation();
                              }
                          }
                      }, true);
                      stage.addEventListener('touchend', function(e) {
                          var tagName = (e.target.tagName).toLowerCase();
                          if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                              e.preventDefault();
                              if (!core.running) {
                                  e.stopPropagation();
                              }
                          }
                      }, true);
                  }
                  stage.addEventListener('mousedown', function(e) {
                      var tagName = (e.target.tagName).toLowerCase();
                      if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                          e.preventDefault();
                          core._mousedownID++;
                          if (!core.running) {
                              e.stopPropagation();
                          }
                      }
                  }, true);
                  stage.addEventListener('mousemove', function(e) {
                      var tagName = (e.target.tagName).toLowerCase();
                      if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                          e.preventDefault();
                          if (!core.running) {
                              e.stopPropagation();
                          }
                      }
                  }, true);
                  stage.addEventListener('mouseup', function(e) {
                      var tagName = (e.target.tagName).toLowerCase();
                      if (enchant.ENV.USE_DEFAULT_EVENT_TAGS.indexOf(tagName) === -1) {
                          e.preventDefault();
                          if (!core.running) {
                              e.stopPropagation();
                          }
                      }
                  }, true);
                  core._touchEventTarget = {};
                  if (enchant.ENV.TOUCH_ENABLED) {
                      stage.addEventListener('touchstart', function(e) {
                          var core = enchant.Core.instance;
                          var evt = new enchant.Event(enchant.Event.TOUCH_START);
                          var touches = e.changedTouches;
                          var touch, target;
                          for (var i = 0, l = touches.length; i < l; i++) {
                              touch = touches[i];
                              evt._initPosition(touch.pageX, touch.pageY);
                              target = core.currentScene._determineEventTarget(evt);
                              core._touchEventTarget[touch.identifier] = target;
                              target.dispatchEvent(evt);
                          }
                      }, false);
                      stage.addEventListener('touchmove', function(e) {
                          var core = enchant.Core.instance;
                          var evt = new enchant.Event(enchant.Event.TOUCH_MOVE);
                          var touches = e.changedTouches;
                          var touch, target;
                          for (var i = 0, l = touches.length; i < l; i++) {
                              touch = touches[i];
                              target = core._touchEventTarget[touch.identifier];
                              if (target) {
                                  evt._initPosition(touch.pageX, touch.pageY);
                                  target.dispatchEvent(evt);
                              }
                          }
                      }, false);
                      stage.addEventListener('touchend', function(e) {
                          var core = enchant.Core.instance;
                          var evt = new enchant.Event(enchant.Event.TOUCH_END);
                          var touches = e.changedTouches;
                          var touch, target;
                          for (var i = 0, l = touches.length; i < l; i++) {
                              touch = touches[i];
                              target = core._touchEventTarget[touch.identifier];
                              if (target) {
                                  evt._initPosition(touch.pageX, touch.pageY);
                                  target.dispatchEvent(evt);
                                  delete core._touchEventTarget[touch.identifier];
                              }
                          }
                      }, false);
                  }
                  stage.addEventListener('mousedown', function(e) {
                      var core = enchant.Core.instance;
                      var evt = new enchant.Event(enchant.Event.TOUCH_START);
                      evt._initPosition(e.pageX, e.pageY);
                      var target = core.currentScene._determineEventTarget(evt);
                      core._touchEventTarget[core._mousedownID] = target;
                      target.dispatchEvent(evt);
                  }, false);
                  stage.addEventListener('mousemove', function(e) {
                      var core = enchant.Core.instance;
                      var evt = new enchant.Event(enchant.Event.TOUCH_MOVE);
                      evt._initPosition(e.pageX, e.pageY);
                      var target = core._touchEventTarget[core._mousedownID];
                      if (target) {
                          target.dispatchEvent(evt);
                      }
                  }, false);
                  stage.addEventListener('mouseup', function(e) {
                      var core = enchant.Core.instance;
                      var evt = new enchant.Event(enchant.Event.TOUCH_END);
                      evt._initPosition(e.pageX, e.pageY);
                      var target = core._touchEventTarget[core._mousedownID];
                      if (target) {
                          target.dispatchEvent(evt);
                      }
                      delete core._touchEventTarget[core._mousedownID];
                  }, false);
              }
          },
          
Performs a file preload. Sets files which are to be preloaded. When {gray enchant.Core#start} is called the actual loading takes place. When all files are loaded, a {gray enchant.Event.LOAD} event is dispatched from the Core object. Depending on the type of the file different objects will be created and stored in {gray enchant.Core#assets} Variable. When an image file is loaded, an {gray enchant.Surface} is created. If a sound file is loaded, an {gray enchant.Sound} object is created. Otherwise it will be accessible as a string. In addition, because this Surface object used made with {gray enchant.Surface.load}, direct object manipulation is not possible. Refer to the items of {gray enchant.Surface.load} @example core.preload('player.gif'); core.onload = function() { var sprite = new Sprite(32, 32); sprite.image = core.assets['player.gif']; // Access via path ... }; core.start();
parameter: {...String} assets Path of images to be preloaded. Multiple settings possible.

  
          preload: function(assets) {
              if (!(assets instanceof Array)) {
                  assets = Array.prototype.slice.call(arguments);
              }
              [].push.apply(this._assets, assets);
          },
          
Loads a file.
parameter: {String} asset File path of the resource to be loaded.
parameter: {Function} [callback] Function called up when file loading is finished.

  
          load: function(src, callback) {
              if (callback == null) {
                  callback = function() {
                  };
              }
  
              var ext = enchant.Core.findExt(src);
  
              if (enchant.Core._loadFuncs[ext]) {
                  enchant.Core._loadFuncs[ext].call(this, src, callback, ext);
              }
              else {
                  var req = new XMLHttpRequest();
                  req.open('GET', src, true);
                  req.onreadystatechange = function(e) {
                      if (req.readyState === 4) {
                          if (req.status !== 200 && req.status !== 0) {
                              throw new Error(req.status + ': ' + 'Cannot load an asset: ' + src);
                          }
  
                          var type = req.getResponseHeader('Content-Type') || '';
                          if (type.match(/^image/)) {
                              core.assets[src] = enchant.Surface.load(src, callback);
                          } else if (type.match(/^audio/)) {
                              core.assets[src] = enchant.Sound.load(src, type, callback);
                          } else {
                              core.assets[src] = req.responseText;
                              callback();
                          }
                      }
                  };
                  req.send(null);
              }
          },
          
Start the core. Obeying the frame rate set in {gray enchant.Core#fps}, the frame in {gray enchant.Core#currentScene} will be updated. If images to preload are present, loading will begin and the loading screen will be displayed.

  
          start: function() {
              var onloadTimeSetter = function() {
                  this.frame = 0;
                  this.removeEventListener('load', onloadTimeSetter);
              };
              this.addEventListener('load', onloadTimeSetter);
  
              this.currentTime = window.getTime();
              this.running = true;
              this.ready = true;
              this._requestNextFrame(0);
  
              if (!this._activated) {
                  this._activated = true;
                  if (enchant.ENV.SOUND_ENABLED_ON_MOBILE_SAFARI && !core._touched &&
                      (navigator.userAgent.indexOf('iPhone OS') !== -1 ||
                      navigator.userAgent.indexOf('iPad') !== -1)) {
                      var scene = new enchant.Scene();
                      scene.backgroundColor = '#000';
                      var size = Math.round(core.width / 10);
                      var sprite = new enchant.Sprite(core.width, size);
                      sprite.y = (core.height - size) / 2;
                      sprite.image = new enchant.Surface(core.width, size);
                      sprite.image.context.fillStyle = '#fff';
                      sprite.image.context.font = (size - 1) + 'px bold Helvetica,Arial,sans-serif';
                      var width = sprite.image.context.measureText('Touch to Start').width;
                      sprite.image.context.fillText('Touch to Start', (core.width - width) / 2, size - 1);
                      scene.addChild(sprite);
                      document.addEventListener('touchstart', function() {
                          core._touched = true;
                          core.removeScene(scene);
                          core.start();
                      }, true);
                      core.pushScene(scene);
                      return;
                  }
              }
              if (this._assets.length) {
  
                  var o = {};
                  var assets = this._assets.filter(function(asset) {
                      return asset in o ? false : o[asset] = true;
                  });
                  var loaded = 0,
                      len = assets.length,
                      loadFunc = function() {
                          var e = new enchant.Event('progress');
                          e.loaded = ++loaded;
                          e.total = len;
                          core.dispatchEvent(e);
                          if (loaded === len) {
                              core.removeScene(core.loadingScene);
                              core.dispatchEvent(new enchant.Event('load'));
                          }
                      };
  
                  this.pushScene(this.loadingScene);
                  for (var i = 0; i < len; i++) {
                      this.load(assets[i], loadFunc);
                  }
              } else {
                  this.dispatchEvent(new enchant.Event('load'));
              }
          },
          
Begin core debug mode. Core debug mode can be set to on even if enchant.Core.instance._debug flag is already set to true.

  
          debug: function() {
              this._debug = true;
              this.start();
          },
          actualFps: {
              get: function() {
                  return this._actualFps || this.fps;
              }
          },
          
@private

  
          _requestNextFrame: function(delay) {
              if (!this.ready) {
                  return;
              }
              setTimeout(function() {
                  var core = enchant.Core.instance;
                  core._calledTime = window.getTime();
                  window.requestAnimationFrame(core._callTick);
              }, delay);
          },
          
@private

  
          _callTick: function(time) {
              enchant.Core.instance._tick(time);
          },
          _tick: function(time) {
              var e = new enchant.Event('enterframe');
              var now = window.getTime();
              var elapsed = e.elapsed = now - this.currentTime;
  
              this._actualFps = e.elapsed > 0 ? (1000 / e.elapsed) : 0;
  
              var nodes = this.currentScene.childNodes.slice();
              var push = Array.prototype.push;
              while (nodes.length) {
                  var node = nodes.pop();
                  node.age++;
                  node.dispatchEvent(e);
                  if (node.childNodes) {
                      push.apply(nodes, node.childNodes);
                  }
              }
  
              this.currentScene.age++;
              this.currentScene.dispatchEvent(e);
              this.dispatchEvent(e);
  
              this.dispatchEvent(new enchant.Event('exitframe'));
              this.frame++;
              this.currentTime = now;
              this._requestNextFrame(1000 / this.fps - (now - this._calledTime));
          },
          getTime: function() {
              return window.getTime();
          },
          
Stops the core. The frame will not be updated, and player input will not be accepted anymore. Core can be restarted using {gray enchant.Core#start}.

  
          stop: function() {
              this.ready = false;
              this.running = false;
          },
          
Stops the core. The frame will not be updated, and player input will not be accepted anymore. Core can be started again using {gray enchant.Core#start}.

  
          pause: function() {
              this.ready = false;
          },
          
Resumes the core.

  
          resume: function() {
              if (this.ready) {
                  return;
              }
              this.currentTime = window.getTime();
              this.ready = true;
              this.running = true;
              this._requestNextFrame(0);
          },
  
          
Switch to a new Scene. Scenes are controlled using a stack, and the display order also obeys that stack order. When {gray enchant.Core#pushScene} is executed, the Scene can be brought to the top of stack. Frames will be updated in the Scene which is on the top of the stack.
parameter: {enchant.Scene} scene The new scene to be switched to.
returns: {enchant.Scene} The new Scene.

  
          pushScene: function(scene) {
              this._element.appendChild(scene._element);
              if (this.currentScene) {
                  this.currentScene.dispatchEvent(new enchant.Event('exit'));
              }
              this.currentScene = scene;
              this.currentScene.dispatchEvent(new enchant.Event('enter'));
              return this._scenes.push(scene);
          },
          
Ends the current Scene, return to the previous Scene. Scenes are controlled using a stack, and the display order also obeys that stack order. When {gray enchant.Core#popScene} is executed, the Scene at the top of the stack will be removed and returned.
returns: {enchant.Scene} Ended Scene.

  
          popScene: function() {
              if (this.currentScene === this.rootScene) {
                  return this.currentScene;
              }
              this._element.removeChild(this.currentScene._element);
              this.currentScene.dispatchEvent(new enchant.Event('exit'));
              this.currentScene = this._scenes[this._scenes.length - 2];
              this.currentScene.dispatchEvent(new enchant.Event('enter'));
              return this._scenes.pop();
          },
          
Overwrites the current Scene with a new Scene. {gray enchant.Core#popScene}, {gray enchant.Core#pushScene} are executed after each other to replace to current scene with the new scene.
parameter: {enchant.Scene} scene The new scene which will replace the previous scene.
returns: {enchant.Scene} The new Scene.

  
          replaceScene: function(scene) {
              this.popScene();
              return this.pushScene(scene);
          },
          
Removes a Scene. Removes a Scene from the Scene stack.
parameter: {enchant.Scene} scene Scene to be removed.
returns: {enchant.Scene} The deleted Scene.

  
          removeScene: function(scene) {
              if (this.currentScene === scene) {
                  return this.popScene();
              } else {
                  var i = this._scenes.indexOf(scene);
                  if (i !== -1) {
                      this._scenes.splice(i, 1);
                      this._element.removeChild(scene._element);
                      return scene;
                  } else {
                      return null;
                  }
              }
          },
          
Set a key binding.
parameter: {Number} key Key code for the button which will be bound.
parameter: {String} button The enchant.js button (left, right, up, down, a, b).

  
          keybind: function(key, button) {
              this._keybind[key] = button;
              var onxbuttondown = function(e) {
                  var inputEvent;
                  if (!this.input[button]) {
                      this.input[button] = true;
                      inputEvent = new enchant.Event((this.pressedKeysNum++) ? 'inputchange' : 'inputstart');
                      this.dispatchEvent(inputEvent);
                      this.currentScene.dispatchEvent(inputEvent);
                  }
                  this.currentScene.dispatchEvent(e);
              };
              var onxbuttonup = function(e) {
                  var inputEvent;
                  if (this.input[button]) {
                      this.input[button] = false;
                      inputEvent = new enchant.Event((--this.pressedKeysNum) ? 'inputchange' : 'inputend');
                      this.dispatchEvent(inputEvent);
                      this.currentScene.dispatchEvent(inputEvent);
                  }
                  this.currentScene.dispatchEvent(e);
              };
  
              this.addEventListener(button + 'buttondown', onxbuttondown);
              this.addEventListener(button + 'buttonup', onxbuttonup);
  
              this._internalButtondownListeners[key] = onxbuttondown;
              this._internalButtonupListeners[key] = onxbuttonup;
          },
          
Delete a key binding.
parameter: {Number} key Key code that want to delete.

  
          keyunbind: function(key) {
              if (!this._keybind[key]) {
                  return;
              }
              var buttondowns = this._internalButtondownListeners;
              var buttonups = this._internalButtonupListeners;
  
              this.removeEventListener(key + 'buttondown', buttondowns);
              this.removeEventListener(key + 'buttonup', buttonups);
  
              delete buttondowns[key];
              delete buttonups[key];
  
              delete this._keybind[key];
          },
          
Get the elapsed core time (not actual) from when core.start was called.
returns: {Number} The elapsed time (seconds)

  
          getElapsedTime: function() {
              return this.frame / this.fps;
          }
      });
  
      enchant.Core._loadFuncs = {};
      enchant.Core._loadFuncs['jpg'] =
          enchant.Core._loadFuncs['jpeg'] =
              enchant.Core._loadFuncs['gif'] =
                  enchant.Core._loadFuncs['png'] =
                      enchant.Core._loadFuncs['bmp'] = function(src, callback) {
                          this.assets[src] = enchant.Surface.load(src, callback);
                      };
      enchant.Core._loadFuncs['mp3'] =
          enchant.Core._loadFuncs['aac'] =
              enchant.Core._loadFuncs['m4a'] =
                  enchant.Core._loadFuncs['wav'] =
                      enchant.Core._loadFuncs['ogg'] = function(src, callback, ext) {
                          this.assets[src] = enchant.Sound.load(src, 'audio/' + ext, callback);
                      };
  
      
Get the file extension from a path
parameter: path
returns: {*}

  
      enchant.Core.findExt = function(path) {
          var matched = path.match(/\.\w+/);
          if (matched && matched.length > 0) {
              return matched[0].slice(1).toLowerCase();
          }
  
          // for data URI
          if (path.indexOf('data:') === 0) {
              return path.split(/[\/;]/)[1].toLowerCase();
          }
          return null;
      };
  
      
The Current Core instance. @type {enchant.Core} @static

  
      enchant.Core.instance = null;
  }());
  
  
enchant.Core is moved to enchant.Core from v0.6 @type {*}

  
  enchant.Game = enchant.Core;
  
@scope enchant.Node.prototype

  
  enchant.Node = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.Node @class Base class for objects in the display tree which is rooted at a Scene. Not to be used directly. @constructs @extends enchant.EventTarget

  
      initialize: function() {
          enchant.EventTarget.call(this);
  
          this._dirty = false;
  
          this._matrix = [ 1, 0, 0, 1, 0, 0 ];
  
          this._x = 0;
          this._y = 0;
          this._offsetX = 0;
          this._offsetY = 0;
  
          
The age (frames) of this node which will be increased before this node receives {gray enchant.Event.ENTER_FRAME} event. @type {Number}

  
          this.age = 0;
  
          
Parent Node of this Node. @type {enchant.Group}

  
          this.parentNode = null;
          
Scene to which Node belongs. @type {enchant.Scene}

  
          this.scene = null;
  
          this.addEventListener('touchstart', function(e) {
              if (this.parentNode) {
                  this.parentNode.dispatchEvent(e);
              }
          });
          this.addEventListener('touchmove', function(e) {
              if (this.parentNode) {
                  this.parentNode.dispatchEvent(e);
              }
          });
          this.addEventListener('touchend', function(e) {
              if (this.parentNode) {
                  this.parentNode.dispatchEvent(e);
              }
          });
  
          

  
          if(enchant.ENV.USE_ANIMATION){
              var tl = this.tl = new enchant.Timeline(this);
          }
      },
      
Move the Node to the given target location.
parameter: {Number} x Target x coordinates.
parameter: {Number} y Target y coordinates.

  
      moveTo: function(x, y) {
          this._x = x;
          this._y = y;
          this._dirty = true;
      },
      
Move the Node relative to its current position.
parameter: {Number} x x axis movement distance.
parameter: {Number} y y axis movement distance.

  
      moveBy: function(x, y) {
          this._x += x;
          this._y += y;
          this._dirty = true;
      },
      
x coordinates of the Node. @type {Number}

  
      x: {
          get: function() {
              return this._x;
          },
          set: function(x) {
              this._x = x;
              this._dirty = true;
          }
      },
      
y coordinates of the Node. @type {Number}

  
      y: {
          get: function() {
              return this._y;
          },
          set: function(y) {
              this._y = y;
              this._dirty = true;
          }
      },
      _updateCoordinate: function() {
          var node = this;
          var tree = [ node ];
          var parent = node.parentNode;
          var scene = this.scene;
          while (parent && node._dirty) {
              tree.unshift(parent);
              node = node.parentNode;
              parent = node.parentNode;
          }
          var matrix = enchant.Matrix.instance;
          var stack = matrix.stack;
          var mat = [];
          var newmat, ox, oy;
          stack.push(tree[0]._matrix);
          for (var i = 1, l = tree.length; i < l; i++) {
              node = tree[i];
              newmat = [];
              matrix.makeTransformMatrix(node, mat);
              matrix.multiply(stack[stack.length - 1], mat, newmat);
              node._matrix = newmat;
              stack.push(newmat);
              ox = (typeof node._originX === 'number') ? node._originX : node._width / 2 || 0;
              oy = (typeof node._originY === 'number') ? node._originY : node._height / 2 || 0;
              var vec = [ ox, oy ];
              matrix.multiplyVec(newmat, vec, vec);
              node._offsetX = vec[0] - ox;
              node._offsetY = vec[1] - oy;
              node._dirty = false;
          }
          matrix.reset();
      },
      remove: function() {
          if (this._listener) {
              this.clearEventListener();
          }
          if (this.parentNode) {
              this.parentNode.removeChild(this);
          }
      }
  });
  
  var _intersectBetweenClassAndInstance = function(Class, instance) {
      var ret = [];
      var c;
      for (var i = 0, l = Class.collection.length; i < l; i++) {
          c = Class.collection[i];
          if (instance._intersectOne(c)) {
              ret.push(c);
          }
      }
      return ret;
  };
  
  var _intersectBetweenClassAndClass = function(Class1, Class2) {
      var ret = [];
      var c1, c2;
      for (var i = 0, l = Class1.collection.length; i < l; i++) {
          c1 = Class1.collection[i];
          for (var j = 0, ll = Class2.collection.length; j < ll; j++) {
              c2 = Class2.collection[j];
              if (c1._intersectOne(c2)) {
                  ret.push([ c1, c2 ]);
              }
          }
      }
      return ret;
  };
  
  var _intersectStrictBetweenClassAndInstance = function(Class, instance) {
      var ret = [];
      var c;
      for (var i = 0, l = Class.collection.length; i < l; i++) {
          c = Class.collection[i];
          if (instance._intersectStrictOne(c)) {
              ret.push(c);
          }
      }
      return ret;
  };
  
  var _intersectStrictBetweenClassAndClass = function(Class1, Class2) {
      var ret = [];
      var c1, c2;
      for (var i = 0, l = Class1.collection.length; i < l; i++) {
          c1 = Class1.collection[i];
          for (var j = 0, ll = Class2.collection.length; j < ll; j++) {
              c2 = Class2.collection[j];
              if (c1._intersectStrictOne(c2)) {
                  ret.push([ c1, c2 ]);
              }
          }
      }
      return ret;
  };
  
  var _staticIntersect = function(other) {
      if (other instanceof enchant.Entity) {
          return _intersectBetweenClassAndInstance(this, other);
      } else if (typeof other === 'function' && other.collection) {
          return _intersectBetweenClassAndClass(this, other);
      }
      return false;
  };
  
  var _staticIntersectStrict = function(other) {
      if (other instanceof enchant.Entity) {
          return _intersectStrictBetweenClassAndInstance(this, other);
      } else if (typeof other === 'function' && other.collection) {
          return _intersectStrictBetweenClassAndClass(this, other);
      }
      return false;
  };
  
  
@scope enchant.Entity.prototype

  
  enchant.Entity = enchant.Class.create(enchant.Node, {
      
@name enchant.Entity @class A class with objects displayed as DOM elements. Not to be used directly. @constructs @extends enchant.Node

  
      initialize: function() {
          var core = enchant.Core.instance;
          enchant.Node.call(this);
  
          this._rotation = 0;
          this._scaleX = 1;
          this._scaleY = 1;
  
          this._touchEnabled = true;
          this._clipping = false;
  
          this._originX = null;
          this._originY = null;
  
          this._width = 0;
          this._height = 0;
          this._backgroundColor = null;
          this._opacity = 1;
          this._visible = true;
          this._buttonMode = null;
  
          this._style = {};
          this.__styleStatus = {};
  
          

  
          this.compositeOperation = null;
  
          
Defines this Entity as a button. When touched or clicked the corresponding button event is dispatched. Valid buttonModes are: left, right, up, down, a, b. @type {String}

  
          this.buttonMode = null;
          
Indicates if this Entity is being clicked. Only works when {gray enchant.Entity.buttonMode} is set. @type {Boolean}

  
          this.buttonPressed = false;
          this.addEventListener('touchstart', function() {
              if (!this.buttonMode) {
                  return;
              }
              this.buttonPressed = true;
              var e = new enchant.Event(this.buttonMode + 'buttondown');
              this.dispatchEvent(e);
              core.dispatchEvent(e);
          });
          this.addEventListener('touchend', function() {
              if (!this.buttonMode) {
                  return;
              }
              this.buttonPressed = false;
              var e = new enchant.Event(this.buttonMode + 'buttonup');
              this.dispatchEvent(e);
              core.dispatchEvent(e);
          });
  
          this.enableCollection();
      },
      
The width of the Entity. @type {Number}

  
      width: {
          get: function() {
              return this._width;
          },
          set: function(width) {
              this._width = width;
              this._dirty = true;
          }
      },
      
The height of the Entity. @type {Number}

  
      height: {
          get: function() {
              return this._height;
          },
          set: function(height) {
              this._height = height;
              this._dirty = true;
          }
      },
      
The Entity background color. Must be provided in the same format as the CSS 'color' property. @type {String}

  
      backgroundColor: {
          get: function() {
              return this._backgroundColor;
          },
          set: function(color) {
              this._backgroundColor = color;
          }
      },
      
The transparency of this entity. Defines the transparency level from 0 to 1 (0 is completely transparent, 1 is completely opaque). @type {Number}

  
      opacity: {
          get: function() {
              return this._opacity;
          },
          set: function(opacity) {
              this._opacity = parseFloat(opacity);
          }
      },
      
Indicates whether or not to display this Entity. @type {Boolean}

  
      visible: {
          get: function() {
              return this._visible;
          },
          set: function(visible) {
              this._visible = visible;
          }
      },
      
Indicates whether or not this Entity can be touched. @type {Boolean}

  
      touchEnabled: {
          get: function() {
              return this._touchEnabled;
          },
          set: function(enabled) {
              this._touchEnabled = enabled;
              if (enabled) {
                  this._style.pointerEvents = 'all';
              } else {
                  this._style.pointerEvents = 'none';
              }
          }
      },
      
Performs a collision detection based on whether or not the bounding rectangles are intersecting.
parameter: {*} other An object like Entity, with the properties x, y, width, height, which are used for the collision detection.
returns: {Boolean} True, if a collision was detected.

  
      intersect: function(other) {
          if (other instanceof enchant.Entity) {
              return this._intersectOne(other);
          } else if (typeof other === 'function' && other.collection) {
              return _intersectBetweenClassAndInstance(other, this);
          }
          return false;
      },
      _intersectOne: function(other) {
          if (this._dirty) {
              this._updateCoordinate();
          } if (other._dirty) {
              other._updateCoordinate();
          }
          return this._offsetX < other._offsetX + other.width && other._offsetX < this._offsetX + this.width &&
              this._offsetY < other._offsetY + other.height && other._offsetY < this._offsetY + this.height;
      },
      intersectStrict: function(other) {
          if (other instanceof enchant.Entity) {
              return this._intersectStrictOne(other);
          } else if (typeof other === 'function' && other.collection) {
              return _intersectStrictBetweenClassAndInstance(other, this);
          }
          return false;
      },
      _intersectStrictOne: function(other) {
          if (this._dirty) {
              this._updateCoordinate();
          } if (other._dirty) {
              other._updateCoordinate();
          }
          var rect1 = this.getOrientedBoundingRect(),
              rect2 = other.getOrientedBoundingRect(),
              lt1 = rect1.leftTop, rt1 = rect1.rightTop,
              lb1 = rect1.leftBottom, rb1 = rect1.rightBottom,
              lt2 = rect2.leftTop, rt2 = rect2.rightTop,
              lb2 = rect2.leftBottom, rb2 = rect2.rightBottom,
              ltx1 = lt1[0], lty1 = lt1[1], rtx1 = rt1[0], rty1 = rt1[1],
              lbx1 = lb1[0], lby1 = lb1[1], rbx1 = rb1[0], rby1 = rb1[1],
              ltx2 = lt2[0], lty2 = lt2[1], rtx2 = rt2[0], rty2 = rt2[1],
              lbx2 = lb2[0], lby2 = lb2[1], rbx2 = rb2[0], rby2 = rb2[1],
              t1 = [ rtx1 - ltx1, rty1 - lty1 ],
              r1 = [ rbx1 - rtx1, rby1 - rty1 ],
              b1 = [ lbx1 - rbx1, lby1 - rby1 ],
              l1 = [ ltx1 - lbx1, lty1 - lby1 ],
              t2 = [ rtx2 - ltx2, rty2 - lty2 ],
              r2 = [ rbx2 - rtx2, rby2 - rty2 ],
              b2 = [ lbx2 - rbx2, lby2 - rby2 ],
              l2 = [ ltx2 - lbx2, lty2 - lby2 ],
              cx1 = (ltx1 + rtx1 + lbx1 + rbx1) >> 2,
              cy1 = (lty1 + rty1 + lby1 + rby1) >> 2,
              cx2 = (ltx2 + rtx2 + lbx2 + rbx2) >> 2,
              cy2 = (lty2 + rty2 + lby2 + rby2) >> 2,
              i, j, poss1, poss2, dirs1, dirs2, pos1, pos2, dir1, dir2,
              px1, py1, px2, py2, dx1, dy1, dx2, dy2, vx, vy, c, c1, c2;
          if (t1[0] * (cy2 - lty1) - t1[1] * (cx2 - ltx1) > 0 &&
              r1[0] * (cy2 - rty1) - r1[1] * (cx2 - rtx1) > 0 &&
              b1[0] * (cy2 - rby1) - b1[1] * (cx2 - rbx1) > 0 &&
              l1[0] * (cy2 - lby1) - l1[1] * (cx2 - lbx1) > 0) {
              return true;
          } else if (t2[0] * (cy1 - lty2) - t2[1] * (cx1 - ltx2) > 0 &&
              r2[0] * (cy1 - rty2) - r2[1] * (cx1 - rtx2) > 0 &&
              b2[0] * (cy1 - rby2) - b2[1] * (cx1 - rbx2) > 0 &&
              l2[0] * (cy1 - lby2) - l2[1] * (cx1 - lbx2) > 0) {
              return true;
          } else {
              poss1 = [ lt1, rt1, rb1, lb1 ];
              poss2 = [ lt2, rt2, rb2, lb2 ];
              dirs1 = [ t1, r1, b1, l1 ];
              dirs2 = [ t2, r2, b2, l2 ];
              for (i = 0; i < 4; i++) {
                  pos1 = poss1[i];
                  px1 = pos1[0]; py1 = pos1[1];
                  dir1 = dirs1[i];
                  dx1 = dir1[0]; dy1 = dir1[1];
                  for (j = 0; j < 4; j++) {
                      pos2 = poss2[j];
                      px2 = pos2[0]; py2 = pos2[1];
                      dir2 = dirs2[j];
                      dx2 = dir2[0]; dy2 = dir2[1];
                      c = dx1 * dy2 - dy1 * dx2;
                      if (c !== 0) {
                          vx = px2 - px1;
                          vy = py2 - py1;
                          c1 = (vx * dy1 - vy * dx1) / c;
                          c2 = (vx * dy2 - vy * dx2) / c;
                          if (0 < c1 && c1 < 1 && 0 < c2 && c2 < 1) {
                              return true;
                          }
                      }
                  }
              }
              return false;
          }
      },
      
Performs a collision detection based on distance from the Entity's central point.
parameter: {*} other An object like Entity, with properties x, y, width, height, which are used for the collision detection.
parameter: {Number} [distance] The greatest distance to be considered for a collision. The default distance is the average of both objects width and height.
returns: {Boolean} True, if a collision was detected.

  
      within: function(other, distance) {
          if (this._dirty) {
              this._updateCoordinate();
          } if (other._dirty) {
              other._updateCoordinate();
          }
          if (distance == null) {
              distance = (this.width + this.height + other.width + other.height) / 4;
          }
          var _;
          return (_ = this._offsetX - other._offsetX + (this.width - other.width) / 2) * _ +
              (_ = this._offsetY - other._offsetY + (this.height - other.height) / 2) * _ < distance * distance;
      }, 
Enlarges or shrinks this Sprite.
parameter: {Number} x Scaling factor on the x axis.
parameter: {Number} [y] Scaling factor on the y axis.

  
      scale: function(x, y) {
          this._scaleX *= x;
          this._scaleY *= (y != null) ? y : x;
          this._dirty = true;
      },
      
Rotate this Sprite.
parameter: {Number} deg Rotation angle (degree).

  
      rotate: function(deg) {
          this._rotation += deg;
          this._dirty = true;
      },
      
Scaling factor on the x axis of this Sprite. @type {Number}

  
      scaleX: {
          get: function() {
              return this._scaleX;
          },
          set: function(scaleX) {
              this._scaleX = scaleX;
              this._dirty = true;
          }
      },
      
Scaling factor on the y axis of this Sprite. @type {Number}

  
      scaleY: {
          get: function() {
              return this._scaleY;
          },
          set: function(scaleY) {
              this._scaleY = scaleY;
              this._dirty = true;
          }
      },
      
Sprite rotation angle (degree). @type {Number}

  
      rotation: {
          get: function() {
              return this._rotation;
          },
          set: function(rotation) {
              this._rotation = rotation;
              this._dirty = true;
          }
      },
      
The point of origin used for rotation and scaling. @type {Number}

  
      originX: {
          get: function() {
              return this._originX;
          },
          set: function(originX) {
              this._originX = originX;
              this._dirty = true;
          }
      },
      
The point of origin used for rotation and scaling. @type {Number}

  
      originY: {
          get: function() {
              return this._originY;
          },
          set: function(originY) {
              this._originY = originY;
              this._dirty = true;
          }
      },
      

  
      enableCollection: function() {
          this.addEventListener('addedtoscene', this._addSelfToCollection);
          this.addEventListener('removedfromscene', this._removeSelfFromCollection);
          if (this.scene) {
              this._addSelfToCollection();
          }
      },
      

  
      disableCollection: function() {
          this.removeEventListener('addedtoscene', this._addSelfToCollection);
          this.removeEventListener('removedfromscene', this._removeSelfFromCollection);
          if (this.scene) {
              this._removeSelfFromCollection();
          }
      },
      _addSelfToCollection: function() {
          var Constructor = this.getConstructor();
          Constructor._collectionTarget.forEach(function(C) {
              C.collection.push(this);
          }, this);
      },
      _removeSelfFromCollection: function() {
          var Constructor = this.getConstructor();
          Constructor._collectionTarget.forEach(function(C) {
              var i = C.collection.indexOf(this);
              if (i !== -1) {
                  C.collection.splice(i, 1);
              }
          }, this);
      },
      getBoundingRect: function() {
          var w = this.width || 0;
          var h = this.height || 0;
          var mat = this._matrix;
          var m11w = mat[0] * w, m12w = mat[1] * w,
              m21h = mat[2] * h, m22h = mat[3] * h,
              mdx = mat[4], mdy = mat[5];
          var xw = [ mdx, m11w + mdx, m21h + mdx, m11w + m21h + mdx ].sort(function(a, b) { return a - b; });
          var yh = [ mdy, m12w + mdy, m22h + mdy, m12w + m22h + mdy ].sort(function(a, b) { return a - b; });
  
          return {
              left: xw[0],
              top: yh[0],
              width: xw[3] - xw[0],
              height: yh[3] - yh[0]
          };
      },
      getOrientedBoundingRect: function() {
          var w = this.width || 0;
          var h = this.height || 0;
          var mat = this._matrix;
          var m11w = mat[0] * w, m12w = mat[1] * w,
              m21h = mat[2] * h, m22h = mat[3] * h,
              mdx = mat[4], mdy = mat[5];
  
          return {
              leftTop: [ mdx, mdy ],
              rightTop: [ m11w + mdx, m12w + mdy ],
              leftBottom: [ m21h + mdx, m22h + mdy ],
              rightBottom: [ m11w + m21h + mdx, m12w + m22h + mdy ]
          };
      },
      getConstructor: function() {
          return Object.getPrototypeOf(this).constructor;
      }
  });
  
  var _collectizeConstructor = function(Constructor) {
      if (Constructor._collective) {
          return;
      }
      var rel = enchant.Class.getInheritanceTree(Constructor);
      var i = rel.indexOf(enchant.Entity);
      if (i !== -1) {
          Constructor._collectionTarget = rel.splice(0, i + 1);
      } else {
          Constructor._collectionTarget = [];
      }
      Constructor.intersect = _staticIntersect;
      Constructor.intersectStrict = _staticIntersectStrict;
      Constructor.collection = [];
      Constructor._collective = true;
  };
  
  _collectizeConstructor(enchant.Entity);
  
  enchant.Entity._inherited = function(subclass) {
      _collectizeConstructor(subclass);
  };
  
  
@scope enchant.Sprite.prototype

  
  enchant.Sprite = enchant.Class.create(enchant.Entity, {
      
@name enchant.Sprite @class Class which can display images.
parameter: {Number} [width] Sprite width.
parameter: {Number} [height] Sprite height. @example var bear = new Sprite(32, 32); bear.image = core.assets['chara1.gif']; @constructs @extends enchant.Entity

  
      initialize: function(width, height) {
          enchant.Entity.call(this);
  
          this.width = width;
          this.height = height;
          this._image = null;
          this._frameLeft = 0;
          this._frameTop = 0;
          this._frame = 0;
          this._frameSequence = [];
          

  
          this.addEventListener('enterframe', function() {
              if (this._frameSequence.length !== 0) {
                  var nextFrame = this._frameSequence.shift();
                  if (nextFrame === null) {
                      this._frameSequence = [];
                  } else {
                      this._setFrame(nextFrame);
                      this._frameSequence.push(nextFrame);
                  }
              }
          });
      },
      
Image displayed in the Sprite. @type {enchant.Surface}

  
      image: {
          get: function() {
              return this._image;
          },
          set: function(image) {
              if (image === this._image) {
                  return;
              }
              this._image = image;
              this._setFrame(this._frame);
          }
      },
      
Indizes of the frames to be displayed. Frames with same width and height as Sprite will be arrayed from upper left corner of the {gray enchant.Sprite#image} image. When a sequence of numbers is provided, the displayed frame will switch automatically. At the end of the array the sequence will restart. By setting a value within the sequence to null, the frame switching is stopped. @example var sprite = new Sprite(32, 32); sprite.frame = [0, 1, 0, 2] //-> 0, 1, 0, 2, 0, 1, 0, 2,.. sprite.frame = [0, 1, 0, 2, null] //-> 0, 1, 0, 2, (2, 2,.. :stop) @type {Number|Array}

  
      frame: {
          get: function() {
              return this._frame;
          },
          set: function(frame) {
              if(this._frame === frame) {
                  return;
              }
              if (frame instanceof Array) {
                  var frameSequence = frame;
                  var nextFrame = frameSequence.shift();
                  this._setFrame(nextFrame);
                  frameSequence.push(nextFrame);
                  this._frameSequence = frameSequence;
              } else {
                  this._setFrame(frame);
                  this._frameSequence = [];
                  this._frame = frame;
              }
          }
      },
      
0 <= frame
parameter: frame @private

  
      _setFrame: function(frame) {
          var image = this._image;
          var row, col;
          if (image != null) {
              this._frame = frame;
              row = image.width / this._width | 0;
              this._frameLeft = (frame % row | 0) * this._width;
              this._frameTop = (frame / row | 0) * this._height % image.height;
          }
      },
      
width of Sprite @type {Number}

  
      width: {
          get: function() {
              return this._width;
          },
          set: function(width) {
              this._width = width;
              this._setFrame();
              this._dirty = true;
          }
      },
      
height of Sprite @type {Number}

  
      height: {
          get: function() {
              return this._height;
          },
          set: function(height) {
              this._height = height;
              this._setFrame();
              this._dirty = true;
          }
      },
      cvsRender: function(ctx) {
          var image = this._image,
              w = this._width, h = this._height,
              iw, ih, elem, sx, sy, sw, sh;
          if (image && w !== 0 && h !== 0) {
              iw = image.width, ih = image.height;
              if (iw < w || ih < h) {
                  ctx.fillStyle = enchant.Surface._getPattern(image);
                  ctx.fillRect(0, 0, w, h);
              } else {
                  elem = image._element;
                  sx = this._frameLeft;
                  sy = Math.min(this._frameTop, ih - h);
                  sw = Math.min(iw - sx, w);
                  sh = Math.min(ih - sy, h);
                  ctx.drawImage(elem, sx, sy, sw, sh, 0, 0, w, h);
              }
          }
      },
      domRender: (function() {
          if (enchant.ENV.VENDOR_PREFIX === 'ms') {
              return function(element) {
                  if (this._image) {
                      if (this._image._css) {
                          this._style['background-image'] = this._image._css;
                          this._style['background-position'] =
                              -this._frameLeft + 'px ' +
                              -this._frameTop + 'px';
                      } else if (this._image._element) {
                      }
                  }
              };
          } else {
              return function(element) {
                  if (this._image) {
                      if (this._image._css) {
                          this._style['background-image'] = this._image._css;
                          this._style['background-position'] =
                              -this._frameLeft + 'px ' +
                              -this._frameTop + 'px';
                      } else if (this._image._element) {
                      }
                  }
              };
          }
      }())
  });
  
  
@scope enchant.Label.prototype

  
  enchant.Label = enchant.Class.create(enchant.Entity, {
      
@name enchant.Label @class A class for Label object. @constructs @extends enchant.Entity

  
      initialize: function(text) {
          enchant.Entity.call(this);
  
          this.text = text || '';
          this.width = 300;
          this.font = '14px serif';
          this.textAlign = 'left';
      },
      width: {
          get: function() {
              return this._width;
          },
          set: function(width) {
              this._width = width;
              this._dirty = true;
              // issue #164
              this.updateBoundArea();
          }
      },
      
Text to be displayed. @type {String}

  
      text: {
          get: function() {
              return this._text;
          },
          set: function(text) {
              text = '' + text;
              if(this._text === text) {
                  return;
              }
              this._text = text;
              text = text.replace(/<(br|BR) ?\/?>/g, '<br/>');
              this._splitText = text.split('<br/>');
              this.updateBoundArea();
              for (var i = 0, l = this._splitText.length; i < l; i++) {
                  text = this._splitText[i];
                  var metrics = this.getMetrics(text);
                  this._splitText[i] = {};
                  this._splitText[i].text = text;
                  this._splitText[i].height = metrics.height;
              }
          }
      },
      
Specifies horizontal alignment of text. Can be set according to the format of the CSS 'text-align' property. @type {String}

  
      textAlign: {
          get: function() {
              return this._style['text-align'];
          },
          set: function(textAlign) {
              this._style['text-align'] = textAlign;
              this.updateBoundArea();
          }
      },
      
Font settings. Can be set according to the format of the CSS 'font' property. @type {String}

  
      font: {
          get: function() {
              return this._style.font;
          },
          set: function(font) {
              this._style.font = font;
              this.updateBoundArea();
          }
      },
      
Text color settings. Can be set according to the format of the CSS 'color' property. @type {String}

  
      color: {
          get: function() {
              return this._style.color;
          },
          set: function(color) {
              this._style.color = color;
          }
      },
      cvsRender: function(ctx) {
          var x, y = 0;
          var labelWidth = this.width;
          var charWidth, amount, line, text, c, buf, increase, length;
          var bufWidth;
          if (this._splitText) {
              ctx.textBaseline = 'top';
              ctx.font = this.font;
              ctx.fillStyle = this.color || '#000000';
              charWidth = ctx.measureText(' ').width;
              amount = labelWidth / charWidth;
              for (var i = 0, l = this._splitText.length; i < l; i++) {
                  line = this._splitText[i];
                  text = line.text;
                  c = 0;
                  while (text.length > c + amount || ctx.measureText(text.slice(c, c + amount)).width > labelWidth) {
                      buf = '';
                      increase = amount;
                      length = 0;
                      while (increase > 0) {
                          if (ctx.measureText(buf).width < labelWidth) {
                              length += increase;
                              buf = text.slice(c, c + length);
                          } else {
                              length -= increase;
                              buf = text.slice(c, c + length);
                          }
                          increase = increase / 2 | 0;
                      }
                      ctx.fillText(buf, 0, y);
                      y += line.height - 1;
                      c += length;
                  }
                  buf = text.slice(c, c + text.length);
                  if (this.textAlign === 'right') {
                      x = labelWidth - ctx.measureText(buf).width;
                  } else if (this.textAlign === 'center') {
                      x = (labelWidth - ctx.measureText(buf).width) / 2;
                  } else {
                      x = 0;
                  }
                  ctx.fillText(buf, x, y);
                  y += line.height - 1;
              }
          }
      },
      domRender: function(element) {
          if (element.innerHTML !== this._text) {
              element.innerHTML = this._text;
          }
      },
      detectRender: function(ctx) {
          ctx.fillRect(this._boundOffset, 0, this._boundWidth, this._boundHeight);
      },
      updateBoundArea: function() {
          var metrics = this.getMetrics();
          this._boundWidth = metrics.width;
          this._boundHeight = metrics.height;
          if (this.textAlign === 'right') {
              this._boundOffset = this.width - this._boundWidth;
          } else if (this.textAlign === 'center') {
              this._boundOffset = (this.width - this._boundWidth) / 2;
          } else {
              this._boundOffset = 0;
          }
      }
  });
  
  enchant.Label.prototype.getMetrics = function(text) {
      var ret = {};
      var div, width, height;
      if (document.body) {
          div = document.createElement('div');
          for (var prop in this._style) {
              if(prop !== 'width' && prop !== 'height') {
                  div.style[prop] = this._style[prop];
              }
          }
          text = text || this._text;
          div.innerHTML = text.replace(/ /g, '&nbsp;');
          div.style.whiteSpace = 'noWrap';
          document.body.appendChild(div);
          ret.height = parseInt(getComputedStyle(div).height, 10) + 1;
          div.style.position = 'absolute';
          ret.width = parseInt(getComputedStyle(div).width, 10) + 1;
          document.body.removeChild(div);
      } else {
          ret.width = this.width;
          ret.height = this.height;
      }
      return ret;
  };
  
  
@scope enchant.Map.prototype

  
  enchant.Map = enchant.Class.create(enchant.Entity, {
      
@name enchant.Map @class A class to create and display maps from a tile set.
parameter: {Number} tileWidth Tile width.
parameter: {Number} tileHeight Tile height. @constructs @extends enchant.Entity

  
      initialize: function(tileWidth, tileHeight) {
          var core = enchant.Core.instance;
  
          enchant.Entity.call(this);
  
          var surface = new enchant.Surface(core.width, core.height);
          this._surface = surface;
          var canvas = surface._element;
          canvas.style.position = 'absolute';
          if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) {
              canvas.width = core.width * 2;
              canvas.height = core.height * 2;
              this._style.webkitTransformOrigin = '0 0';
              this._style.webkitTransform = 'scale(0.5)';
          } else {
              canvas.width = core.width;
              canvas.height = core.height;
          }
          this._context = canvas.getContext('2d');
  
          this._tileWidth = tileWidth || 0;
          this._tileHeight = tileHeight || 0;
          this._image = null;
          this._data = [
              [
                  []
              ]
          ];
          this._dirty = false;
          this._tight = false;
  
          this.touchEnabled = false;
  
          
Two dimensional array to store if collision detection should be performed for a tile. @type {Array.<Array.<Number>>}

  
          this.collisionData = null;
  
          this._listeners['render'] = null;
          this.addEventListener('render', function() {
              if (this._dirty || this._previousOffsetX == null) {
                  this.redraw(0, 0, core.width, core.height);
              } else if (this._offsetX !== this._previousOffsetX ||
                  this._offsetY !== this._previousOffsetY) {
                  if (this._tight) {
                      var x = -this._offsetX;
                      var y = -this._offsetY;
                      var px = -this._previousOffsetX;
                      var py = -this._previousOffsetY;
                      var w1 = x - px + core.width;
                      var w2 = px - x + core.width;
                      var h1 = y - py + core.height;
                      var h2 = py - y + core.height;
                      if (w1 > this._tileWidth && w2 > this._tileWidth &&
                          h1 > this._tileHeight && h2 > this._tileHeight) {
                          var sx, sy, dx, dy, sw, sh;
                          if (w1 < w2) {
                              sx = 0;
                              dx = px - x;
                              sw = w1;
                          } else {
                              sx = x - px;
                              dx = 0;
                              sw = w2;
                          }
                          if (h1 < h2) {
                              sy = 0;
                              dy = py - y;
                              sh = h1;
                          } else {
                              sy = y - py;
                              dy = 0;
                              sh = h2;
                          }
  
                          if (core._buffer == null) {
                              core._buffer = document.createElement('canvas');
                              core._buffer.width = this._context.canvas.width;
                              core._buffer.height = this._context.canvas.height;
                          }
                          var context = core._buffer.getContext('2d');
                          if (this._doubledImage) {
                              context.clearRect(0, 0, sw * 2, sh * 2);
                              context.drawImage(this._context.canvas,
                                  sx * 2, sy * 2, sw * 2, sh * 2, 0, 0, sw * 2, sh * 2);
                              context = this._context;
                              context.clearRect(dx * 2, dy * 2, sw * 2, sh * 2);
                              context.drawImage(core._buffer,
                                  0, 0, sw * 2, sh * 2, dx * 2, dy * 2, sw * 2, sh * 2);
                          } else {
                              context.clearRect(0, 0, sw, sh);
                              context.drawImage(this._context.canvas,
                                  sx, sy, sw, sh, 0, 0, sw, sh);
                              context = this._context;
                              context.clearRect(dx, dy, sw, sh);
                              context.drawImage(core._buffer,
                                  0, 0, sw, sh, dx, dy, sw, sh);
                          }
  
                          if (dx === 0) {
                              this.redraw(sw, 0, core.width - sw, core.height);
                          } else {
                              this.redraw(0, 0, core.width - sw, core.height);
                          }
                          if (dy === 0) {
                              this.redraw(0, sh, core.width, core.height - sh);
                          } else {
                              this.redraw(0, 0, core.width, core.height - sh);
                          }
                      } else {
                          this.redraw(0, 0, core.width, core.height);
                      }
                  } else {
                      this.redraw(0, 0, core.width, core.height);
                  }
              }
              this._previousOffsetX = this._offsetX;
              this._previousOffsetY = this._offsetY;
          });
      },
      
Set map data. Sets the tile data, whereas the data (two-dimensional array with indizes starting from 0) is mapped on the image starting from the upper left corner. When more than one map data array is set, they are displayed in reverse order.
parameter: {...Array>} data Two-dimensional array of tile indizes. Multiple designations possible.

  
      loadData: function(data) {
          this._data = Array.prototype.slice.apply(arguments);
          this._dirty = true;
  
          this._tight = false;
          for (var i = 0, len = this._data.length; i < len; i++) {
              var c = 0;
              data = this._data[i];
              for (var y = 0, l = data.length; y < l; y++) {
                  for (var x = 0, ll = data[y].length; x < ll; x++) {
                      if (data[y][x] >= 0) {
                          c++;
                      }
                  }
              }
              if (c / (data.length * data[0].length) > 0.2) {
                  this._tight = true;
                  break;
              }
          }
      },
      
Checks what tile is present at the given position.
parameter: {Number} x x coordinates of the point on the map.
parameter: {Number} y y coordinates of the point on the map.
returns: {*} The tile data for the given position.

  
      checkTile: function(x, y) {
          if (x < 0 || this.width <= x || y < 0 || this.height <= y) {
              return false;
          }
          var width = this._image.width;
          var height = this._image.height;
          var tileWidth = this._tileWidth || width;
          var tileHeight = this._tileHeight || height;
          x = x / tileWidth | 0;
          y = y / tileHeight | 0;
          //                return this._data[y][x];
          var data = this._data[0];
          return data[y][x];
      },
      
Judges whether or not obstacles are on top of Map.
parameter: {Number} x x coordinates of detection spot on map.
parameter: {Number} y y coordinates of detection spot on map.
returns: {Boolean} True, if there are obstacles.

  
      hitTest: function(x, y) {
          if (x < 0 || this.width <= x || y < 0 || this.height <= y) {
              return false;
          }
          var width = this._image.width;
          var height = this._image.height;
          var tileWidth = this._tileWidth || width;
          var tileHeight = this._tileHeight || height;
          x = x / tileWidth | 0;
          y = y / tileHeight | 0;
          if (this.collisionData != null) {
              return this.collisionData[y] && !!this.collisionData[y][x];
          } else {
              for (var i = 0, len = this._data.length; i < len; i++) {
                  var data = this._data[i];
                  var n;
                  if (data[y] != null && (n = data[y][x]) != null &&
                      0 <= n && n < (width / tileWidth | 0) * (height / tileHeight | 0)) {
                      return true;
                  }
              }
              return false;
          }
      },
      
Image with which the tile set is displayed on the map. @type {enchant.Surface}

  
      image: {
          get: function() {
              return this._image;
          },
          set: function(image) {
              var core = enchant.Core.instance;
  
              this._image = image;
              if (enchant.ENV.RETINA_DISPLAY && core.scale === 2) {
                  var img = new enchant.Surface(image.width * 2, image.height * 2);
                  var tileWidth = this._tileWidth || image.width;
                  var tileHeight = this._tileHeight || image.height;
                  var row = image.width / tileWidth | 0;
                  var col = image.height / tileHeight | 0;
                  for (var y = 0; y < col; y++) {
                      for (var x = 0; x < row; x++) {
                          img.draw(image, x * tileWidth, y * tileHeight, tileWidth, tileHeight,
                              x * tileWidth * 2, y * tileHeight * 2, tileWidth * 2, tileHeight * 2);
                      }
                  }
                  this._doubledImage = img;
              }
              this._dirty = true;
          }
      },
      
Map tile width. @type {Number}

  
      tileWidth: {
          get: function() {
              return this._tileWidth;
          },
          set: function(tileWidth) {
              this._tileWidth = tileWidth;
              this._dirty = true;
          }
      },
      
Map tile height. @type {Number}

  
      tileHeight: {
          get: function() {
              return this._tileHeight;
          },
          set: function(tileHeight) {
              this._tileHeight = tileHeight;
              this._dirty = true;
          }
      },
      
@private

  
      width: {
          get: function() {
              return this._tileWidth * this._data[0][0].length;
          }
      },
      
@private

  
      height: {
          get: function() {
              return this._tileHeight * this._data[0].length;
          }
      },
      
@private

  
      redraw: function(x, y, width, height) {
          if (this._image == null) {
              return;
          }
  
          var image, tileWidth, tileHeight, dx, dy;
          if (this._doubledImage) {
              image = this._doubledImage;
              tileWidth = this._tileWidth * 2;
              tileHeight = this._tileHeight * 2;
              dx = -this._offsetX * 2;
              dy = -this._offsetY * 2;
              x *= 2;
              y *= 2;
              width *= 2;
              height *= 2;
          } else {
              image = this._image;
              tileWidth = this._tileWidth;
              tileHeight = this._tileHeight;
              dx = -this._offsetX;
              dy = -this._offsetY;
          }
          var row = image.width / tileWidth | 0;
          var col = image.height / tileHeight | 0;
          var left = Math.max((x + dx) / tileWidth | 0, 0);
          var top = Math.max((y + dy) / tileHeight | 0, 0);
          var right = Math.ceil((x + dx + width) / tileWidth);
          var bottom = Math.ceil((y + dy + height) / tileHeight);
  
          var source = image._element;
          var context = this._context;
          var canvas = context.canvas;
          context.clearRect(x, y, width, height);
          for (var i = 0, len = this._data.length; i < len; i++) {
              var data = this._data[i];
              var r = Math.min(right, data[0].length);
              var b = Math.min(bottom, data.length);
              for (y = top; y < b; y++) {
                  for (x = left; x < r; x++) {
                      var n = data[y][x];
                      if (0 <= n && n < row * col) {
                          var sx = (n % row) * tileWidth;
                          var sy = (n / row | 0) * tileHeight;
                          context.drawImage(source, sx, sy, tileWidth, tileHeight,
                              x * tileWidth - dx, y * tileHeight - dy, tileWidth, tileHeight);
                      }
                  }
              }
          }
      },
      cvsRender: function(ctx) {
          var core = enchant.Core.instance;
          if (this.width !== 0 && this.height !== 0) {
              ctx.save();
              ctx.setTransform(1, 0, 0, 1, 0, 0);
              var cvs = this._context.canvas;
                  ctx.drawImage(cvs, 0, 0, core.width, core.height);
              ctx.restore();
          }
      },
      domRender: function(element) {
          if (this._image) {
              this._style['background-image'] = this._surface._css;
              // bad performance
              this._style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(1, 0, 0, 1, 0, 0)';
          }
      }
  });
  
  
@scope enchant.Group.prototype

  
  enchant.Group = enchant.Class.create(enchant.Node, {
      
@name enchant.Group @class A class that can hold multiple {gray enchant.Node}. @example var stage = new Group(); stage.addChild(player); stage.addChild(enemy); stage.addChild(map); stage.addEventListener('enterframe', function() { // Moves the entire frame in according to the player's coordinates. if (this.x > 64 - player.x) { this.x = 64 - player.x; } }); @constructs @extends enchant.Node

  
      initialize: function() {
          
Child Nodes. @type {Array.<enchant.Node>}

  
          this.childNodes = [];
  
          enchant.Node.call(this);
  
          this._rotation = 0;
          this._scaleX = 1;
          this._scaleY = 1;
  
          this._originX = null;
          this._originY = null;
  
          this.__dirty = false;
  
          [enchant.Event.ADDED_TO_SCENE, enchant.Event.REMOVED_FROM_SCENE]
              .forEach(function(event) {
                  this.addEventListener(event, function(e) {
                      this.childNodes.forEach(function(child) {
                          child.scene = this.scene;
                          child.dispatchEvent(e);
                      }, this);
                  });
              }, this);
      },
      
Adds a Node to the Group.
parameter: {enchant.Node} node Node to be added.

  
      addChild: function(node) {
          this.childNodes.push(node);
          node.parentNode = this;
          var childAdded = new enchant.Event('childadded');
          childAdded.node = node;
          childAdded.next = null;
          this.dispatchEvent(childAdded);
          node.dispatchEvent(new enchant.Event('added'));
          if (this.scene) {
              node.scene = this.scene;
              var addedToScene = new enchant.Event('addedtoscene');
              node.dispatchEvent(addedToScene);
          }
      },
      
Incorporates Node into Group.
parameter: {enchant.Node} node Node to be incorporated.
parameter: {enchant.Node} reference Node in position before insertion.

  
      insertBefore: function(node, reference) {
          var i = this.childNodes.indexOf(reference);
          if (i !== -1) {
              this.childNodes.splice(i, 0, node);
              node.parentNode = this;
              var childAdded = new enchant.Event('childadded');
              childAdded.node = node;
              childAdded.next = reference;
              this.dispatchEvent(childAdded);
              node.dispatchEvent(new enchant.Event('added'));
              if (this.scene) {
                  node.scene = this.scene;
                  var addedToScene = new enchant.Event('addedtoscene');
                  node.dispatchEvent(addedToScene);
              }
          } else {
              this.addChild(node);
          }
      },
      
Remove a Node from the Group.
parameter: {enchant.Node} node Node to be deleted.

  
      removeChild: function(node) {
          var i;
          if ((i = this.childNodes.indexOf(node)) !== -1) {
              this.childNodes.splice(i, 1);
              node.parentNode = null;
              var childRemoved = new enchant.Event('childremoved');
              childRemoved.node = node;
              this.dispatchEvent(childRemoved);
              node.dispatchEvent(new enchant.Event('removed'));
              if (this.scene) {
                  node.scene = null;
                  var removedFromScene = new enchant.Event('removedfromscene');
                  node.dispatchEvent(removedFromScene);
              }
          }
      },
      
The Node which is the first child. @type {enchant.Node}

  
      firstChild: {
          get: function() {
              return this.childNodes[0];
          }
      },
      
The Node which is the last child. @type {enchant.Node}

  
      lastChild: {
          get: function() {
              return this.childNodes[this.childNodes.length - 1];
          }
      },
      
Group rotation angle (degree). @type {Number}

  
      rotation: {
          get: function() {
              return this._rotation;
          },
          set: function(rotation) {
              this._rotation = rotation;
              this._dirty = true;
          }
      },
      
Scaling factor on the x axis of the Group. @type {Number}
see: enchant.CanvasGroup.originX
see: enchant.CanvasGroup.originY

  
      scaleX: {
          get: function() {
              return this._scaleX;
          },
          set: function(scale) {
              this._scaleX = scale;
              this._dirty = true;
          }
      },
      
Scaling factor on the y axis of the Group. @type {Number}
see: enchant.CanvasGroup.originX
see: enchant.CanvasGroup.originY

  
      scaleY: {
          get: function() {
              return this._scaleY;
          },
          set: function(scale) {
              this._scaleY = scale;
              this._dirty = true;
          }
      },
      
origin point of rotation, scaling @type {Number}

  
      originX: {
          get: function() {
              return this._originX;
          },
          set: function(originX) {
              this._originX = originX;
              this._dirty = true;
          }
      },
      
origin point of rotation, scaling @type {Number}

  
      originY: {
          get: function() {
              return this._originY;
          },
          set: function(originY) {
              this._originY = originY;
              this._dirty = true;
          }
      },
      _dirty: {
          get: function() {
              return this.__dirty;
          },
          set: function(dirty) {
              dirty = !!dirty;
              this.__dirty = dirty;
              if (dirty) {
                  for (var i = 0, l = this.childNodes.length; i < l; i++) {
                      this.childNodes[i]._dirty = true;
                  }
              }
          }
      }
  });
  
  enchant.Matrix = enchant.Class.create({
      initialize: function() {
          if (enchant.Matrix.instance) {
              return enchant.Matrix.instance;
          }
          this.reset();
      },
      reset: function() {
          this.stack = [];
          this.stack.push([ 1, 0, 0, 1, 0, 0 ]);
      },
      makeTransformMatrix: function(node, dest) {
          var x = node._x;
          var y = node._y;
          var width = node.width || 0;
          var height = node.height || 0;
          var rotation = node._rotation || 0;
          var scaleX = (typeof node._scaleX === 'number') ? node._scaleX : 1;
          var scaleY = (typeof node._scaleY === 'number') ? node._scaleY : 1;
          var theta = rotation * Math.PI / 180;
          var tmpcos = Math.cos(theta);
          var tmpsin = Math.sin(theta);
          var w = (typeof node._originX === 'number') ? node._originX : width / 2;
          var h = (typeof node._originY === 'number') ? node._originY : height / 2;
          var a = scaleX * tmpcos;
          var b = scaleX * tmpsin;
          var c = scaleY * tmpsin;
          var d = scaleY * tmpcos;
          dest[0] = a;
          dest[1] = b;
          dest[2] = -c;
          dest[3] = d;
          dest[4] = (-a * w + c * h + x + w);
          dest[5] = (-b * w - d * h + y + h);
      },
      multiply: function(m1, m2, dest) {
          var a11 = m1[0], a21 = m1[2], adx = m1[4],
              a12 = m1[1], a22 = m1[3], ady = m1[5];
          var b11 = m2[0], b21 = m2[2], bdx = m2[4],
              b12 = m2[1], b22 = m2[3], bdy = m2[5];
  
          dest[0] = a11 * b11 + a21 * b12;
          dest[1] = a12 * b11 + a22 * b12;
          dest[2] = a11 * b21 + a21 * b22;
          dest[3] = a12 * b21 + a22 * b22;
          dest[4] = a11 * bdx + a21 * bdy + adx;
          dest[5] = a12 * bdx + a22 * bdy + ady;
      },
      multiplyVec: function(mat, vec, dest) {
          var x = vec[0], y = vec[1];
          var m11 = mat[0], m21 = mat[2], mdx = mat[4],
              m12 = mat[1], m22 = mat[3], mdy = mat[5];
          dest[0] = m11 * x + m21 * y + mdx;
          dest[1] = m12 * x + m22 * y + mdy;
      }
  });
  enchant.Matrix.instance = new enchant.Matrix();
  
  enchant.DetectColorManager = enchant.Class.create({
      initialize: function(reso, max) {
          this.reference = [];
          this.colorResolution = reso || 16;
          this.max = max || 1;
          this.capacity = Math.pow(this.colorResolution, 3);
          for (var i = 1, l = this.capacity; i < l; i++) {
              this.reference[i] = null;
          }
      },
      attachDetectColor: function(sprite) {
          var i = this.reference.indexOf(null);
          if (i === -1) {
              i = 1;
          }
          this.reference[i] = sprite;
          return this._getColor(i);
      },
      detachDetectColor: function(sprite) {
          var i = this.reference.indexOf(sprite);
          if (i !== -1) {
              this.reference[i] = null;
          }
      },
      _getColor: function(n) {
          var C = this.colorResolution;
          var d = C / this.max;
          return [
              parseInt((n / C / C) % C, 10) / d,
              parseInt((n / C) % C, 10) / d,
              parseInt(n % C, 10) / d,
              1.0
          ];
      },
      _decodeDetectColor: function(color) {
          var C = this.colorResolution;
          return ~~(color[0] * C * C * C / 256) +
              ~~(color[1] * C * C / 256) +
              ~~(color[2] * C / 256);
      },
      getSpriteByColor: function(color) {
          return this.reference[this._decodeDetectColor(color)];
      }
  });
  
  enchant.DomManager = enchant.Class.create({
      initialize: function(node, elementDefinition) {
          var core = enchant.Core.instance;
          this.layer = null;
          this.targetNode = node;
          if (typeof elementDefinition === 'string') {
              this.element = document.createElement(elementDefinition);
          } else if (elementDefinition instanceof HTMLElement) {
              this.element = elementDefinition;
          }
          this.style = this.element.style;
          this.style.position = 'absolute';
          this.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0px 0px';
          if (core._debug) {
              this.style.border = '1px solid blue';
              this.style.margin = '-1px';
          }
  
          var manager = this;
          this._setDomTarget = function() {
              manager.layer._touchEventTarget = manager.targetNode;
          };
          this._attachEvent();
      },
      getDomElement: function() {
          return this.element;
      },
      getDomElementAsNext: function() {
          return this.element;
      },
      getNextManager: function(manager) {
          var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode);
          if (i !== this.targetNode.parentNode.childNodes.length - 1) {
              return this.targetNode.parentNode.childNodes[i + 1]._domManager;
          } else {
              return null;
          }
      },
      addManager: function(childManager, nextManager) {
          var nextElement;
          if (nextManager) {
              nextElement = nextManager.getDomElementAsNext();
          }
          var element = childManager.getDomElement();
          if (element instanceof Array) {
              element.forEach(function(child) {
                  if (nextElement) {
                      this.element.insertBefore(child, nextElement);
                  } else {
                      this.element.appendChild(child);
                  }
              }, this);
          } else {
              if (nextElement) {
                  this.element.insertBefore(element, nextElement);
              } else {
                  this.element.appendChild(element);
              }
          }
          this.setLayer(this.layer);
      },
      removeManager: function(childManager) {
          if (childManager instanceof enchant.DomlessManager) {
              childManager._domRef.forEach(function(element) {
                  this.element.removeChild(element);
              }, this);
          } else {
              this.element.removeChild(childManager.element);
          }
          this.setLayer(this.layer);
      },
      setLayer: function(layer) {
          this.layer = layer;
          var node = this.targetNode;
          var manager;
          if (node.childNodes) {
              for (var i = 0, l = node.childNodes.length; i < l; i++) {
                  manager = node.childNodes[i]._domManager;
                  if (manager) {
                      manager.setLayer(layer);
                  }
              }
          }
      },
      render: function(inheritMat) {
          var node = this.targetNode;
          var matrix = enchant.Matrix.instance;
          var stack = matrix.stack;
          var dest = [];
          matrix.makeTransformMatrix(node, dest);
          matrix.multiply(stack[stack.length - 1], dest, dest);
          matrix.multiply(inheritMat, dest, inheritMat);
          node._matrix = inheritMat;
          var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0;
          var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0;
          var vec = [ ox, oy ];
          matrix.multiplyVec(dest, vec, vec);
  
          node._offsetX = vec[0] - ox;
          node._offsetY = vec[1] - oy;
          if(node.parentNode && !(node.parentNode instanceof enchant.Group)) {
              node._offsetX += node.parentNode._offsetX;
              node._offsetY += node.parentNode._offsetY;
          }
          if (node._dirty) {
              this.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'matrix(' +
                  dest[0].toFixed(10) + ',' +
                  dest[1].toFixed(10) + ',' +
                  dest[2].toFixed(10) + ',' +
                  dest[3].toFixed(10) + ',' +
                  dest[4].toFixed(10) + ',' +
                  dest[5].toFixed(10) +
              ')';
          }
          this.domRender();
      },
      domRender: function() {
          var node = this.targetNode;
          if(!node._style) {
              node._style = {};
          }
          if(!node.__styleStatus) {
              node.__styleStatus = {};
          }
          if (node.width !== null) {
              node._style.width = node.width + 'px';
          }
          if (node.height !== null) {
              node._style.height = node.height + 'px';
          }
          node._style.opacity = node._opacity;
          node._style['background-color'] = node._backgroundColor;
          if (typeof node._visible !== 'undefined') {
              node._style.display = node._visible ? 'block' : 'none';
          }
          if (typeof node.domRender === 'function') {
              node.domRender(this.element);
          }
          var value;
          for (var prop in node._style) {
              value = node._style[prop];
              if(node.__styleStatus[prop] !== value && value != null) {
                  this.style.setProperty(prop, '' + value);
                  node.__styleStatus[prop] = value;
              }
          }
      },
      _attachEvent: function() {
          if (enchant.ENV.TOUCH_ENABLED) {
              this.element.addEventListener('touchstart', this._setDomTarget, true);
          }
          this.element.addEventListener('mousedown', this._setDomTarget, true);
      },
      _detachEvent: function() {
          if (enchant.ENV.TOUCH_ENABLED) {
              this.element.removeEventListener('touchstart', this._setDomTarget, true);
          }
          this.element.removeEventListener('mousedown', this._setDomTarget, true);
      },
      remove: function() {
          this._detachEvent();
          this.element = this.style = this.targetNode = null;
      }
  });
  
  enchant.DomlessManager = enchant.Class.create({
      initialize: function(node) {
          this._domRef = [];
          this.targetNode = node;
      },
      _register: function(element, nextElement) {
          var i = this._domRef.indexOf(nextElement);
          var childNodes;
          if (element instanceof Array) {
              if (i === -1) {
                  Array.prototype.push.apply(this._domRef, element);
              } else {
                  Array.prototype.splice.apply(this._domRef, [i, 0].concat(element));
              }
          } else {
              if (i === -1) {
                  this._domRef.push(element);
              } else {
                  this._domRef.splice(i, 0, element);
              }
          }
      },
      getNextManager: function(manager) {
          var i = this.targetNode.parentNode.childNodes.indexOf(manager.targetNode);
          if (i !== this.targetNode.parentNode.childNodes.length - 1) {
              return this.targetNode.parentNode.childNodes[i + 1]._domManager;
          } else {
              return null;
          }
      },
      getDomElement: function() {
          var ret = [];
          this.targetNode.childNodes.forEach(function(child) {
              ret = ret.concat(child._domManager.getDomElement());
          });
          return ret;
      },
      getDomElementAsNext: function() {
          if (this._domRef.length) {
              return this._domRef[0];
          } else {
              var nextManager = this.getNextManager(this);
              if (nextManager) {
                  return nextManager.element;
              } else {
                  return null;
              }
          }
      },
      addManager: function(childManager, nextManager) {
          var parentNode = this.targetNode.parentNode;
          if (parentNode) {
              if (nextManager === null) {
                  nextManager = this.getNextManager(this);
              }
              if (parentNode instanceof enchant.Scene) {
                  parentNode._layers.Dom._domManager.addManager(childManager, nextManager);
              } else {
                  parentNode._domManager.addManager(childManager, nextManager);
              }
          }
          var nextElement = nextManager ? nextManager.getDomElementAsNext() : null;
          this._register(childManager.getDomElement(), nextElement);
          this.setLayer(this.layer);
      },
      removeManager: function(childManager) {
          var dom;
          var i = this._domRef.indexOf(childManager.element);
          if (i !== -1) {
              dom = this._domRef[i];
              dom.parentNode.removeChild(dom);
              this._domRef.splice(i, 1);
          }
          this.setLayer(this.layer);
      },
      setLayer: function(layer) {
          this.layer = layer;
          var node = this.targetNode;
          var manager;
          if (node.childNodes) {
              for (var i = 0, l = node.childNodes.length; i < l; i++) {
                  manager = node.childNodes[i]._domManager;
                  if (manager) {
                      manager.setLayer(layer);
                  }
              }
          }
      },
      render: function(inheritMat) {
          var matrix = enchant.Matrix.instance;
          var stack = matrix.stack;
          var node = this.targetNode;
          var dest = [];
          matrix.makeTransformMatrix(node, dest);
          matrix.multiply(stack[stack.length - 1], dest, dest);
          matrix.multiply(inheritMat, dest, inheritMat);
          node._matrix = inheritMat;
          var ox = (typeof node._originX === 'number') ? node._originX : node.width / 2 || 0;
          var oy = (typeof node._originY === 'number') ? node._originY : node.height / 2 || 0;
          var vec = [ ox, oy ];
          matrix.multiplyVec(dest, vec, vec);
          node._offsetX = vec[0] - ox;
          node._offsetY = vec[1] - oy;
          stack.push(dest);
      },
      remove: function() {
          this._domRef = [];
          this.targetNode = null;
      }
  });
  
  enchant.DomLayer = enchant.Class.create(enchant.Group, {
      initialize: function() {
          var core = enchant.Core.instance;
          enchant.Group.call(this);
  
          this.width = this._width = core.width;
          this.height = this._height = core.height;
  
          this._touchEventTarget = null;
  
          this._element = document.createElement('div');
          this._element.style.width = this.width + 'px';
          this._element.style.height = this.height + 'px';
          this._element.style.position = 'absolute';
  
          this._domManager = new enchant.DomManager(this, this._element);
          this._domManager.layer = this;
  
          var touch = [
              enchant.Event.TOUCH_START,
              enchant.Event.TOUCH_MOVE,
              enchant.Event.TOUCH_END
          ];
  
          touch.forEach(function(type) {
              this.addEventListener(type, function(e) {
                  if (this._scene) {
                      this._scene.dispatchEvent(e);
                  }
              });
          }, this);
  
          var __onchildadded = function(e) {
              var child = e.node;
              var next = e.next;
              var self = e.target;
              var nextManager = next ? next._domManager : null;
              enchant.DomLayer._attachDomManager(child, __onchildadded, __onchildremoved);
              self._domManager.addManager(child._domManager, nextManager);
              var render = new enchant.Event(enchant.Event.RENDER);
              child._dirty = true;
              self._domManager.layer._rendering(child, render);
          };
  
          var __onchildremoved = function(e) {
              var child = e.node;
              var self = e.target;
              self._domManager.removeManager(child._domManager);
              enchant.DomLayer._detachDomManager(child, __onchildadded, __onchildremoved);
          };
  
          this.addEventListener('childremoved', __onchildremoved);
          this.addEventListener('childadded', __onchildadded);
  
      },
      _startRendering: function() {
          this.addEventListener('exitframe', this._onexitframe);
          this._onexitframe();
      },
      _stopRendering: function() {
          this.removeEventListener('exitframe', this._onexitframe);
          this._onexitframe();
      },
      _onexitframe: function() {
          this._rendering(this, new enchant.Event(enchant.Event.RENDER));
      },
      _rendering: function(node, e, inheritMat) {
          var child;
          if (!inheritMat) {
              inheritMat = [ 1, 0, 0, 1, 0, 0 ];
          }
          node.dispatchEvent(e);
          node._domManager.render(inheritMat);
          if (node.childNodes) {
              for (var i = 0, l = node.childNodes.length; i < l; i++) {
                  child = node.childNodes[i];
                  this._rendering(child, e, inheritMat.slice());
              }
          }
          if (node._domManager instanceof enchant.DomlessManager) {
              enchant.Matrix.instance.stack.pop();
          }
          node._dirty = false;
      },
      _determineEventTarget: function() {
          if (this._touchEventTarget) {
              if (this._touchEventTarget !== this) {
                  return this._touchEventTarget;
              }
          }
          return null;
      }
  });
  
  enchant.DomLayer._attachDomManager = function(node, onchildadded, onchildremoved) {
      var child;
      if (!node._domManager) {
          node.addEventListener('childadded', onchildadded);
          node.addEventListener('childremoved', onchildremoved);
          if (node instanceof enchant.Group) {
              node._domManager = new enchant.DomlessManager(node);
          } else {
              if (node._element) {
                  node._domManager = new enchant.DomManager(node, node._element);
              } else {
                  node._domManager = new enchant.DomManager(node, 'div');
              }
          }
      }
      if (node.childNodes) {
          for (var i = 0, l = node.childNodes.length; i < l; i++) {
              child = node.childNodes[i];
              enchant.DomLayer._attachDomManager(child, onchildadded, onchildremoved);
              node._domManager.addManager(child._domManager, null);
          }
      }
  };
  
  enchant.DomLayer._detachDomManager = function(node, onchildadded, onchildremoved) {
      var child;
      node.removeEventListener('childadded', onchildadded);
      node.removeEventListener('childremoved', onchildremoved);
      if (node.childNodes) {
          for (var i = 0, l = node.childNodes.length; i < l; i++) {
              child = node.childNodes[i];
              node._domManager.removeManager(child._domManager, null);
              enchant.DomLayer._detachDomManager(child, onchildadded, onchildremoved);
          }
      }
      node._domManager.remove();
      delete node._domManager;
  };
  
  
@scope enchant.CanvasLayer.prototype

  
  enchant.CanvasLayer = enchant.Class.create(enchant.Group, {
      
@name enchant.CanvasLayer @class A class which is using HTML Canvas for the rendering. The rendering of children will be replaced by the Canvas rendering. @constructs

  
      initialize: function() {
          var core = enchant.Core.instance;
  
          enchant.Group.call(this);
  
          this._cvsCache = {
              matrix: [1, 0, 0, 1, 0, 0],
              detectColor: '#000000'
          };
          this._cvsCache.layer = this;
  
          this.width = core.width;
          this.height = core.height;
  
          this._element = document.createElement('canvas');
          this._element.width = core.width;
          this._element.height = core.height;
          this._element.style.position = 'absolute';
          // issue 179
          this._element.style.left = this._element.style.top = '0px';
  
          this._detect = document.createElement('canvas');
          this._detect.width = core.width;
          this._detect.height = core.height;
          this._detect.style.position = 'absolute';
          this._lastDetected = 0;
  
          this.context = this._element.getContext('2d');
          this._dctx = this._detect.getContext('2d');
  
          this._colorManager = new enchant.DetectColorManager(16, 256);
  
          var touch = [
              enchant.Event.TOUCH_START,
              enchant.Event.TOUCH_MOVE,
              enchant.Event.TOUCH_END
          ];
  
          touch.forEach(function(type) {
              this.addEventListener(type, function(e) {
                  if (this._scene) {
                      this._scene.dispatchEvent(e);
                  }
              });
          }, this);
  
          var __onchildadded = function(e) {
              var child = e.node;
              var self = e.target;
              var layer;
              if (self instanceof enchant.CanvasLayer) {
                  layer = self._scene._layers.Canvas;
              } else {
                  layer = self.scene._layers.Canvas;
              }
              enchant.CanvasLayer._attachCache(child, layer, __onchildadded, __onchildremoved);
              var render = new enchant.Event(enchant.Event.RENDER);
              if (self._dirty) {
                  self._updateCoordinate();
              }
              child._dirty = true;
              enchant.Matrix.instance.stack.push(self._matrix);
              layer._rendering(child, render);
              enchant.Matrix.instance.stack.pop(self._matrix);
          };
  
          var __onchildremoved = function(e) {
              var child = e.node;
              var self = e.target;
              var layer;
              if (self instanceof enchant.CanvasLayer) {
                  layer = self._scene._layers.Canvas;
              } else {
                  layer = self.scene._layers.Canvas;
              }
              enchant.CanvasLayer._detachCache(child, layer, __onchildadded, __onchildremoved);
          };
  
          this.addEventListener('childremoved', __onchildremoved);
          this.addEventListener('childadded', __onchildadded);
  
      },
      
@private

  
      _startRendering: function() {
          this.addEventListener('exitframe', this._onexitframe);
          this._onexitframe(new enchant.Event(enchant.Event.RENDER));
      },
      
@private

  
      _stopRendering: function() {
          this.removeEventListener('render', this._onexitframe);
          this._onexitframe(new enchant.Event(enchant.Event.RENDER));
      },
      _onexitframe: function() {
          var core = enchant.Core.instance;
          var ctx = this.context;
          ctx.clearRect(0, 0, core.width, core.height);
          var render = new enchant.Event(enchant.Event.RENDER);
          this._rendering(this, render);
      },
      _rendering:  function(node, e) {
          var ctx = this.context;
          var width, height, child;
          ctx.save();
          node.dispatchEvent(e);
          // transform
          this._transform(node, ctx);
          if (typeof node._visible === 'undefined' || node._visible) {
              width = node.width;
              height = node.height;
              // composite
              if (node.compositeOperation) {
                  ctx.globalCompositeOperation = node.compositeOperation;
              } else {
                  ctx.globalCompositeOperation = 'source-over';
              }
              ctx.globalAlpha = (typeof node._opacity === 'number') ? node._opacity : 1.0;
              // render
              if (node._backgroundColor) {
                  ctx.fillStyle = node._backgroundColor;
                  ctx.fillRect(0, 0, width, height);
              }
  
              if (node.cvsRender) {
                  node.cvsRender(ctx);
              }
  
              if (enchant.Core.instance._debug) {
                  if (node instanceof enchant.Label || node instanceof enchant.Sprite) {
                      ctx.strokeStyle = '#ff0000';
                  } else {
                      ctx.strokeStyle = '#0000ff';
                  }
                  ctx.strokeRect(0, 0, width, height);
              }
              if (node._clipping) {
                  ctx.beginPath();
                  ctx.rect(0, 0, width, height);
                  ctx.clip();
              }
              if (node.childNodes) {
                  for (var i = 0, l = node.childNodes.length; i < l; i++) {
                      child = node.childNodes[i];
                      this._rendering(child, e);
                  }
              }
          }
          ctx.restore();
          enchant.Matrix.instance.stack.pop();
      },
      _detectrendering: function(node) {
          var ctx, width, height, child;
          if (typeof node._visible === 'undefined' || node._visible) {
              width = node.width;
              height = node.height;
              ctx = this._dctx;
              ctx.save();
              this._transform(node, ctx);
              ctx.fillStyle = node._cvsCache.detectColor;
              if (node._touchEnabled) {
                  if (node.detectRender) {
                      node.detectRender(ctx);
                  } else {
                      ctx.fillRect(0, 0, width, height);
                  }
              }
              if (node._clipping) {
                  ctx.beginPath();
                  ctx.rect(0, 0, width, height);
                  ctx.clip();
              }
              if (node.childNodes) {
                  for (var i = 0, l = node.childNodes.length; i < l; i++) {
                      child = node.childNodes[i];
                      this._detectrendering(child);
                  }
              }
              ctx.restore();
              enchant.Matrix.instance.stack.pop();
          }
      },
      _transform: function(node, ctx) {
          var matrix = enchant.Matrix.instance;
          var stack = matrix.stack;
          var newmat, ox, oy, vec;
          if (node._dirty) {
              matrix.makeTransformMatrix(node, node._cvsCache.matrix);
              newmat = [];
              matrix.multiply(stack[stack.length - 1], node._cvsCache.matrix, newmat);
              node._matrix = newmat;
              ox = (typeof node._originX === 'number') ? node._originX : node._width / 2 || 0;
              oy = (typeof node._originY === 'number') ? node._originY : node._height / 2 || 0;
              vec = [ ox, oy ];
              matrix.multiplyVec(newmat, vec, vec);
              node._offsetX = vec[0] - ox;
              node._offsetY = vec[1] - oy;
              node._dirty = false;
          } else {
              newmat = node._matrix;
          }
          stack.push(newmat);
          ctx.setTransform.apply(ctx, newmat);
  
      },
      _determineEventTarget: function(e) {
          return this._getEntityByPosition(e.x, e.y);
      },
      _getEntityByPosition: function(x, y) {
          var core = enchant.Core.instance;
          var ctx = this._dctx;
          if (this._lastDetected < core.frame) {
              ctx.clearRect(0, 0, this.width, this.height);
              this._detectrendering(this);
              this._lastDetected = core.frame;
          }
          var color = ctx.getImageData(x, y, 1, 1).data;
          return this._colorManager.getSpriteByColor(color);
      }
  });
  
  enchant.CanvasLayer._attachCache = function(node, layer, onchildadded, onchildremoved) {
      var child;
      if (!node._cvsCache) {
          node._cvsCache = {};
          node._cvsCache.matrix = [ 1, 0, 0, 1, 0, 0 ];
          node._cvsCache.detectColor = 'rgba(' + layer._colorManager.attachDetectColor(node) + ')';
          node.addEventListener('childadded', onchildadded);
          node.addEventListener('childremoved', onchildremoved);
      }
      if (node.childNodes) {
          for (var i = 0, l = node.childNodes.length; i < l; i++) {
              child = node.childNodes[i];
              enchant.CanvasLayer._attachCache(child, layer, onchildadded, onchildremoved);
          }
      }
  };
  
  enchant.CanvasLayer._detachCache = function(node, layer, onchildadded, onchildremoved) {
      var child;
      if (node._cvsCache) {
          layer._colorManager.detachDetectColor(node);
          node.removeEventListener('childadded', onchildadded);
          node.removeEventListener('childremoved', onchildremoved);
          delete node._cvsCache;
      }
      if (node.childNodes) {
          for (var i = 0, l = node.childNodes.length; i < l; i++) {
              child = node.childNodes[i];
              enchant.CanvasLayer._detachCache(child, layer, onchildadded, onchildremoved);
          }
      }
  };
  
  
@scope enchant.Scene.prototype @type {*}

  
  enchant.Scene = enchant.Class.create(enchant.Group, {
      
@name enchant.Scene @class A Class that becomes the root of the display object tree. @example var scene = new Scene(); scene.addChild(player); scene.addChild(enemy); core.pushScene(scene); @constructs @extends enchant.Group

  
      initialize: function() {
          var core = enchant.Core.instance;
  
          // Call initialize method of enchant.Group
          enchant.Group.call(this);
  
          this.width = core.width;
          this.height = core.height;
  
          // All nodes (entities, groups, scenes) have reference to the scene that it belongs to.
          this.scene = this;
  
          this._backgroundColor = null;
  
          // Create div tag which possesses its layers
          this._element = document.createElement('div');
          this._element.style.width = this.width + 'px';
          this._element.style.height = this.height + 'px';
          this._element.style.position = 'absolute';
          this._element.style.overflow = 'hidden';
          this._element.style[enchant.ENV.VENDOR_PREFIX + 'TransformOrigin'] = '0 0';
          this._element.style[enchant.ENV.VENDOR_PREFIX + 'Transform'] = 'scale(' + enchant.Core.instance.scale + ')';
  
          this._layers = {};
          this._layerPriority = [];
  
          this.addEventListener(enchant.Event.CHILD_ADDED, this._onchildadded);
          this.addEventListener(enchant.Event.CHILD_REMOVED, this._onchildremoved);
          this.addEventListener(enchant.Event.ENTER, this._onenter);
          this.addEventListener(enchant.Event.EXIT, this._onexit);
  
          var that = this;
          this._dispatchExitframe = function() {
              var layer;
              for (var prop in that._layers) {
                  layer = that._layers[prop];
                  layer.dispatchEvent(new enchant.Event(enchant.Event.EXIT_FRAME));
              }
          };
      },
      x: {
          get: function() {
              return this._x;
          },
          set: function(x) {
              this._x = x;
              for (var type in this._layers) {
                  this._layers[type].x = x;
              }
          }
      },
      y: {
          get: function() {
              return this._y;
          },
          set: function(y) {
              this._y = y;
              for (var type in this._layers) {
                  this._layers[type].y = y;
              }
          }
      },
      rotation: {
          get: function() {
              return this._rotation;
          },
          set: function(rotation) {
              this._rotation = rotation;
              for (var type in this._layers) {
                  this._layers[type].rotation = rotation;
              }
          }
      },
      scaleX: {
          get: function() {
              return this._scaleX;
          },
          set: function(scaleX) {
              this._scaleX = scaleX;
              for (var type in this._layers) {
                  this._layers[type].scaleX = scaleX;
              }
          }
      },
      scaleY: {
          get: function() {
              return this._scaleY;
          },
          set: function(scaleY) {
              this._scaleY = scaleY;
              for (var type in this._layers) {
                  this._layers[type].scaleY = scaleY;
              }
          }
      },
      backgroundColor: {
          get: function() {
              return this._backgroundColor;
          },
          set: function(color) {
              this._backgroundColor = this._element.style.backgroundColor = color;
          }
      },
      addLayer: function(type, i) {
          var core = enchant.Core.instance;
          if (this._layers[type]) {
              return;
          }
          var layer = new enchant[type + 'Layer']();
          if (core.currentScene === this) {
              layer._startRendering();
          }
          this._layers[type] = layer;
          var element = layer._element;
          if (typeof i === 'number') {
              var nextSibling = this._element.childNodes[i];
              if (nextSibling) {
                  this._element.insertBefore(element, nextSibling);
              } else {
                  this._element.appendChild(element);
              }
              this._layerPriority.splice(i, 0, type);
          } else {
              this._element.appendChild(element);
              this._layerPriority.push(type);
          }
          layer._scene = this;
      },
      _determineEventTarget: function(e) {
          var layer, target;
          for (var i = this._layerPriority.length - 1; i >= 0; i--) {
              layer = this._layers[this._layerPriority[i]];
              target = layer._determineEventTarget(e);
              if (target) {
                  break;
              }
          }
          if (!target) {
              target = this;
          }
          return target;
      },
      _onchildadded: function(e) {
          var child = e.node;
          var next = e.next;
          var target, i;
          if (child._element) {
              target = 'DOM';
              i = 1;
          } else {
              target = 'Canvas';
              i = 0;
          }
          if (!this._layers[target]) {
              this.addLayer(target, i);
          }
          child._layer = this._layers[target];
          this._layers[target].insertBefore(child, next);
          child.parentNode = this;
      },
      _onchildremoved: function(e) {
          var child = e.node;
          child._layer.removeChild(child);
          child._layer = null;
      },
      _onenter: function() {
          for (var type in this._layers) {
              this._layers[type]._startRendering();
          }
          enchant.Core.instance.addEventListener('exitframe', this._dispatchExitframe);
      },
      _onexit: function() {
          for (var type in this._layers) {
              this._layers[type]._stopRendering();
          }
          enchant.Core.instance.removeEventListener('exitframe', this._dispatchExitframe);
      }
  });
  
  
@scope enchant.CanvasScene.prototype @type {*}

  
  enchant.CanvasScene = enchant.Class.create(enchant.Scene, {
      initialize: function() {
          enchant.Scene.call(this);
          this.addLayer('Canvas');
      },
      _determineEventTarget: function(e) {
          var target = this._layers.Canvas._determineEventTarget(e);
          if (!target) {
              target = this;
          }
          return target;
      },
      _onchildadded: function(e) {
          var child = e.node;
          var next = e.next;
          child._layer = this._layers.Canvas;
          this._layers.Canvas.insertBefore(child, next);
      },
      _onenter: function() {
          this._layers.Canvas._startRendering();
          enchant.Core.instance.addEventListener('exitframe', this._dispatchExitframe);
      },
      _onexit: function() {
          this._layers.Canvas._stopRendering();
          enchant.Core.instance.removeEventListener('exitframe', this._dispatchExitframe);
      }
  });
  
  
@scope enchant.CanvasScene.prototype @type {*}

  
  enchant.DOMScene = enchant.Class.create(enchant.Scene, {
      initialize: function() {
          enchant.Scene.call(this);
          this.addLayer('Dom');
      },
      _determineEventTarget: function(e) {
          var target = this._layers.Dom._determineEventTarget(e);
          if (!target) {
              target = this;
          }
          return target;
      },
      _onchildadded: function(e) {
          var child = e.node;
          var next = e.next;
          child._layer = this._layers.Dom;
          this._layers.Dom.insertBefore(child, next);
      },
      _onenter: function() {
          this._layers.Dom._startRendering();
          enchant.Core.instance.addEventListener('exitframe', this._dispatchExitframe);
      },
      _onexit: function() {
          this._layers.Dom._stopRendering();
          enchant.Core.instance.removeEventListener('exitframe', this._dispatchExitframe);
      }
  });
  
  
@scope enchant.Surface.prototype

  
  enchant.Surface = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.Surface @class Class that wraps canvas elements. Can be used to set the {gray enchant.Sprite} and {gray enchant.Map}'s image properties to be displayed. If you wish to access Canvas API use the {gray enchant.Surface#context} property. @example // Creates Sprite that displays a circle. var ball = new Sprite(50, 50); var surface = new Surface(50, 50); surface.context.beginPath(); surface.context.arc(25, 25, 25, 0, Math.PI*2, true); surface.context.fill(); ball.image = surface;
parameter: {Number} width Surface width.
parameter: {Number} height Surface height. @constructs

  
      initialize: function(width, height) {
          enchant.EventTarget.call(this);
  
          var core = enchant.Core.instance;
  
          
Surface width. @type {Number}

  
          this.width = width;
          
Surface height. @type {Number}

  
          this.height = height;
          
Surface drawing context. @type {CanvasRenderingContext2D}

  
          this.context = null;
  
          var id = 'enchant-surface' + core._surfaceID++;
          if (document.getCSSCanvasContext) {
              this.context = document.getCSSCanvasContext('2d', id, width, height);
              this._element = this.context.canvas;
              this._css = '-webkit-canvas(' + id + ')';
              var context = this.context;
          } else if (document.mozSetImageElement) {
              this._element = document.createElement('canvas');
              this._element.width = width;
              this._element.height = height;
              this._css = '-moz-element(#' + id + ')';
              this.context = this._element.getContext('2d');
              document.mozSetImageElement(id, this._element);
          } else {
              this._element = document.createElement('canvas');
              this._element.width = width;
              this._element.height = height;
              this._element.style.position = 'absolute';
              this.context = this._element.getContext('2d');
  
              enchant.ENV.CANVAS_DRAWING_METHODS.forEach(function(name) {
                  var method = this.context[name];
                  this.context[name] = function() {
                      method.apply(this, arguments);
                      this._dirty = true;
                  };
              }, this);
          }
      },
      
Returns 1 pixel from the Surface.
parameter: {Number} x The pixel's x coordinates.
parameter: {Number} y The pixel's y coordinates.
returns: {Array.} An array that holds pixel information in [r, g, b, a] format.

  
      getPixel: function(x, y) {
          return this.context.getImageData(x, y, 1, 1).data;
      },
      
Sets one pixel within the surface.
parameter: {Number} x The pixel's x coordinates.
parameter: {Number} y The pixel's y coordinates.
parameter: {Number} r The pixel's red level.
parameter: {Number} g The pixel's green level.
parameter: {Number} b The pixel's blue level.
parameter: {Number} a The pixel's transparency.

  
      setPixel: function(x, y, r, g, b, a) {
          var pixel = this.context.createImageData(1, 1);
          pixel.data[0] = r;
          pixel.data[1] = g;
          pixel.data[2] = b;
          pixel.data[3] = a;
          this.context.putImageData(pixel, x, y);
      },
      
Clears all Surface pixels and makes the pixels transparent.

  
      clear: function() {
          this.context.clearRect(0, 0, this.width, this.height);
      },
      
Draws the content of the given Surface onto this surface. Wraps Canvas API drawImage and if multiple arguments are given, these are getting applied to the Canvas drawImage method. @example var src = core.assets['src.gif']; var dst = new Surface(100, 100); dst.draw(src); // Draws source at (0, 0) dst.draw(src, 50, 50); // Draws source at (50, 50) // Draws just 30 horizontal and vertical pixels of source at (50, 50) dst.draw(src, 50, 50, 30, 30); // Takes the image content in src starting at (10,10) with a (Width, Height) of (40,40), // scales it and draws it in this surface at (50, 50) with a (Width, Height) of (30,30). dst.draw(src, 10, 10, 40, 40, 50, 50, 30, 30);
parameter: {enchant.Surface} image Surface used in drawing.

  
      draw: function(image) {
          image = image._element;
          if (arguments.length === 1) {
              this.context.drawImage(image, 0, 0);
          } else {
              var args = arguments;
              args[0] = image;
              this.context.drawImage.apply(this.context, args);
          }
      },
      
Copies Surface.
returns: {enchant.Surface} The copied Surface.

  
      clone: function() {
          var clone = new enchant.Surface(this.width, this.height);
          clone.draw(this);
          return clone;
      },
      
Creates a data URI scheme from this Surface.
returns: {String} The data URI scheme that identifies this Surface and can be used to include this Surface into a dom tree.

  
      toDataURL: function() {
          var src = this._element.src;
          if (src) {
              if (src.slice(0, 5) === 'data:') {
                  return src;
              } else {
                  return this.clone().toDataURL();
              }
          } else {
              return this._element.toDataURL();
          }
      }
  });
  
  
Loads an image and creates a Surface object out of it. It is not possible to access properties or methods of the {gray enchant.Surface#context}, or to call methods using the Canvas API - like {gray enchant.Surface#draw}, {gray enchant.Surface#clear}, {gray enchant.Surface#getPixel}, {gray enchant.Surface#setPixel}.. - of the wrapped image created with this method. However, it is possible to use this surface to draw it to another surface using the {gray enchant.Surface#draw} method. The resulting surface can then be manipulated. (when loading images in a cross-origin resource sharing environment, pixel acquisition and other image manipulation might be limited).
parameter: {String} src The file path of the image to be loaded. @static

  
  enchant.Surface.load = function(src, callback) {
      var image = new Image();
      var surface = Object.create(enchant.Surface.prototype, {
          context: { value: null },
          _css: { value: 'url(' + src + ')' },
          _element: { value: image }
      });
      enchant.EventTarget.call(surface);
      if (typeof callback === 'function') {
          surface.addEventListener('load', callback);
      }
      image.onerror = function() {
          throw new Error('Cannot load an asset: ' + image.src);
      };
      image.onload = function() {
          surface.width = image.width;
          surface.height = image.height;
          surface.dispatchEvent(new enchant.Event('load'));
      };
      image.src = src;
      return surface;
  };
  
  enchant.Surface._getPattern = function(surface, force) {
      if (!(surface instanceof enchant.Surface)) {
          throw new Error('Cannot create pattern from passed object');
      }
      if (!surface._pattern || force) {
          surface._pattern = document.createElement('canvas').getContext('2d').createPattern(surface._element, 'repeat');
      }
      return surface._pattern;
  };
  
  
@scope enchant.DOMSound.prototype @type {*}

  
  enchant.DOMSound = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.DOMSound @class Class to wrap audio elements. Safari, Chrome, Firefox, Opera, and IE all play MP3 files (Firefox and Opera play via Flash). WAVE files can be played on Safari, Chrome, Firefox, and Opera. When the browser is not compatible with the used codec the file will not play. Instances are created not via constructor but via {gray enchant.DOMSound.load}. @constructs

  
      initialize: function() {
          enchant.EventTarget.call(this);
          
Sound file duration (seconds). @type {Number}

  
          this.duration = 0;
          throw new Error("Illegal Constructor");
      },
      
Begin playing.

  
      play: function() {
          if (this._element) {
              this._element.play();
          }
      },
      
Pause playback.

  
      pause: function() {
          if (this._element) {
              this._element.pause();
          }
      },
      
Stop playing.

  
      stop: function() {
          this.pause();
          this.currentTime = 0;
      },
      
Create a copy of this Sound object.
returns: {enchant.DOMSound} Copied Sound.

  
      clone: function() {
          var clone;
          if (this._element instanceof Audio) {
              clone = Object.create(enchant.DOMSound.prototype, {
                  _element: { value: this._element.cloneNode(false) },
                  duration: { value: this.duration }
              });
          } else if (enchant.ENV.USE_FLASH_SOUND) {
              return this;
          } else {
              clone = Object.create(enchant.DOMSound.prototype);
          }
          enchant.EventTarget.call(clone);
          return clone;
      },
      
Current playback position (seconds). @type {Number}

  
      currentTime: {
          get: function() {
              return this._element ? this._element.currentTime : 0;
          },
          set: function(time) {
              if (this._element) {
                  this._element.currentTime = time;
              }
          }
      },
      
Volume. 0 (muted) ~ 1 (full volume). @type {Number}

  
      volume: {
          get: function() {
              return this._element ? this._element.volume : 1;
          },
          set: function(volume) {
              if (this._element) {
                  this._element.volume = volume;
              }
          }
      }
  });
  
  
Loads an audio file and creates Sound object.
parameter: {String} src Path of the audio file to be loaded.
parameter: {String} [type] MIME Type of the audio file. @static

  
  enchant.DOMSound.load = function(src, type, callback) {
      if (type == null) {
          var ext = enchant.Core.findExt(src);
          if (ext) {
              type = 'audio/' + ext;
          } else {
              type = '';
          }
      }
      type = type.replace('mp3', 'mpeg').replace('m4a', 'mp4');
  
      var sound = Object.create(enchant.DOMSound.prototype);
      enchant.EventTarget.call(sound);
      sound.addEventListener('load', function() {
          callback.call(enchant.Core.instance);
      });
      var audio = new Audio();
      if (!enchant.ENV.SOUND_ENABLED_ON_MOBILE_SAFARI &&
          enchant.ENV.VENDOR_PREFIX === 'webkit' && enchant.ENV.TOUCH_ENABLED) {
          window.setTimeout(function() {
              sound.dispatchEvent(new enchant.Event('load'));
          }, 0);
      } else {
          if (!enchant.ENV.USE_FLASH_SOUND && audio.canPlayType(type)) {
              audio.addEventListener('canplaythrough', function() {
                  sound.duration = audio.duration;
                  sound.dispatchEvent(new enchant.Event('load'));
              }, false);
              audio.src = src;
              audio.load();
              audio.autoplay = false;
              audio.onerror = function() {
                  throw new Error('Cannot load an asset: ' + audio.src);
              };
              sound._element = audio;
          } else if (type === 'audio/mpeg') {
              var embed = document.createElement('embed');
              var id = 'enchant-audio' + enchant.Core.instance._soundID++;
              embed.width = embed.height = 1;
              embed.name = id;
              embed.src = 'sound.swf?id=' + id + '&src=' + src;
              embed.allowscriptaccess = 'always';
              embed.style.position = 'absolute';
              embed.style.left = '-1px';
              sound.addEventListener('load', function() {
                  Object.defineProperties(embed, {
                      currentTime: {
                          get: function() {
                              return embed.getCurrentTime();
                          },
                          set: function(time) {
                              embed.setCurrentTime(time);
                          }
                      },
                      volume: {
                          get: function() {
                              return embed.getVolume();
                          },
                          set: function(volume) {
                              embed.setVolume(volume);
                          }
                      }
                  });
                  sound._element = embed;
                  sound.duration = embed.getDuration();
              });
              enchant.Core.instance._element.appendChild(embed);
              enchant.DOMSound[id] = sound;
          } else {
              window.setTimeout(function() {
                  sound.dispatchEvent(new enchant.Event('load'));
              }, 0);
          }
      }
      return sound;
  };
  
  window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext || window.oAudioContext;
  
  
@scope enchant.WebAudioSound.prototype @type {*}

  
  enchant.WebAudioSound = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.WebAudioSound @class Sound wrapper class for Web Audio API (supported on some webkit-based browsers) @constructs

  
      initialize: function() {
          if(!window.webkitAudioContext){
              throw new Error("This browser does not support WebAudio API.");
          }
          var actx = enchant.WebAudioSound.audioContext;
          enchant.EventTarget.call(this);
          this.src = actx.createBufferSource();
          this.buffer = null;
          this._volume = 1;
          this._currentTime = 0;
          this._state = 0;
          this.connectTarget = enchant.WebAudioSound.destination;
      },
      play: function(dup) {
          var actx = enchant.WebAudioSound.audioContext;
          if (this._state === 2) {
              this.src.connect(this.connectTarget);
          } else {
              if (this._state === 1 && !dup) {
                  this.src.disconnect(this.connectTarget);
              }
              this.src = actx.createBufferSource();
              this.src.buffer = this.buffer;
              this.src.gain.value = this._volume;
              this.src.connect(this.connectTarget);
              this.src.noteOn(0);
          }
          this._state = 1;
      },
      pause: function() {
          var actx = enchant.WebAudioSound.audioContext;
          this.src.disconnect(this.connectTarget);
          this._state = 2;
      },
      stop: function() {
          this.src.noteOff(0);
          this._state = 0;
      },
      clone: function() {
          var sound = new enchant.WebAudioSound();
          sound.buffer = this.buffer;
          return sound;
      },
      dulation: {
          get: function() {
              if (this.buffer) {
                  return this.buffer.dulation;
              } else {
                  return 0;
              }
          }
      },
      volume: {
          get: function() {
              return this._volume;
          },
          set: function(volume) {
              volume = Math.max(0, Math.min(1, volume));
              this._volume = volume;
              if (this.src) {
                  this.src.gain.value = volume;
              }
          }
      },
      currentTime: {
          get: function() {
              window.console.log('currentTime is not allowed');
              return this._currentTime;
          },
          set: function(time) {
              window.console.log('currentTime is not allowed');
              this._currentTime = time;
          }
      }
  });
  
  enchant.WebAudioSound.load = function(src, type, callback) {
      var actx = enchant.WebAudioSound.audioContext;
      var xhr = new XMLHttpRequest();
      var sound = new enchant.WebAudioSound();
      var mimeType = 'audio/' + enchant.Core.findExt(src);
      // TODO check Audio.canPlayType(mimeType)
      xhr.responseType = 'arraybuffer';
      xhr.open('GET', src, true);
      xhr.onload = function() {
          actx.decodeAudioData(
              xhr.response,
              function(buffer) {
                  sound.buffer = buffer;
                  callback.call(enchant.Core.instance);
              },
              function(error) {
                  // TODO change to enchant Error
                  window.console.log(error);
              }
          );
      };
      xhr.send(null);
      return sound;
  };
  
  if(window.AudioContext){
      enchant.WebAudioSound.audioContext = new window.AudioContext();
      enchant.WebAudioSound.destination = enchant.WebAudioSound.audioContext.destination;
  }
  
  /* jshint newcap: false */
  
  enchant.Sound = window.AudioContext && enchant.ENV.USE_WEBAUDIO ? enchant.WebAudioSound : enchant.DOMSound;
  
  
============================================================================================ Easing Equations v2.0 September 1, 2003 (c) 2003 Robert Penner, all rights reserved. This work is subject to the terms in http://www.robertpenner.com/easing_terms_of_use.html. ============================================================================================

  
  
  
Easing function library, from "Easing Equations" by Robert Penner. @type {Object} @namespace {gray enchant.Tween} クラスで用いるイージング関数のライブラリ名前空間.

  
  enchant.Easing = {
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      LINEAR: function(t, b, c, d) {
          return c * t / d + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      SWING: function(t, b, c, d) {
          return c * (0.5 - Math.cos(((t / d) * Math.PI)) / 2) + b;
      },
      // quad
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUAD_EASEIN: function(t, b, c, d) {
          return c * (t /= d) * t + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUAD_EASEOUT: function(t, b, c, d) {
          return -c * (t /= d) * (t - 2) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUAD_EASEINOUT: function(t, b, c, d) {
          if ((t /= d / 2) < 1) {
              return c / 2 * t * t + b;
          }
          return -c / 2 * ((--t) * (t - 2) - 1) + b;
      },
      // cubic
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CUBIC_EASEIN: function(t, b, c, d) {
          return c * (t /= d) * t * t + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CUBIC_EASEOUT: function(t, b, c, d) {
          return c * ((t = t / d - 1) * t * t + 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CUBIC_EASEINOUT: function(t, b, c, d) {
          if ((t /= d / 2) < 1) {
              return c / 2 * t * t * t + b;
          }
          return c / 2 * ((t -= 2) * t * t + 2) + b;
      },
      // quart
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUART_EASEIN: function(t, b, c, d) {
          return c * (t /= d) * t * t * t + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUART_EASEOUT: function(t, b, c, d) {
          return -c * ((t = t / d - 1) * t * t * t - 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUART_EASEINOUT: function(t, b, c, d) {
          if ((t /= d / 2) < 1) {
              return c / 2 * t * t * t * t + b;
          }
          return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
      },
      // quint
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUINT_EASEIN: function(t, b, c, d) {
          return c * (t /= d) * t * t * t * t + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUINT_EASEOUT: function(t, b, c, d) {
          return c * ((t = t / d - 1) * t * t * t * t + 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      QUINT_EASEINOUT: function(t, b, c, d) {
          if ((t /= d / 2) < 1) {
              return c / 2 * t * t * t * t * t + b;
          }
          return c / 2 * ((t -= 2) * t * t * t * t + 2) + b;
      },
      //sin
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      SIN_EASEIN: function(t, b, c, d) {
          return -c * Math.cos(t / d * (Math.PI / 2)) + c + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      SIN_EASEOUT: function(t, b, c, d) {
          return c * Math.sin(t / d * (Math.PI / 2)) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      SIN_EASEINOUT: function(t, b, c, d) {
          return -c / 2 * (Math.cos(Math.PI * t / d) - 1) + b;
      },
      // circ
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CIRC_EASEIN: function(t, b, c, d) {
          return -c * (Math.sqrt(1 - (t /= d) * t) - 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CIRC_EASEOUT: function(t, b, c, d) {
          return c * Math.sqrt(1 - (t = t / d - 1) * t) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      CIRC_EASEINOUT: function(t, b, c, d) {
          if ((t /= d / 2) < 1) {
              return -c / 2 * (Math.sqrt(1 - t * t) - 1) + b;
          }
          return c / 2 * (Math.sqrt(1 - (t -= 2) * t) + 1) + b;
      },
      // elastic
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      ELASTIC_EASEIN: function(t, b, c, d, a, p) {
          if (t === 0) {
              return b;
          }
          if ((t /= d) === 1) {
              return b + c;
          }
  
          if (!p) {
              p = d * 0.3;
          }
  
          var s;
          if (!a || a < Math.abs(c)) {
              a = c;
              s = p / 4;
          } else {
              s = p / (2 * Math.PI) * Math.asin(c / a);
          }
          return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      ELASTIC_EASEOUT: function(t, b, c, d, a, p) {
          if (t === 0) {
              return b;
          }
          if ((t /= d) === 1) {
              return b + c;
          }
          if (!p) {
              p = d * 0.3;
          }
          var s;
          if (!a || a < Math.abs(c)) {
              a = c;
              s = p / 4;
          } else {
              s = p / (2 * Math.PI) * Math.asin(c / a);
          }
          return (a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b);
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      ELASTIC_EASEINOUT: function(t, b, c, d, a, p) {
          if (t === 0) {
              return b;
          }
          if ((t /= d / 2) === 2) {
              return b + c;
          }
          if (!p) {
              p = d * (0.3 * 1.5);
          }
          var s;
          if (!a || a < Math.abs(c)) {
              a = c;
              s = p / 4;
          } else {
              s = p / (2 * Math.PI) * Math.asin(c / a);
          }
          if (t < 1) {
              return -0.5 * (a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
          }
          return a * Math.pow(2, -10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p) * 0.5 + c + b;
      },
      // bounce
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BOUNCE_EASEOUT: function(t, b, c, d) {
          if ((t /= d) < (1 / 2.75)) {
              return c * (7.5625 * t * t) + b;
          } else if (t < (2 / 2.75)) {
              return c * (7.5625 * (t -= (1.5 / 2.75)) * t + 0.75) + b;
          } else if (t < (2.5 / 2.75)) {
              return c * (7.5625 * (t -= (2.25 / 2.75)) * t + 0.9375) + b;
          } else {
              return c * (7.5625 * (t -= (2.625 / 2.75)) * t + 0.984375) + b;
          }
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BOUNCE_EASEIN: function(t, b, c, d) {
          return c - enchant.Easing.BOUNCE_EASEOUT(d - t, 0, c, d) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BOUNCE_EASEINOUT: function(t, b, c, d) {
          if (t < d / 2) {
              return enchant.Easing.BOUNCE_EASEIN(t * 2, 0, c, d) * 0.5 + b;
          } else {
              return enchant.Easing.BOUNCE_EASEOUT(t * 2 - d, 0, c, d) * 0.5 + c * 0.5 + b;
          }
  
      },
      // back
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BACK_EASEIN: function(t, b, c, d, s) {
          if (s === undefined) {
              s = 1.70158;
          }
          return c * (t /= d) * t * ((s + 1) * t - s) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BACK_EASEOUT: function(t, b, c, d, s) {
          if (s === undefined) {
              s = 1.70158;
          }
          return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      BACK_EASEINOUT: function(t, b, c, d, s) {
          if (s === undefined) {
              s = 1.70158;
          }
          if ((t /= d / 2) < 1) {
              return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
          }
          return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
      },
      // expo
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      EXPO_EASEIN: function(t, b, c, d) {
          return (t === 0) ? b : c * Math.pow(2, 10 * (t / d - 1)) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      EXPO_EASEOUT: function(t, b, c, d) {
          return (t === d) ? b + c : c * (-Math.pow(2, -10 * t / d) + 1) + b;
      },
      

parameter: t
parameter: b
parameter: c
parameter: d
returns: {Number}

  
      EXPO_EASEINOUT: function(t, b, c, d) {
          if (t === 0) {
              return b;
          }
          if (t === d) {
              return b + c;
          }
          if ((t /= d / 2) < 1) {
              return c / 2 * Math.pow(2, 10 * (t - 1)) + b;
          }
          return c / 2 * (-Math.pow(2, -10 * --t) + 2) + b;
      }
  };
  
  
Easing Equations v2.0

  
  
  
@scope enchant.ActionEventTarget.prototype @type {*}

  
  enchant.ActionEventTarget = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.ActionEventTarget @class EventTarget which can change the context of event listeners @constructs @extends enchant.EventTarget

  
      initialize: function() {
          enchant.EventTarget.apply(this, arguments);
      },
      
Issue event.
parameter: {enchant.Event} e Event issued.

  
      dispatchEvent: function(e) {
          var target;
          if (this.node) {
              target = this.node;
              e.target = target;
              e.localX = e.x - target._offsetX;
              e.localY = e.y - target._offsetY;
          } else {
              this.node = null;
          }
  
          if (this['on' + e.type] != null) {
              this['on' + e.type].call(target, e);
          }
          var listeners = this._listeners[e.type];
          if (listeners != null) {
              listeners = listeners.slice();
              for (var i = 0, len = listeners.length; i < len; i++) {
                  listeners[i].call(target, e);
              }
          }
      }
  });
  
  
@scope enchant.Timeline.prototype

  
  enchant.Timeline = enchant.Class.create(enchant.EventTarget, {
      
@name enchant.Timeline @class Time-line class. Class for managing the action. For one node to manipulate the timeline of one must correspond.      * Reading a tl.enchant.js, all classes (Group, Scene, Entity, Label, Sprite) of the Node class that inherits      * Tlthe property, an instance of the Timeline class is generated.      * Time-line class has a method to add a variety of actions to himself,      * entities can be animated and various operations by using these briefly.      * You can choose time based and frame based(default) animation.
parameter: node target node
parameter: [unitialized] if this param is true, when add method called in the first time, enchant.Event.ENTER_FRAME event listener will be added to node (for reducing unused event listeners) @constructs

  
      initialize: function(node) {
          enchant.EventTarget.call(this);
          this.node = node;
          this.queue = [];
          this.paused = false;
          this.looped = false;
          this.isFrameBased = true;
          this._parallel = null;
          this._activated = false;
          this.addEventListener(enchant.Event.ENTER_FRAME, this.tick);
      },
      
@private

  
      _deactivateTimeline: function() {
          if (this._activated) {
              this._activated = false;
              this.node.removeEventListener('enterframe', this._nodeEventListener);
          }
      },
      
@private

  
      _activateTimeline: function() {
          if (!this._activated && !this.paused) {
              this.node.addEventListener("enterframe", this._nodeEventListener);
              this._activated = true;
          }
      },
      

  
      setFrameBased: function() {
          this.isFrameBased = true;
      },
      

  
      setTimeBased: function() {
          this.isFrameBased = false;
      },
      

  
      next: function(remainingTime) {
          var e, action = this.queue.shift();
          e = new enchant.Event("actionend");
          e.timeline = this;
          action.dispatchEvent(e);
  
          if (this.queue.length === 0) {
              this._activated = false;
              this.node.removeEventListener('enterframe', this._nodeEventListener);
              return;
          }
  
          if (this.looped) {
              e = new enchant.Event("removedfromtimeline");
              e.timeline = this;
              action.dispatchEvent(e);
              action.frame = 0;
  
              this.add(action);
          } else {
              // remove after dispatching removedfromtimeline event
              e = new enchant.Event("removedfromtimeline");
              e.timeline = this;
              action.dispatchEvent(e);
          }
          if (remainingTime > 0 || (this.queue[0] && this.queue[0].time === 0)) {
              var event = new enchant.Event("enterframe");
              event.elapsed = remainingTime;
              this.dispatchEvent(event);
          }
      },
      

  
      tick: function(enterFrameEvent) {
          if (this.paused) {
              return;
          }
          if (this.queue.length > 0) {
              var action = this.queue[0];
              if (action.frame === 0) {
                  var f;
                  f = new enchant.Event("actionstart");
                  f.timeline = this;
                  action.dispatchEvent(f);
              }
  
              var e = new enchant.Event("actiontick");
              e.timeline = this;
              if (this.isFrameBased) {
                  e.elapsed = 1;
              } else {
                  e.elapsed = enterFrameEvent.elapsed;
              }
              action.dispatchEvent(e);
          }
      },
      add: function(action) {
          if (!this._activated) {
              var tl = this;
              this._nodeEventListener = function(e) {
                  tl.dispatchEvent(e);
              };
              this.node.addEventListener("enterframe", this._nodeEventListener);
  
              this._activated = true;
          }
          if (this._parallel) {
              this._parallel.actions.push(action);
              this._parallel = null;
          } else {
              this.queue.push(action);
          }
          action.frame = 0;
  
          var e = new enchant.Event("addedtotimeline");
          e.timeline = this;
          action.dispatchEvent(e);
  
          e = new enchant.Event("actionadded");
          e.action = action;
          this.dispatchEvent(e);
  
          return this;
      },
      

  
      action: function(params) {
          return this.add(new enchant.Action(params));
      },
      

  
      tween: function(params) {
          return this.add(new enchant.Tween(params));
      },
      

  
      clear: function() {
          var e = new enchant.Event("removedfromtimeline");
          e.timeline = this;
  
          for (var i = 0, len = this.queue.length; i < len; i++) {
              this.queue[i].dispatchEvent(e);
          }
          this.queue = [];
          this._deactivateTimeline();
          return this;
      },
      

  
      skip: function(frames) {
          var event = new enchant.Event("enterframe");
          if (this.isFrameBased) {
              event.elapsed = 1;
          } else {
              event.elapsed = frames;
              frames = 1;
          }
          while (frames--) {
              this.dispatchEvent(event);
          }
          return this;
      },
      

  
      pause: function() {
          if (!this.paused) {
              this.paused = true;
              this._deactivateTimeline();
          }
          return this;
      },
      

  
      resume: function() {
          if (this.paused) {
              this.paused = false;
              this._activateTimeline();
          }
          return this;
      },
      

  
      loop: function() {
          this.looped = true;
          return this;
      },
      

  
      unloop: function() {
          this.looped = false;
          return this;
      },
      

  
      delay: function(time) {
          this.add(new enchant.Action({
              time: time
          }));
          return this;
      },
      

  
      wait: function(time) {
          // reserved
          return this;
      },
      

  
      then: function(func) {
          var timeline = this;
          this.add(new enchant.Action({
              onactiontick: function(evt) {
                  func.call(timeline.node);
              },
              // if time is 0, next action will be immediately executed
              time: 0
          }));
          return this;
      },
      

  
      exec: function(func) {
          this.then(func);
      },
      

  
      cue: function(cue) {
          var ptr = 0;
          for (var frame in cue) {
              if (cue.hasOwnProperty(frame)) {
                  this.delay(frame - ptr);
                  this.then(cue[frame]);
                  ptr = frame;
              }
          }
      },
      

  
      repeat: function(func, time) {
          this.add(new enchant.Action({
              onactiontick: function(evt) {
                  func.call(this);
              },
              time: time
          }));
          return this;
      },
      

  
      and: function() {
          var last = this.queue.pop();
          if (last instanceof enchant.ParallelAction) {
              this._parallel = last;
              this.queue.push(last);
          } else {
              var parallel = new enchant.ParallelAction();
              parallel.actions.push(last);
              this.queue.push(parallel);
              this._parallel = parallel;
          }
          return this;
      },
      
@ignore

  
      or: function() {
          return this;
      },
      
@ignore

  
      doAll: function(children) {
          return this;
      },
      
@ignore

  
      waitAll: function() {
          return this;
      },
      

  
      waitUntil: function(func) {
          var timeline = this;
          this.add(new enchant.Action({
              onactionstart: func,
              onactiontick: function(evt) {
                  if (func.call(this)) {
                      timeline.next();
                  }
              }
          }));
          return this;
      },
      

  
      fadeTo: function(opacity, time, easing) {
          this.tween({
              opacity: opacity,
              time: time,
              easing: easing
          });
          return this;
      },
      

  
      fadeIn: function(time, easing) {
          return this.fadeTo(1, time, easing);
      },
      

  
      fadeOut: function(time, easing) {
          return this.fadeTo(0, time, easing);
      },
      

  
      moveTo: function(x, y, time, easing) {
          return this.tween({
              x: x,
              y: y,
              time: time,
              easing: easing
          });
      },
      

  
      moveX: function(x, time, easing) {
          return this.tween({
              x: x,
              time: time,
              easing: easing
          });
      },
      

  
      moveY: function(y, time, easing) {
          return this.tween({
              y: y,
              time: time,
              easing: easing
          });
      },
      

  
      moveBy: function(x, y, time, easing) {
          return this.tween({
              x: function() {
                  return this.x + x;
              },
              y: function() {
                  return this.y + y;
              },
              time: time,
              easing: easing
          });
      },
      

  
      hide: function() {
          return this.then(function() {
              this.opacity = 0;
          });
      },
      

  
      show: function() {
          return this.then(function() {
              this.opacity = 1;
          });
      },
      

  
      removeFromScene: function() {
          return this.then(function() {
              this.scene.removeChild(this);
          });
      },
      

  
      scaleTo: function(scale, time, easing) {
          if (typeof easing === "number") {
              return this.tween({
                  scaleX: arguments[0],
                  scaleY: arguments[1],
                  time: arguments[2],
                  easing: arguments[3]
              });
          }
          return this.tween({
              scaleX: scale,
              scaleY: scale,
              time: time,
              easing: easing
          });
      },
      

  
      scaleBy: function(scale, time, easing) {
          if (typeof easing === "number") {
              return this.tween({
                  scaleX: function() {
                      return this.scaleX * arguments[0];
                  },
                  scaleY: function() {
                      return this.scaleY * arguments[1];
                  },
                  time: arguments[2],
                  easing: arguments[3]
              });
          }
          return this.tween({
              scaleX: function() {
                  return this.scaleX * scale;
              },
              scaleY: function() {
                  return this.scaleY * scale;
              },
              time: time,
              easing: easing
          });
      },
      

  
      rotateTo: function(deg, time, easing) {
          return this.tween({
              rotation: deg,
              time: time,
              easing: easing
          });
      },
      

  
      rotateBy: function(deg, time, easing) {
          return this.tween({
              rotation: function() {
                  return this.rotation + deg;
              },
              time: time,
              easing: easing
          });
      }
  });
  
  
@scope enchant.Action.prototype @type {*}

  
  
  enchant.Action = enchant.Class.create(enchant.ActionEventTarget, {
      
@name enchant.Action @class Action class.      * Actions are units that make up the time line,      * It is a unit used to specify the action you want to perform.      * Action has been added to the time line is performed in order.      *      * Actionstart, actiontick event is fired when the action is started and stopped,      * When one frame has elapsed actiontick event is also issued.      * Specify the action you want to perform as a listener for these events.     * The transition to the next action automatically the number of frames that are specified in the time has elapsed. @constructs
parameter: param @config {integer} [time] The number of frames that will last action. infinite length is specified null @config {function} [onactionstart] Event listener for when the action is initiated @config {function} [onactiontick] Event listener for when the action has passed one frame @config {function} [onactionend] Event listener for when the action is finished @constructs

  
      initialize: function(param) {
          enchant.ActionEventTarget.call(this);
          this.time = null;
          this.frame = 0;
          for (var key in param) {
              if (param.hasOwnProperty(key)) {
                  if (param[key] != null) {
                      this[key] = param[key];
                  }
              }
          }
          var action = this;
  
          this.timeline = null;
          this.node = null;
  
          this.addEventListener(enchant.Event.ADDED_TO_TIMELINE, function(evt) {
              action.timeline = evt.timeline;
              action.node = evt.timeline.node;
              action.frame = 0;
          });
  
          this.addEventListener(enchant.Event.REMOVED_FROM_TIMELINE, function() {
              action.timeline = null;
              action.node = null;
              action.frame = 0;
          });
  
          this.addEventListener(enchant.Event.ACTION_TICK, function(evt) {
              var remaining = action.time - (action.frame + evt.elapsed);
              if (action.time != null && remaining <= 0) {
                  action.frame = action.time;
                  evt.timeline.next(-remaining);
              } else {
                  action.frame += evt.elapsed;
              }
          });
  
      }
  });
  
  
@scope enchant.ParallelAction.prototype

  
  enchant.ParallelAction = enchant.Class.create(enchant.Action, {
      
@name enchant.ParallelAction @class @constructs @extends enchant.Action

  
      initialize: function(param) {
          enchant.Action.call(this, param);
          var timeline = this.timeline;
          var node = this.node;
          
Children Actions

  
          this.actions = [];
          
Removed actions

  
          this.endedActions = [];
          var that = this;
  
          this.addEventListener(enchant.Event.ACTION_START, function(evt) {
              for (var i = 0, len = that.actions.length; i < len; i++) {
                  that.actions[i].dispatchEvent(evt);
              }
          });
  
          this.addEventListener(enchant.Event.ACTION_TICK, function(evt) {
              var i, len, timeline = {
                  next: function(remaining) {
                      var action = that.actions[i];
                      that.actions.splice(i--, 1);
                      len = that.actions.length;
                      that.endedActions.push(action);
  
                      var e = new enchant.Event("actionend");
                      e.timeline = this;
                      action.dispatchEvent(e);
  
                      e = new enchant.Event("removedfromtimeline");
                      e.timeline = this;
                      action.dispatchEvent(e);
                  }
              };
  
              var e = new enchant.Event("actiontick");
              e.timeline = timeline;
              e.elapsed = evt.elapsed;
              for (i = 0, len = that.actions.length; i < len; i++) {
                  that.actions[i].dispatchEvent(e);
              }
  
              if (that.actions.length === 0) {
                  evt.timeline.next();
              }
          });
  
          this.addEventListener(enchant.Event.ADDED_TO_TIMELINE, function(evt) {
              for (var i = 0, len = that.actions.length; i < len; i++) {
                  that.actions[i].dispatchEvent(evt);
              }
          });
  
          this.addEventListener(enchant.Event.REMOVED_FROM_TIMELINE, function() {
              this.actions = this.endedActions;
              this.endedActions = [];
          });
  
      }
  });
  
  
@scope enchant.Tween.prototype

  
  enchant.Tween = enchant.Class.create(enchant.Action, {
      
@name enchant.Tween @class

  
      initialize: function(params) {
          var origin = {};
          var target = {};
          enchant.Action.call(this, params);
  
          if (this.easing == null) {
              // linear
              this.easing = function(t, b, c, d) {
                  return c * t / d + b;
              };
          }
  
          var tween = this;
          this.addEventListener(enchant.Event.ACTION_START, function() {
              // excepted property
              var excepted = ["frame", "time", "callback", "onactiontick", "onactionstart", "onactionend"];
              for (var prop in params) {
                  if (params.hasOwnProperty(prop)) {
                      // if function is used instead of numerical value, evaluate it
                      var target_val;
                      if (typeof params[prop] === "function") {
                          target_val = params[prop].call(tween.node);
                      } else {
                          target_val = params[prop];
                      }
  
                      if (excepted.indexOf(prop) === -1) {
                          origin[prop] = tween.node[prop];
                          target[prop] = target_val;
                      }
                  }
              }
          });
  
          this.addEventListener(enchant.Event.ACTION_TICK, function(evt) {
              // if time is 0, set property to target value immediately
              var ratio = tween.time === 0 ? 1 : tween.easing(Math.min(tween.time,tween.frame + evt.elapsed), 0, 1, tween.time) - tween.easing(tween.frame, 0, 1, tween.time);
  
              for (var prop in target){
                  if (target.hasOwnProperty(prop)) {
                      if (typeof this[prop] === "undefined"){
                          continue;
                      }
                      tween.node[prop] += (target[prop] - origin[prop]) * ratio;
                      if (Math.abs(tween.node[prop]) < 10e-8){
                          tween.node[prop] = 0;
                      }
                  }
              }
          });
      }
  });
  
  

  
  }(window));
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.