2012-12-02 04:04:10 +08:00
|
|
|
(function() {
|
2013-03-25 04:12:33 +08:00
|
|
|
// CONSTANTS
|
|
|
|
var IMAGE = 'Image',
|
2013-05-04 15:40:46 +08:00
|
|
|
CROP = 'crop',
|
|
|
|
SET = 'set';
|
2013-03-25 04:12:33 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
/**
|
|
|
|
* Image constructor
|
|
|
|
* @constructor
|
|
|
|
* @augments Kinetic.Shape
|
|
|
|
* @param {Object} config
|
|
|
|
* @param {ImageObject} config.image
|
|
|
|
* @param {Object} [config.crop]
|
2013-01-27 12:42:19 +08:00
|
|
|
* {{ShapeParams}}
|
|
|
|
* {{NodeParams}}
|
2012-12-02 04:04:10 +08:00
|
|
|
*/
|
|
|
|
Kinetic.Image = function(config) {
|
|
|
|
this._initImage(config);
|
|
|
|
};
|
2012-11-29 12:50:33 +08:00
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
Kinetic.Image.prototype = {
|
|
|
|
_initImage: function(config) {
|
2013-03-25 04:12:33 +08:00
|
|
|
var that = this;
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
// call super constructor
|
|
|
|
Kinetic.Shape.call(this, config);
|
2013-03-25 04:12:33 +08:00
|
|
|
this.shapeType = IMAGE;
|
2012-12-02 04:04:10 +08:00
|
|
|
this._setDrawFuncs();
|
|
|
|
},
|
2012-12-10 01:52:33 +08:00
|
|
|
drawFunc: function(canvas) {
|
2013-03-25 04:12:33 +08:00
|
|
|
var width = this.getWidth(),
|
|
|
|
height = this.getHeight(),
|
|
|
|
params,
|
|
|
|
that = this,
|
|
|
|
context = canvas.getContext(),
|
|
|
|
crop = this.getCrop(),
|
2013-05-04 15:40:46 +08:00
|
|
|
cropX, cropY, cropWidth, cropHeight, image;
|
2013-05-01 13:28:05 +08:00
|
|
|
|
2013-05-04 15:40:46 +08:00
|
|
|
// if a filter is set, and the filter needs to be updated, reapply
|
|
|
|
if (this.getFilter() && this._applyFilter) {
|
|
|
|
this.applyFilter();
|
|
|
|
this._applyFilter = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: this.filterCanvas may be set by the above code block
|
|
|
|
if (this.filterCanvas) {
|
|
|
|
image = this.filterCanvas.getElement();
|
2013-05-01 13:28:05 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
image = this.getImage();
|
|
|
|
}
|
2012-11-29 12:50:33 +08:00
|
|
|
|
2012-11-24 15:55:20 +08:00
|
|
|
context.beginPath();
|
|
|
|
context.rect(0, 0, width, height);
|
|
|
|
context.closePath();
|
2012-12-10 01:52:33 +08:00
|
|
|
canvas.fillStroke(this);
|
2012-07-17 15:32:26 +08:00
|
|
|
|
2013-03-25 04:12:33 +08:00
|
|
|
if(image) {
|
2012-12-02 04:04:10 +08:00
|
|
|
// if cropping
|
2013-03-25 04:12:33 +08:00
|
|
|
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];
|
2012-07-17 15:32:26 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
// no cropping
|
|
|
|
else {
|
2013-03-25 04:12:33 +08:00
|
|
|
params = [image, 0, 0, width, height];
|
2012-12-02 04:04:10 +08:00
|
|
|
}
|
|
|
|
|
2012-12-31 16:45:38 +08:00
|
|
|
if(this.hasShadow()) {
|
2012-12-10 01:52:33 +08:00
|
|
|
canvas.applyShadow(this, function() {
|
|
|
|
that._drawImage(context, params);
|
2012-12-02 04:04:10 +08:00
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
2012-12-10 01:52:33 +08:00
|
|
|
this._drawImage(context, params);
|
2012-12-02 04:04:10 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2012-12-10 01:52:33 +08:00
|
|
|
drawHitFunc: function(canvas) {
|
2013-03-25 04:12:33 +08:00
|
|
|
var width = this.getWidth(),
|
|
|
|
height = this.getHeight(),
|
|
|
|
imageHitRegion = this.imageHitRegion,
|
|
|
|
context = canvas.getContext();
|
2012-12-02 04:04:10 +08:00
|
|
|
|
|
|
|
if(imageHitRegion) {
|
2012-12-10 01:52:33 +08:00
|
|
|
context.drawImage(imageHitRegion, 0, 0, width, height);
|
2012-12-02 04:04:10 +08:00
|
|
|
context.beginPath();
|
|
|
|
context.rect(0, 0, width, height);
|
|
|
|
context.closePath();
|
2012-12-10 01:52:33 +08:00
|
|
|
canvas.stroke(this);
|
2012-12-02 04:04:10 +08:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
context.beginPath();
|
|
|
|
context.rect(0, 0, width, height);
|
|
|
|
context.closePath();
|
2012-12-10 01:52:33 +08:00
|
|
|
canvas.fillStroke(this);
|
2012-12-02 04:04:10 +08:00
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* apply filter
|
|
|
|
* @name applyFilter
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
2013-05-04 15:40:46 +08:00
|
|
|
applyFilter: function() {
|
2013-03-25 04:12:33 +08:00
|
|
|
var image = this.getImage(),
|
2013-05-01 13:28:05 +08:00
|
|
|
that = this,
|
|
|
|
width = this.getWidth(),
|
|
|
|
height = this.getHeight(),
|
2013-05-04 15:40:46 +08:00
|
|
|
filter = this.getFilter(),
|
2013-05-01 13:28:05 +08:00
|
|
|
filterCanvas, context, imageData;
|
|
|
|
|
|
|
|
if (this.filterCanvas){
|
|
|
|
filterCanvas = this.filterCanvas;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
filterCanvas = this.filterCanvas = new Kinetic.SceneCanvas({
|
|
|
|
width: width,
|
|
|
|
height: height
|
2012-12-02 04:04:10 +08:00
|
|
|
});
|
|
|
|
}
|
2013-05-01 13:28:05 +08:00
|
|
|
|
|
|
|
context = filterCanvas.getContext();
|
|
|
|
|
|
|
|
try {
|
|
|
|
this._drawImage(context, [image, 0, 0, width, height]);
|
|
|
|
imageData = context.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight());
|
2013-05-04 15:40:46 +08:00
|
|
|
filter.call(this, imageData);
|
2013-05-01 13:28:05 +08:00
|
|
|
context.putImageData(imageData, 0, 0);
|
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
catch(e) {
|
2013-05-01 13:28:05 +08:00
|
|
|
this.clearFilter();
|
2012-12-02 04:04:10 +08:00
|
|
|
Kinetic.Global.warn('Unable to apply filter. ' + e.message);
|
|
|
|
}
|
|
|
|
},
|
2013-05-01 13:28:05 +08:00
|
|
|
/**
|
|
|
|
* clear filter
|
|
|
|
* @name clearFilter
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
|
|
|
clearFilter: function() {
|
|
|
|
this.filterCanvas = null;
|
2013-05-04 15:40:46 +08:00
|
|
|
this._applyFilter = false;
|
2013-05-01 13:28:05 +08:00
|
|
|
},
|
2012-12-02 04:04:10 +08:00
|
|
|
/**
|
|
|
|
* set crop
|
|
|
|
* @name setCrop
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
* @param {Object|Array} config
|
|
|
|
* @param {Number} config.x
|
|
|
|
* @param {Number} config.y
|
|
|
|
* @param {Number} config.width
|
|
|
|
* @param {Number} config.height
|
|
|
|
*/
|
|
|
|
setCrop: function() {
|
2013-03-25 04:12:33 +08:00
|
|
|
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()));
|
2012-12-02 04:04:10 +08:00
|
|
|
},
|
|
|
|
/**
|
|
|
|
* create image hit region which enables more accurate hit detection mapping of the image
|
|
|
|
* by avoiding event detections for transparent pixels
|
|
|
|
* @name createImageHitRegion
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
* @param {Function} [callback] callback function to be called once
|
|
|
|
* the image hit region has been created
|
|
|
|
*/
|
|
|
|
createImageHitRegion: function(callback) {
|
2013-03-25 04:12:33 +08:00
|
|
|
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);
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
try {
|
2013-03-25 04:12:33 +08:00
|
|
|
imageData = context.getImageData(0, 0, width, height);
|
|
|
|
data = imageData.data;
|
|
|
|
rgbColorKey = Kinetic.Type._hexToRgb(this.colorKey);
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
// replace non transparent pixels with color key
|
2013-03-25 04:12:33 +08:00
|
|
|
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;
|
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Kinetic.Type._getImage(imageData, function(imageObj) {
|
|
|
|
that.imageHitRegion = imageObj;
|
|
|
|
if(callback) {
|
|
|
|
callback();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
Kinetic.Global.warn('Unable to create image hit region. ' + e.message);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* clear image hit region
|
|
|
|
* @name clearImageHitRegion
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
|
|
|
clearImageHitRegion: function() {
|
|
|
|
delete this.imageHitRegion;
|
|
|
|
},
|
2013-03-25 04:12:33 +08:00
|
|
|
getWidth: function() {
|
2013-03-25 07:30:43 +08:00
|
|
|
var image = this.getImage();
|
|
|
|
return this.attrs.width || (image ? image.width : 0);
|
2013-03-25 04:12:33 +08:00
|
|
|
},
|
|
|
|
getHeight: function() {
|
|
|
|
var image = this.getImage();
|
2013-03-25 07:30:43 +08:00
|
|
|
return this.attrs.height || (image ? image.height : 0);
|
2012-12-10 01:52:33 +08:00
|
|
|
},
|
|
|
|
_drawImage: function(context, a) {
|
|
|
|
if(a.length === 5) {
|
|
|
|
context.drawImage(a[0], a[1], a[2], a[3], a[4]);
|
|
|
|
}
|
|
|
|
else if(a.length === 9) {
|
|
|
|
context.drawImage(a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8]);
|
|
|
|
}
|
2012-07-17 15:32:26 +08:00
|
|
|
}
|
2012-12-02 04:04:10 +08:00
|
|
|
};
|
|
|
|
Kinetic.Global.extend(Kinetic.Image, Kinetic.Shape);
|
|
|
|
|
2013-05-04 15:40:46 +08:00
|
|
|
|
|
|
|
Kinetic.Node.addFilterGetterSetter = function(constructor, attr, def) {
|
|
|
|
this.addGetter(constructor, attr, def);
|
|
|
|
this.addFilterSetter(constructor, attr);
|
|
|
|
};
|
|
|
|
|
|
|
|
Kinetic.Node.addFilterSetter = function(constructor, attr) {
|
|
|
|
var that = this,
|
|
|
|
method = SET + Kinetic.Type._capitalize(attr);
|
|
|
|
|
|
|
|
constructor.prototype[method] = function(val) {
|
|
|
|
this.setAttr(attr, val);
|
|
|
|
this._applyFilter = true;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
2012-12-02 04:04:10 +08:00
|
|
|
// add getters setters
|
2013-03-15 23:33:05 +08:00
|
|
|
Kinetic.Node.addGetterSetter(Kinetic.Image, 'image');
|
2012-12-02 04:04:10 +08:00
|
|
|
|
2012-09-25 11:34:23 +08:00
|
|
|
/**
|
2012-12-02 04:04:10 +08:00
|
|
|
* set image
|
|
|
|
* @name setImage
|
2012-09-25 11:34:23 +08:00
|
|
|
* @methodOf Kinetic.Image.prototype
|
2012-12-02 04:04:10 +08:00
|
|
|
* @param {ImageObject} image
|
2012-09-25 11:34:23 +08:00
|
|
|
*/
|
2012-12-02 04:04:10 +08:00
|
|
|
|
2012-08-19 13:02:16 +08:00
|
|
|
/**
|
2013-05-04 12:13:26 +08:00
|
|
|
* get image
|
|
|
|
* @name getImage
|
2012-08-19 13:02:16 +08:00
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
2013-05-04 12:13:26 +08:00
|
|
|
|
|
|
|
Kinetic.Node.addGetter(Kinetic.Image, 'crop');
|
2012-08-19 13:02:16 +08:00
|
|
|
|
|
|
|
/**
|
2013-05-04 12:13:26 +08:00
|
|
|
* get crop
|
|
|
|
* @name getCrop
|
2012-08-19 13:02:16 +08:00
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
2013-05-04 12:13:26 +08:00
|
|
|
|
2013-05-04 15:40:46 +08:00
|
|
|
Kinetic.Node.addFilterGetterSetter(Kinetic.Image, 'filter');
|
|
|
|
|
2013-05-08 01:19:54 +08:00
|
|
|
/**
|
|
|
|
* set filter
|
|
|
|
* @name setFilter
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
* @param {Function} filter
|
|
|
|
*/
|
2013-05-04 15:40:46 +08:00
|
|
|
|
2013-05-08 01:19:54 +08:00
|
|
|
/**
|
|
|
|
* get filter
|
|
|
|
* @name getFilter
|
|
|
|
* @methodOf Kinetic.Image.prototype
|
|
|
|
*/
|
2012-12-02 04:04:10 +08:00
|
|
|
})();
|