From ffe11a4539b31c0b5df6234426b6620678d89680 Mon Sep 17 00:00:00 2001 From: Eric Rowell Date: Sun, 24 Mar 2013 13:12:33 -0700 Subject: [PATCH] refactored and optimized Image.js and Type.js --- src/Node.js | 2 +- src/shapes/Image.js | 120 +++++++++++++++++++++++++------------------- src/util/Type.js | 51 ++++++++++++------- 3 files changed, 102 insertions(+), 71 deletions(-) diff --git a/src/Node.js b/src/Node.js index cb261740..2f493692 100644 --- a/src/Node.js +++ b/src/Node.js @@ -154,7 +154,7 @@ go._removeName(this.getName(), this._id); // stop DD - if(dd && dd.targetNode && dd.targetNode._id === this._id) { + if(dd && dd.node && dd.node._id === this._id) { node._endDrag(); } diff --git a/src/shapes/Image.js b/src/shapes/Image.js index 7172dbbe..23005637 100644 --- a/src/shapes/Image.js +++ b/src/shapes/Image.js @@ -1,4 +1,8 @@ (function() { + // CONSTANTS + var IMAGE = 'Image', + CROP = 'crop'; + /** * Image constructor * @constructor @@ -15,38 +19,40 @@ Kinetic.Image.prototype = { _initImage: function(config) { + var that = this; + // call super constructor Kinetic.Shape.call(this, config); - this.shapeType = 'Image'; + this.shapeType = IMAGE; this._setDrawFuncs(); - - var that = this; - this.on('imageChange', function(evt) { - that._syncSize(); - }); - - this._syncSize(); }, drawFunc: function(canvas) { - var width = this.getWidth(), height = this.getHeight(), params, that = this, context = canvas.getContext(); + var width = this.getWidth(), + height = this.getHeight(), + params, + that = this, + context = canvas.getContext(), + image = this.getImage(), + crop = this.getCrop(), + cropX, cropY, cropWidth, cropHeight; context.beginPath(); context.rect(0, 0, width, height); context.closePath(); canvas.fillStroke(this); - if(this.attrs.image) { + if(image) { // if cropping - if(this.attrs.crop && this.attrs.crop.width && this.attrs.crop.height) { - var cropX = this.attrs.crop.x || 0; - var cropY = this.attrs.crop.y || 0; - var cropWidth = this.attrs.crop.width; - var cropHeight = this.attrs.crop.height; - params = [this.attrs.image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height]; + if(crop) { + cropX = crop.x || 0; + cropY = crop.y || 0; + cropWidth = crop.width || 0; + cropHeight = crop.height || 0; + params = [image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height]; } // no cropping else { - params = [this.attrs.image, 0, 0, width, height]; + params = [image, 0, 0, width, height]; } if(this.hasShadow()) { @@ -57,12 +63,13 @@ else { this._drawImage(context, params); } - } - }, drawHitFunc: function(canvas) { - var width = this.getWidth(), height = this.getHeight(), imageHitRegion = this.imageHitRegion, appliedShadow = false, context = canvas.getContext(); + var width = this.getWidth(), + height = this.getHeight(), + imageHitRegion = this.imageHitRegion, + context = canvas.getContext(); if(imageHitRegion) { context.drawImage(imageHitRegion, 0, 0, width, height); @@ -89,16 +96,17 @@ * filter has been applied */ applyFilter: function(filter, config, callback) { - var canvas = new Kinetic.Canvas(this.attrs.image.width, this.attrs.image.height); - var context = canvas.getContext(); - context.drawImage(this.attrs.image, 0, 0); + var image = this.getImage(), + canvas = new Kinetic.Canvas(image.width, image.height), + context = canvas.getContext(), + that = this; + + context.drawImage(image, 0, 0); try { var imageData = context.getImageData(0, 0, canvas.getWidth(), canvas.getHeight()); filter(imageData, config); - var that = this; Kinetic.Type._getImage(imageData, function(imageObj) { that.setImage(imageObj); - if(callback) { callback(); } @@ -119,11 +127,12 @@ * @param {Number} config.height */ setCrop: function() { - var config = [].slice.call(arguments); - var pos = Kinetic.Type._getXY(config); - var size = Kinetic.Type._getSize(config); - var both = Kinetic.Type._merge(pos, size); - this.setAttr('crop', Kinetic.Type._merge(both, this.getCrop())); + var config = [].slice.call(arguments), + pos = Kinetic.Type._getXY(config), + size = Kinetic.Type._getSize(config), + both = Kinetic.Type._merge(pos, size); + + this.setAttr(CROP, Kinetic.Type._merge(both, this.getCrop())); }, /** * create image hit region which enables more accurate hit detection mapping of the image @@ -134,22 +143,33 @@ * the image hit region has been created */ createImageHitRegion: function(callback) { - var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height); - var context = canvas.getContext(); - context.drawImage(this.attrs.image, 0, 0); + var that = this, + width = this.getWidth(), + height = this.getHeight(), + canvas = new Kinetic.Canvas({ + width: width, + height: height + }), + context = canvas.getContext(), + image = this.getImage(), + imageData, data, rgbColorKey, i, n; + + context.drawImage(image, 0, 0); + try { - var imageData = context.getImageData(0, 0, canvas.getWidth(), canvas.getHeight()); - var data = imageData.data; - var rgbColorKey = Kinetic.Type._hexToRgb(this.colorKey); + imageData = context.getImageData(0, 0, width, height); + data = imageData.data; + rgbColorKey = Kinetic.Type._hexToRgb(this.colorKey); + // replace non transparent pixels with color key - for(var i = 0, n = data.length; i < n; i += 4) { - data[i] = rgbColorKey.r; - data[i + 1] = rgbColorKey.g; - data[i + 2] = rgbColorKey.b; - // i+3 is alpha (the fourth element) + for(i = 0, n = data.length; i < n; i += 4) { + if (data[i + 3] > 0) { + data[i] = rgbColorKey.r; + data[i + 1] = rgbColorKey.g; + data[i + 2] = rgbColorKey.b; + } } - var that = this; Kinetic.Type._getImage(imageData, function(imageObj) { that.imageHitRegion = imageObj; if(callback) { @@ -169,15 +189,13 @@ clearImageHitRegion: function() { delete this.imageHitRegion; }, - _syncSize: function() { - if(this.attrs.image) { - if(!this.attrs.width) { - this.setWidth(this.attrs.image.width); - } - if(!this.attrs.height) { - this.setHeight(this.attrs.image.height); - } - } + getWidth: function() { + var image = this.getImage(); + return this.attrs.width || image.width || 0; + }, + getHeight: function() { + var image = this.getImage(); + return this.attrs.height || image.height || 0; }, _drawImage: function(context, a) { if(a.length === 5) { diff --git a/src/util/Type.js b/src/util/Type.js index ff584759..41c48ff1 100644 --- a/src/util/Type.js +++ b/src/util/Type.js @@ -1,4 +1,13 @@ (function() { + // CONSTANTS + var CANVAS = 'canvas', + CONTEXT_2D = '2d', + OBJECT_ARRAY = '[object Array]', + OBJECT_NUMBER = '[object Number]', + OBJECT_STRING = '[object String]', + PI_OVER_DEG180 = Math.PI / 180, + DEG180_OVER_PI = 180 / Math.PI; + /* * utilities that handle data type detection, conversion, and manipulation */ @@ -16,27 +25,30 @@ return (!!obj && obj.constructor == Object); }, _isArray: function(obj) { - return Object.prototype.toString.call(obj) == '[object Array]'; + return Object.prototype.toString.call(obj) == OBJECT_ARRAY; }, _isNumber: function(obj) { - return Object.prototype.toString.call(obj) == '[object Number]'; + return Object.prototype.toString.call(obj) == OBJECT_NUMBER; }, _isString: function(obj) { - return Object.prototype.toString.call(obj) == '[object String]'; + return Object.prototype.toString.call(obj) == OBJECT_STRING; }, /* * other utils */ _hasMethods: function(obj) { - var names = []; - for(var key in obj) { - if(this._isFunction(obj[key])) + var names = [], + key; + + for(key in obj) { + if(this._isFunction(obj[key])) { names.push(key); + } } return names.length > 0; }, _isInDocument: function(el) { - while( el = el.parentNode) { + while(el = el.parentNode) { if(el == document) { return true; } @@ -229,6 +241,8 @@ * arg can be an image object or image data */ _getImage: function(arg, callback) { + var imageObj, canvas, context, dataUrl; + // if arg is null or undefined if(!arg) { callback(null); @@ -241,8 +255,7 @@ // if arg is a string, then it's a data url else if(this._isString(arg)) { - var imageObj = new Image(); - /** @ignore */ + imageObj = new Image(); imageObj.onload = function() { callback(imageObj); } @@ -251,14 +264,13 @@ //if arg is an object that contains the data property, it's an image object else if(arg.data) { - var canvas = document.createElement('canvas'); + canvas = document.createElement(CANVAS); canvas.width = arg.width; canvas.height = arg.height; - var context = canvas.getContext('2d'); + context = canvas.getContext(CONTEXT_2D); context.putImageData(arg, 0, 0); - var dataUrl = canvas.toDataURL(); - var imageObj = new Image(); - /** @ignore */ + dataUrl = canvas.toDataURL(); + imageObj = new Image(); imageObj.onload = function() { callback(imageObj); } @@ -280,9 +292,10 @@ }; }, _getRandomColorKey: function() { - var r = (Math.random() * 255) | 0; - var g = (Math.random() * 255) | 0; - var b = (Math.random() * 255) | 0; + var r = (Math.random() * 255) | 0, + g = (Math.random() * 255) | 0, + b = (Math.random() * 255) | 0; + return this._rgbToHex(r, g, b); }, // o1 takes precedence over o2 @@ -312,10 +325,10 @@ return retObj; }, _degToRad: function(deg) { - return deg * Math.PI / 180; + return deg * PI_OVER_DEG180; }, _radToDeg: function(rad) { - return rad * 180 / Math.PI; + return rad * DEG180_OVER_PI; }, _capitalize: function(str) { return str.charAt(0).toUpperCase() + str.slice(1);