Show:

File: src\node\class.node.image.js

/*
 * Copyright (c) 2012  Capgemini Technology Services (hereinafter “Capgemini”)
 *
 * License/Terms of Use
 *
 * Permission is hereby granted, free of charge and for the term of intellectual property rights on the Software, to any
 * person obtaining a copy of this software and associated documentation files (the "Software"), to use, copy, modify
 * and propagate free of charge, anywhere in the world, all or part of the Software subject to the following mandatory conditions:
 *
 *   •    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
 *
 *  Any failure to comply with the above shall automatically terminate the license and be construed as a breach of these
 *  Terms of Use causing significant harm to Capgemini.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 *  WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
 *  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 *  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 *  Except as contained in this notice, the name of Capgemini shall not be used in advertising or otherwise to promote
 *  the use or other dealings in this Software without prior written authorization from Capgemini.
 *
 *  These Terms of Use are subject to French law.
 */

/**
 * A CGSGNodeImage represent an image node
 *
 * @class CGSGNodeImage
 * @extends CGSGNode
 * @module Node
 * @constructor
 * @param {Number} x Relative position on X
 * @param {Number} y Relative position on X
 * @param {String} urlImage URL of the src image. Can be null tobe loaded later.
 * @type {CGSGNodeImage}
 * @author Gwennael Buchet (gwennael.buchet@gmail.com)
 */
var CGSGNodeImage = CGSGNode.extend(
	{
		initialize: function (x, y, urlImage) {
			this._super(x, y, 0, 0);

			/**
			 * @property classType
			 * @type {String}
			 */
			this.classType = "CGSGNodeImage";

			/**
			 * the selected effect to be applied
			 * @property effect
			 * @default null
			 * @type {CGSGEffect}
			 */
			this.effect = null;
			/**
			 * URL of the image
			 * @property _urlImage
			 * @type {String}
			 * @private
			 */
			this._urlImage = urlImage;

			/**
			 * @property isProportionalResize
			 * @default true
			 * @type {Boolean}
			 */
			this.isProportionalResize = true;
			/**
			 * the image object itself
			 * @property _img
			 * @type {Image}
			 * @private
			 */
			this._img = new Image();
			/**
			 * the region on the image to render
			 * @property slice
			 * @type {CGSGRegion}
			 */
			this.slice = new CGSGRegion(0, 0, 0, 0);

			/**
			 * @property _isLoaded
			 * @type {Boolean}
			 * @private
			 */
			this.isLoaded = false;

			/**
			 * Event Fired when the image is finally loaded
			 * @property onLoadEnd
			 * @default null
			 * @type {Function}
			 */
			this.onLoadEnd = null;
			/**
			 * Event Fired when the image failed to load
			 * @property onLoadError
			 * @default null
			 * @type {Function}
			 */
			this.onLoadError = null;
			/**
			 * Event Fired when the image loading is aborted
			 * @property onLoadAbort
			 * @default null
			 * @type {Function}
			 */
			this.onLoadAbort = null;

			///// INITIALIZATION //////
			//finally load the image
			if (cgsgExist(this._urlImage) && this._urlImage != "") {
				this.setURL(urlImage);
			}
		},

		/**
		 * used to call delegate method when the image is finally loaded
		 * @private
		 * @method _createDelegate
		 * @param objectContext
		 * @param delegateMethod
		 * @return {Function}
		 */
		_createDelegate: function (objectContext, delegateMethod) {
			return function () {
				return delegateMethod.call(objectContext);
			}
		},

		/**
		 * fired when the image is loaded.
		 * Check the dimension of the image and fired the onLoadEnd event
		 * @private
		 * @method _onImageLoaded
		 */
		_onImageLoaded: function () {
			this._checkDimension();
			this.isLoaded = true;

			if (this.onLoadEnd !== null) {
				this.onLoadEnd();
			}
		},

		/**
		 * To be overrided when the image failed to load
		 * @method _onImageError
		 * @protected
		 */
		_onImageError: function () {
			if (this.onLoadError !== null) {
				this.onLoadError();
			}
		},
		/**
		 * To be overrided when the image loading is aborted
		 * @method _onImageAbort
		 * @protected
		 */
		_onImageAbort: function () {
			if (this.onLoadAbort !== null) {
				this.onLoadAbort();
			}
		},

		/**
		 * Check the true dimension of the image and fill the this.dimension property with it,
		 * only if dimension is not already defined in the constructor
		 * @private
		 * @method _checkDimension
		 */
		_checkDimension: function () {
			//if no width or height are specified in the constructor
			if (this.dimension.width <= 0 && this.dimension.height <= 0) {
				this.dimension.width = this._img.width;
				this.dimension.height = this._img.height;
			}

			//if no slice was specified, adjust it with the full image
			if (this.slice.dimension.width <= 0 || this.slice.dimension.height <= 0) {
				this.slice.dimension.width = this.dimension.width;
				this.slice.dimension.height = this.dimension.height;
			}
		},

		/**
		 * Set the slice into the image
		 * @method setSlice
		 * @param {Number} x
		 * @param {Number} y
		 * @param {Number} w
		 * @param {Number} h
		 * @param {Boolean} updateDimension If true, the dimension will be set with the dimension of the slice
		 */
		setSlice: function (x, y, w, h, updateDimension) {
			this.slice.position.x = x;
			this.slice.position.y = y;
			this.slice.dimension.width = w;
			this.slice.dimension.height = h;

			if (updateDimension) {
				this.resizeTo(w, h);
			}
		},

		/**
		 * @public
		 * @method setImage
		 * @param {Image} newImage new Image object. Must bea already loaded before
		 */
		setImage: function (newImage) {
			this._img = newImage;
			if (cgsgExist(this._img)) {
				this._urlImage = this._img.src;
				this._checkDimension();
				this.isLoaded = true;
			}
		},

		/**
		 * Set a new URL for the image of the node
		 * @method setURL
		 * @param {String} url
		 */
		setURL: function (url) {
			this._urlImage = url;

			delete(this._img);
			this.isLoaded = false;
			this._img = new Image();

			this._img.onload = this._createDelegate(this, this._onImageLoaded);
			this._img.onerror = this._createDelegate(this, this._onImageError);
			this._img.onabort = this._createDelegate(this, this._onImageAbort);
			this._img.src = this._urlImage;
		},

		/**
		 * Must be defined to allow the scene graph to render the image nodes
		 * @protected
		 * @method render
		 * @param {CanvasRenderingContext2D} context the context to render on
		 * */
		render: function (context) {
			if (this.isLoaded && this._img.src != "") {
				//save current state
				this.beforeRender(context);

				context.globalAlpha = this.globalAlpha;

				context.drawImage(
					this._img, // image
					this.slice.position.x, this.slice.position.y, // start position on the image
					this.slice.dimension.width, this.slice.dimension.height, // dimension on the image
					0, 0,
					// position on the screen. let it to [0,0] because the 'beforeRender' function will translate the image
					this.getWidth(), this.getHeight()                // dimension on the screen
				);
				//restore state
				this.afterRender(context);
			}
		},

		/**
		 * @public
		 * @method setEffect
		 * @param {CGSGEffect} effect
		 */
		setEffect: function (effect) {
			this.effect = effect;
		},

		/**
		 * Ghost rendering function.
		 * Render here your custom nodes with a single color (cgsgGhostColor).
		 * This will be used by the SceneGraph to know if the mouse cursor is over this nodes.
		 * @protected
		 * @method renderGhost
		 * @param {CanvasRenderingContext2D} ghostContext The context for the ghost rendering
		 */
		renderGhost: function (ghostContext) {
			if (this.isLoaded && this._img.src != "") {
				//save current state
				this.beforeRenderGhost(ghostContext);

				ghostContext.drawImage(
					this._img, // image
					this.slice.position.x, this.slice.position.y, // start position on the image
					this.slice.dimension.width, this.slice.dimension.height, // dimension on the image
					0, 0,
					// position on the screen. let it to [0,0] because the 'beforeRender' function will tanslate the image
					this.getWidth(), this.getHeight()                // dimension on the screen
				);

				//restore state
				this.afterRenderGhost(ghostContext);
			}
		},

		/**
		 * Increase/decrease current dimension with adding values. It is used when the user resize
		 * the image with the handle boxes
		 * @public
		 * @method resizeWith
		 * @param {Number} width
		 * @param {Number} height
		 * */
		resizeWith: function (width, height) {
			this._super(width, height);
			//this._initShape();
		},

		/**
		 * @public
		 * @method copy
		 * @return {CGSGNodeImage} a copy of this node
		 */
		copy: function (node) {
			if (!cgsgExist(node)) {
				node = new CGSGNodeImage(this.position.x, this.position.y, null);
			}
			//call the super method
			node = this._super(node);

			node._urlImage = this._urlImage;

			node.effect = this.effect;
			node.isProportionalResize = this.isProportionalResize;
			node._isLoaded = this.isLoaded;

			//the image object itself
			node.setImage(this._img);

			node.setSlice(this.slice.position.x, this.slice.position.y, this.slice.dimension.width,
						  this.slice.dimension.height, true);
			node.resizeTo(this.dimension.width, this.dimension.height);

			node.onLoadEnd = this.onLoadEnd;
			/*if (this.urlImage !== undefined && this.urlImage !== null && this.urlImage != "") {
			 node.img.onload = node.createDelegate(node, node._onImageLoaded, node.context);
			 //this.img.onload = this._onImageLoaded(context);
			 node.img.src = node.urlImage;
			 }*/

			return node;
		}
	}
);