refactored and optimized Image.js and Type.js

This commit is contained in:
Eric Rowell
2013-03-24 13:12:33 -07:00
parent c8e83dfacb
commit ffe11a4539
3 changed files with 102 additions and 71 deletions

View File

@@ -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();
}

View File

@@ -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) {

View File

@@ -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);