mirror of
https://github.com/konvajs/konva.git
synced 2025-06-28 15:23:44 +08:00
360 lines
10 KiB
JavaScript
360 lines
10 KiB
JavaScript
(function() {
|
|
|
|
// CONSTANTS
|
|
var IMAGE = 'Image',
|
|
CROP = 'crop',
|
|
SET = 'set';
|
|
|
|
/**
|
|
* Image constructor
|
|
* @constructor
|
|
* @memberof Kinetic
|
|
* @augments Kinetic.Shape
|
|
* @param {Object} config
|
|
* @param {ImageObject} config.image
|
|
* @param {Object} [config.crop]
|
|
* @@shapeParams
|
|
* @@nodeParams
|
|
* @example
|
|
* var imageObj = new Image();<br>
|
|
* imageObj.onload = function() {<br>
|
|
* var image = new Kinetic.Image({<br>
|
|
* x: 200,<br>
|
|
* y: 50,<br>
|
|
* image: imageObj,<br>
|
|
* width: 100,<br>
|
|
* height: 100<br>
|
|
* });<br>
|
|
* };<br>
|
|
* imageObj.src = '/path/to/image.jpg'
|
|
*/
|
|
Kinetic.Image = function(config) {
|
|
this.___init(config);
|
|
};
|
|
|
|
Kinetic.Image.prototype = {
|
|
___init: function(config) {
|
|
var that = this;
|
|
|
|
// call super constructor
|
|
Kinetic.Shape.call(this, config);
|
|
this.className = IMAGE;
|
|
},
|
|
drawFunc: function(context) {
|
|
var width = this.getWidth(),
|
|
height = this.getHeight(),
|
|
params,
|
|
that = this,
|
|
cropX = this.getCropX() || 0,
|
|
cropY = this.getCropY() || 0,
|
|
cropWidth = this.getCropWidth(),
|
|
cropHeight = this.getCropHeight(),
|
|
image;
|
|
|
|
// 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._canvas;
|
|
}
|
|
else {
|
|
image = this.getImage();
|
|
}
|
|
|
|
context.beginPath();
|
|
context.rect(0, 0, width, height);
|
|
context.closePath();
|
|
context.fillStrokeShape(this);
|
|
|
|
if(image) {
|
|
// if cropping
|
|
if(cropWidth && cropHeight) {
|
|
params = [image, cropX, cropY, cropWidth, cropHeight, 0, 0, width, height];
|
|
}
|
|
// no cropping
|
|
else {
|
|
params = [image, 0, 0, width, height];
|
|
}
|
|
|
|
if(this.hasShadow()) {
|
|
context.applyShadow(this, function() {
|
|
context.drawImage.apply(context, params);
|
|
});
|
|
}
|
|
else {
|
|
context.drawImage.apply(context, params);
|
|
}
|
|
}
|
|
},
|
|
drawHitFunc: function(context) {
|
|
var width = this.getWidth(),
|
|
height = this.getHeight(),
|
|
imageHitRegion = this.imageHitRegion;
|
|
|
|
if(imageHitRegion) {
|
|
context.drawImage(imageHitRegion, 0, 0, width, height);
|
|
context.beginPath();
|
|
context.rect(0, 0, width, height);
|
|
context.closePath();
|
|
context.stroke(this);
|
|
}
|
|
else {
|
|
context.beginPath();
|
|
context.rect(0, 0, width, height);
|
|
context.closePath();
|
|
context.fillStrokeShape(this);
|
|
}
|
|
},
|
|
applyFilter: function() {
|
|
var image = this.getImage(),
|
|
that = this,
|
|
width = this.getWidth(),
|
|
height = this.getHeight(),
|
|
filter = this.getFilter(),
|
|
filterCanvas, context, imageData;
|
|
|
|
if (this.filterCanvas){
|
|
filterCanvas = this.filterCanvas;
|
|
filterCanvas.getContext().clear();
|
|
}
|
|
else {
|
|
filterCanvas = this.filterCanvas = new Kinetic.SceneCanvas({
|
|
width: width,
|
|
height: height,
|
|
pixelRatio: 1
|
|
});
|
|
}
|
|
|
|
context = filterCanvas.getContext();
|
|
|
|
try {
|
|
context.drawImage(image, 0, 0, filterCanvas.getWidth(), filterCanvas.getHeight());
|
|
imageData = context.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight());
|
|
filter.call(this, imageData);
|
|
context.putImageData(imageData, 0, 0);
|
|
}
|
|
catch(e) {
|
|
this.clearFilter();
|
|
Kinetic.Util.warn('Unable to apply filter. ' + e.message);
|
|
}
|
|
},
|
|
/**
|
|
* clear filter
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
clearFilter: function() {
|
|
this.filterCanvas = null;
|
|
this._applyFilter = false;
|
|
},
|
|
/**
|
|
* create image hit region which enables more accurate hit detection mapping of the image
|
|
* by avoiding event detections for transparent pixels
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Function} [callback] callback function to be called once
|
|
* the image hit region has been created
|
|
*/
|
|
createImageHitRegion: function(callback) {
|
|
var that = this,
|
|
width = this.getWidth(),
|
|
height = this.getHeight(),
|
|
// TODO: may consider creating a native canvas element here instead
|
|
canvas = new Kinetic.SceneCanvas({
|
|
width: width,
|
|
height: height
|
|
}),
|
|
context = canvas.getContext(),
|
|
image = this.getImage(),
|
|
imageData, data, rgbColorKey, i, n;
|
|
|
|
context.drawImage(image, 0, 0);
|
|
|
|
try {
|
|
imageData = context.getImageData(0, 0, width, height);
|
|
data = imageData.data;
|
|
rgbColorKey = Kinetic.Util._hexToRgb(this.colorKey);
|
|
|
|
// replace non transparent pixels with color key
|
|
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;
|
|
}
|
|
}
|
|
|
|
Kinetic.Util._getImage(imageData, function(imageObj) {
|
|
that.imageHitRegion = imageObj;
|
|
if(callback) {
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
catch(e) {
|
|
Kinetic.Util.warn('Unable to create image hit region. ' + e.message);
|
|
}
|
|
},
|
|
/**
|
|
* clear image hit region
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
clearImageHitRegion: function() {
|
|
delete this.imageHitRegion;
|
|
},
|
|
getWidth: function() {
|
|
var image = this.getImage();
|
|
return this.attrs.width || (image ? image.width : 0);
|
|
},
|
|
getHeight: function() {
|
|
var image = this.getImage();
|
|
return this.attrs.height || (image ? image.height : 0);
|
|
}
|
|
};
|
|
Kinetic.Util.extend(Kinetic.Image, Kinetic.Shape);
|
|
|
|
|
|
Kinetic.Factory.addFilterGetterSetter = function(constructor, attr, def) {
|
|
this.addGetter(constructor, attr, def);
|
|
this.addFilterSetter(constructor, attr);
|
|
};
|
|
|
|
Kinetic.Factory.addFilterSetter = function(constructor, attr) {
|
|
var that = this,
|
|
method = SET + Kinetic.Util._capitalize(attr);
|
|
|
|
constructor.prototype[method] = function(val) {
|
|
this._setAttr(attr, val);
|
|
this._applyFilter = true;
|
|
};
|
|
};
|
|
|
|
// add getters setters
|
|
Kinetic.Factory.addGetterSetter(Kinetic.Image, 'image');
|
|
|
|
/**
|
|
* set image
|
|
* @name setImage
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {ImageObject} image
|
|
*/
|
|
|
|
/**
|
|
* get image
|
|
* @name getImage
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
|
|
Kinetic.Factory.addBoxGetterSetter(Kinetic.Image, 'crop');
|
|
/**
|
|
* set crop
|
|
* @method
|
|
* @name setCrop
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Object|Array}
|
|
* @example
|
|
* // set crop x, y, width and height with an array<br>
|
|
* image.setCrop([20, 20, 100, 100]);<br><br>
|
|
*
|
|
* // set crop x, y, width and height with an object<br>
|
|
* image.setCrop({<br>
|
|
* x: 20,<br>
|
|
* y: 20,<br>
|
|
* width: 20,<br>
|
|
* height: 20<br>
|
|
* });
|
|
*/
|
|
|
|
/**
|
|
* set cropX
|
|
* @method
|
|
* @name setCropX
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Number} x
|
|
*/
|
|
|
|
/**
|
|
* set cropY
|
|
* @name setCropY
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Number} y
|
|
*/
|
|
|
|
/**
|
|
* set cropWidth
|
|
* @name setCropWidth
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Number} width
|
|
*/
|
|
|
|
/**
|
|
* set cropHeight
|
|
* @name setCropHeight
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Number} height
|
|
*/
|
|
|
|
/**
|
|
* get crop
|
|
* @name getCrop
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @return {Object}
|
|
*/
|
|
|
|
/**
|
|
* get crop x
|
|
* @name getCropX
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
|
|
/**
|
|
* get crop y
|
|
* @name getCropY
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
|
|
/**
|
|
* get crop width
|
|
* @name getCropWidth
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
|
|
/**
|
|
* get crop height
|
|
* @name getCropHeight
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
|
|
Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filter');
|
|
|
|
/**
|
|
* set filter
|
|
* @name setFilter
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
* @param {Function} filter
|
|
*/
|
|
|
|
/**
|
|
* get filter
|
|
* @name getFilter
|
|
* @method
|
|
* @memberof Kinetic.Image.prototype
|
|
*/
|
|
})();
|