mirror of
https://github.com/konvajs/konva.git
synced 2025-08-24 03:35:02 +08:00
first pass at implementing filters. Still have a lot to work through.
This commit is contained in:
parent
384a686740
commit
20adf7e036
2
Thorfile
2
Thorfile
@ -6,7 +6,7 @@ class Build < Thor
|
||||
"license.js", "src/Global.js", "src/util/Type.js", "src/util/Class.js", "src/Animation.js", "src/Node.js", "src/Container.js", "src/Stage.js",
|
||||
"src/Layer.js", "src/Group.js", "src/Shape.js", "src/shapes/Rect.js", "src/shapes/Ellipse.js", "src/shapes/Image.js",
|
||||
"src/shapes/Sprite.js", "src/shapes/Polygon.js", "src/shapes/RegularPolygon.js", "src/shapes/Star.js", "src/shapes/Text.js",
|
||||
"src/shapes/Line.js", "src/shapes/Path.js", "src/util/Transform.js", "src/Transition.js", "src/util/Tween.js"
|
||||
"src/shapes/Line.js", "src/shapes/Path.js", "src/util/Transform.js", "src/Transition.js", "src/util/Tween.js", "src/filters/Grayscale.js"
|
||||
]
|
||||
|
||||
desc "dev", "Concatenate all the js files into /dist/kinetic-VERSION.js."
|
||||
|
173
dist/kinetic-core.js
vendored
173
dist/kinetic-core.js
vendored
@ -3,7 +3,7 @@
|
||||
* http://www.kineticjs.com/
|
||||
* Copyright 2012, Eric Rowell
|
||||
* Licensed under the MIT or GPL Version 2 licenses.
|
||||
* Date: Jul 15 2012
|
||||
* Date: Jul 17 2012
|
||||
*
|
||||
* Copyright (C) 2011 - 2012 by Eric Rowell
|
||||
*
|
||||
@ -49,6 +49,11 @@ Kinetic.Global = {
|
||||
},
|
||||
lastDrawTime: 0
|
||||
},
|
||||
warn: function(str) {
|
||||
if(console && console.warn) {
|
||||
console.warn('Kinetic warning: ' + str);
|
||||
}
|
||||
},
|
||||
_pullNodes: function(stage) {
|
||||
var tempNodes = this.tempNodes;
|
||||
for(var n = 0; n < tempNodes.length; n++) {
|
||||
@ -1273,29 +1278,38 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
},
|
||||
/**
|
||||
* save image data
|
||||
* @name saveImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
saveImageData: function() {
|
||||
var stage = this.getStage();
|
||||
var w = stage.attrs.width;
|
||||
var h = stage.attrs.height;
|
||||
try {
|
||||
var stage = this.getStage();
|
||||
var bufferLayer = stage.bufferLayer;
|
||||
var bufferLayerContext = bufferLayer.getContext();
|
||||
var width = stage.getWidth();
|
||||
var height = stage.getHeight();
|
||||
|
||||
var bufferLayer = stage.bufferLayer;
|
||||
var bufferLayerContext = bufferLayer.getContext();
|
||||
|
||||
bufferLayer.clear();
|
||||
this._draw(bufferLayer);
|
||||
|
||||
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
|
||||
this.imageData = imageData;
|
||||
bufferLayer.clear();
|
||||
this._draw(bufferLayer);
|
||||
var imageData = bufferLayerContext.getImageData(0, 0, width, height);
|
||||
this.imageData = imageData;
|
||||
}
|
||||
catch(e) {
|
||||
Kinetic.Global.warn('Image data could not saved because canvas is dirty.');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* clear image data
|
||||
* @name clearImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
clearImageData: function() {
|
||||
delete this.imageData;
|
||||
},
|
||||
/**
|
||||
* get image data
|
||||
* @name getImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
getImageData: function() {
|
||||
return this.imageData;
|
||||
@ -3872,7 +3886,7 @@ Kinetic.Node.addGettersSetters(Kinetic.Ellipse, ['radius']);
|
||||
* @constructor
|
||||
* @augments Kinetic.Shape
|
||||
* @param {Object} config
|
||||
* @param {ImageObject|String|ImageData} config.image can be an image object, a data url string, or an image data object
|
||||
* @param {ImageObject} config.image
|
||||
* @param {Number} [config.width]
|
||||
* @param {Number} [config.height]
|
||||
* @param {Object} [config.crop]
|
||||
@ -3882,8 +3896,8 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
this.shapeType = "Image";
|
||||
config.drawFunc = function() {
|
||||
if(!!this.attrs.image) {
|
||||
var width = !!this.attrs.width ? this.attrs.width : this.attrs.image.width;
|
||||
var height = !!this.attrs.height ? this.attrs.height : this.attrs.image.height;
|
||||
var width = this.getWidth();
|
||||
var height = this.getHeight();
|
||||
var canvas = this.getCanvas();
|
||||
var context = this.getContext();
|
||||
|
||||
@ -3909,6 +3923,11 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
};
|
||||
// call super constructor
|
||||
this._super(config);
|
||||
|
||||
var that = this;
|
||||
this.on('filterChange', function() {
|
||||
that._applyFilter();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* set width and height
|
||||
@ -3929,11 +3948,94 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
width: this.attrs.width,
|
||||
height: this.attrs.height
|
||||
};
|
||||
},
|
||||
/**
|
||||
* get width
|
||||
* @name getWidth
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
getWidth: function() {
|
||||
if(this.attrs.width) {
|
||||
return this.attrs.width;
|
||||
}
|
||||
if(this.attrs.image) {
|
||||
return this.attrs.image.width;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* get height
|
||||
* @name getHeight
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
getHeight: function() {
|
||||
if(this.attrs.height) {
|
||||
return this.attrs.height;
|
||||
}
|
||||
if(this.attrs.image) {
|
||||
return this.attrs.image.height;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* apply filter
|
||||
* @name applyFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
* @param {Object} config
|
||||
* @param {Function} config.filter filter function
|
||||
* @param {Function} [config.callback] callback function to be called once
|
||||
* filter has been applied
|
||||
*/
|
||||
applyFilter: function(config) {
|
||||
try {
|
||||
// save transformation state
|
||||
var x = this.getX();
|
||||
var y = this.getY();
|
||||
var rotation = this.getRotation();
|
||||
var scaleX = this.getScale().x;
|
||||
var scaleY = this.getScale().y;
|
||||
var offsetX = this.getOffset().x;
|
||||
var offsetY = this.getOffset().y;
|
||||
|
||||
// reset transformation state
|
||||
this.attrs.x = 0;
|
||||
this.attrs.y = 0;
|
||||
this.attrs.rotation = 0;
|
||||
this.attrs.scale.x = 1;
|
||||
this.attrs.scale.y = 1;
|
||||
this.attrs.offset.x = 0;
|
||||
this.attrs.offset.y = 0;
|
||||
|
||||
this.saveImageData();
|
||||
|
||||
// restore transformation state
|
||||
this.attrs.x = x;
|
||||
this.attrs.y = y;
|
||||
this.attrs.rotation = rotation;
|
||||
this.attrs.scale.x = scaleX;
|
||||
this.attrs.scale.y = scaleY;
|
||||
this.attrs.offset.x = offsetX;
|
||||
this.attrs.offset.y = offsetY;
|
||||
|
||||
config.filter.call(this, config);
|
||||
var that = this;
|
||||
Kinetic.Type._getImage(this.getImageData(), function(imageObj) {
|
||||
that.setImage(imageObj);
|
||||
|
||||
if(config.callback) {
|
||||
config.callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
Kinetic.Global.warn('Unable to apply filter.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add getters setters
|
||||
Kinetic.Node.addGettersSetters(Kinetic.Image, ['height', 'width', 'image', 'crop']);
|
||||
Kinetic.Node.addGettersSetters(Kinetic.Image, ['image', 'crop', 'filter']);
|
||||
Kinetic.Node.addSetters(Kinetic.Image, ['width', 'height']);
|
||||
|
||||
/**
|
||||
* set width
|
||||
@ -3963,29 +4065,30 @@ Kinetic.Node.addGettersSetters(Kinetic.Image, ['height', 'width', 'image', 'crop
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
/**
|
||||
* set filter
|
||||
* @name setFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
/**
|
||||
* get crop
|
||||
* @name getCrop
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get width
|
||||
* @name getWidth
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get height
|
||||
* @name getHeight
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get image
|
||||
* @name getImage
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get filter
|
||||
* @name getFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
// Sprite
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
@ -5812,3 +5915,17 @@ Kinetic.Tweens = {
|
||||
}
|
||||
};
|
||||
|
||||
Kinetic.Filters.Grayscale = function() {
|
||||
var data = this.imageData.data;
|
||||
for(var i = 0; i < data.length; i += 4) {
|
||||
var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
|
||||
// red
|
||||
data[i] = brightness;
|
||||
// green
|
||||
data[i + 1] = brightness;
|
||||
// blue
|
||||
data[i + 2] = brightness;
|
||||
// i+3 is alpha (the fourth element)
|
||||
}
|
||||
};
|
||||
|
||||
|
29
dist/kinetic-core.min.js
vendored
29
dist/kinetic-core.min.js
vendored
File diff suppressed because one or more lines are too long
@ -21,6 +21,11 @@ Kinetic.Global = {
|
||||
},
|
||||
lastDrawTime: 0
|
||||
},
|
||||
warn: function(str) {
|
||||
if(console && console.warn) {
|
||||
console.warn('Kinetic warning: ' + str);
|
||||
}
|
||||
},
|
||||
_pullNodes: function(stage) {
|
||||
var tempNodes = this.tempNodes;
|
||||
for(var n = 0; n < tempNodes.length; n++) {
|
||||
|
31
src/Node.js
31
src/Node.js
@ -797,29 +797,38 @@ Kinetic.Node = Kinetic.Class.extend({
|
||||
},
|
||||
/**
|
||||
* save image data
|
||||
* @name saveImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
saveImageData: function() {
|
||||
var stage = this.getStage();
|
||||
var w = stage.attrs.width;
|
||||
var h = stage.attrs.height;
|
||||
try {
|
||||
var stage = this.getStage();
|
||||
var bufferLayer = stage.bufferLayer;
|
||||
var bufferLayerContext = bufferLayer.getContext();
|
||||
var width = stage.getWidth();
|
||||
var height = stage.getHeight();
|
||||
|
||||
var bufferLayer = stage.bufferLayer;
|
||||
var bufferLayerContext = bufferLayer.getContext();
|
||||
|
||||
bufferLayer.clear();
|
||||
this._draw(bufferLayer);
|
||||
|
||||
var imageData = bufferLayerContext.getImageData(0, 0, w, h);
|
||||
this.imageData = imageData;
|
||||
bufferLayer.clear();
|
||||
this._draw(bufferLayer);
|
||||
var imageData = bufferLayerContext.getImageData(0, 0, width, height);
|
||||
this.imageData = imageData;
|
||||
}
|
||||
catch(e) {
|
||||
Kinetic.Global.warn('Image data could not saved because canvas is dirty.');
|
||||
}
|
||||
},
|
||||
/**
|
||||
* clear image data
|
||||
* @name clearImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
clearImageData: function() {
|
||||
delete this.imageData;
|
||||
},
|
||||
/**
|
||||
* get image data
|
||||
* @name getImageData
|
||||
* @methodOf Kinetic.Node.prototype
|
||||
*/
|
||||
getImageData: function() {
|
||||
return this.imageData;
|
||||
|
@ -1,5 +1,5 @@
|
||||
Kinetic.Filters.Grayscale = function(config) {
|
||||
var data = config.data;
|
||||
Kinetic.Filters.Grayscale = function() {
|
||||
var data = this.imageData.data;
|
||||
for(var i = 0; i < data.length; i += 4) {
|
||||
var brightness = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
|
||||
// red
|
||||
@ -10,5 +10,4 @@ Kinetic.Filters.Grayscale = function(config) {
|
||||
data[i + 2] = brightness;
|
||||
// i+3 is alpha (the fourth element)
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
@ -6,7 +6,7 @@
|
||||
* @constructor
|
||||
* @augments Kinetic.Shape
|
||||
* @param {Object} config
|
||||
* @param {ImageObject|String|ImageData} config.image can be an image object, a data url string, or an image data object
|
||||
* @param {ImageObject} config.image
|
||||
* @param {Number} [config.width]
|
||||
* @param {Number} [config.height]
|
||||
* @param {Object} [config.crop]
|
||||
@ -16,8 +16,8 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
this.shapeType = "Image";
|
||||
config.drawFunc = function() {
|
||||
if(!!this.attrs.image) {
|
||||
var width = !!this.attrs.width ? this.attrs.width : this.attrs.image.width;
|
||||
var height = !!this.attrs.height ? this.attrs.height : this.attrs.image.height;
|
||||
var width = this.getWidth();
|
||||
var height = this.getHeight();
|
||||
var canvas = this.getCanvas();
|
||||
var context = this.getContext();
|
||||
|
||||
@ -43,6 +43,11 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
};
|
||||
// call super constructor
|
||||
this._super(config);
|
||||
|
||||
var that = this;
|
||||
this.on('filterChange', function() {
|
||||
that._applyFilter();
|
||||
});
|
||||
},
|
||||
/**
|
||||
* set width and height
|
||||
@ -63,11 +68,94 @@ Kinetic.Image = Kinetic.Shape.extend({
|
||||
width: this.attrs.width,
|
||||
height: this.attrs.height
|
||||
};
|
||||
},
|
||||
/**
|
||||
* get width
|
||||
* @name getWidth
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
getWidth: function() {
|
||||
if(this.attrs.width) {
|
||||
return this.attrs.width;
|
||||
}
|
||||
if(this.attrs.image) {
|
||||
return this.attrs.image.width;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* get height
|
||||
* @name getHeight
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
getHeight: function() {
|
||||
if(this.attrs.height) {
|
||||
return this.attrs.height;
|
||||
}
|
||||
if(this.attrs.image) {
|
||||
return this.attrs.image.height;
|
||||
}
|
||||
return 0;
|
||||
},
|
||||
/**
|
||||
* apply filter
|
||||
* @name applyFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
* @param {Object} config
|
||||
* @param {Function} config.filter filter function
|
||||
* @param {Function} [config.callback] callback function to be called once
|
||||
* filter has been applied
|
||||
*/
|
||||
applyFilter: function(config) {
|
||||
try {
|
||||
// save transformation state
|
||||
var x = this.getX();
|
||||
var y = this.getY();
|
||||
var rotation = this.getRotation();
|
||||
var scaleX = this.getScale().x;
|
||||
var scaleY = this.getScale().y;
|
||||
var offsetX = this.getOffset().x;
|
||||
var offsetY = this.getOffset().y;
|
||||
|
||||
// reset transformation state
|
||||
this.attrs.x = 0;
|
||||
this.attrs.y = 0;
|
||||
this.attrs.rotation = 0;
|
||||
this.attrs.scale.x = 1;
|
||||
this.attrs.scale.y = 1;
|
||||
this.attrs.offset.x = 0;
|
||||
this.attrs.offset.y = 0;
|
||||
|
||||
this.saveImageData();
|
||||
|
||||
// restore transformation state
|
||||
this.attrs.x = x;
|
||||
this.attrs.y = y;
|
||||
this.attrs.rotation = rotation;
|
||||
this.attrs.scale.x = scaleX;
|
||||
this.attrs.scale.y = scaleY;
|
||||
this.attrs.offset.x = offsetX;
|
||||
this.attrs.offset.y = offsetY;
|
||||
|
||||
config.filter.call(this, config);
|
||||
var that = this;
|
||||
Kinetic.Type._getImage(this.getImageData(), function(imageObj) {
|
||||
that.setImage(imageObj);
|
||||
|
||||
if(config.callback) {
|
||||
config.callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
catch(e) {
|
||||
Kinetic.Global.warn('Unable to apply filter.');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// add getters setters
|
||||
Kinetic.Node.addGettersSetters(Kinetic.Image, ['height', 'width', 'image', 'crop']);
|
||||
Kinetic.Node.addGettersSetters(Kinetic.Image, ['image', 'crop', 'filter']);
|
||||
Kinetic.Node.addSetters(Kinetic.Image, ['width', 'height']);
|
||||
|
||||
/**
|
||||
* set width
|
||||
@ -97,26 +185,27 @@ Kinetic.Node.addGettersSetters(Kinetic.Image, ['height', 'width', 'image', 'crop
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
/**
|
||||
* set filter
|
||||
* @name setFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
/**
|
||||
* get crop
|
||||
* @name getCrop
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get width
|
||||
* @name getWidth
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get height
|
||||
* @name getHeight
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get image
|
||||
* @name getImage
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
||||
|
||||
/**
|
||||
* get filter
|
||||
* @name getFilter
|
||||
* @methodOf Kinetic.Image.prototype
|
||||
*/
|
@ -247,7 +247,6 @@ Test.prototype.tests = {
|
||||
clientY: 101
|
||||
});
|
||||
|
||||
console.log(layer.toDataURL())
|
||||
warn(layer.toDataURL() === urls[1], 'mid data url is incorrect');
|
||||
|
||||
// move mouse back out of circle
|
||||
|
@ -31,7 +31,7 @@ Test.prototype.tests = {
|
||||
for(var n = 0; n < 10000; n++) {
|
||||
context.putImageData(imageData, 7, 7);
|
||||
}
|
||||
endTimer('draw 10,000 images with image object from image data');
|
||||
endTimer('draw 10,000 images with putImageData');
|
||||
|
||||
},
|
||||
'DRAWING - draw rect vs image from data url': function(containerId) {
|
||||
@ -61,15 +61,17 @@ Test.prototype.tests = {
|
||||
endTimer('create data url');
|
||||
|
||||
var imageObj = new Image();
|
||||
imageObj.onload = function() {
|
||||
layer.clear();
|
||||
|
||||
startTimer();
|
||||
for(var n = 0; n < 10000; n++) {
|
||||
context.drawImage(imageObj, 7, 7, 106, 106, 10, 10, 106, 106);
|
||||
}
|
||||
endTimer('draw 10,000 images with image object from data url');
|
||||
}
|
||||
imageObj.src = url;
|
||||
|
||||
layer.clear();
|
||||
|
||||
startTimer();
|
||||
for(var n = 0; n < 10000; n++) {
|
||||
context.drawImage(imageObj, 7, 7, 106, 106, 10, 10, 106, 106);
|
||||
}
|
||||
endTimer('draw 10,000 images with image object from data url');
|
||||
},
|
||||
'DRAWING - draw 1,000 stars': function(containerId) {
|
||||
var stage = new Kinetic.Stage({
|
||||
@ -121,7 +123,7 @@ Test.prototype.tests = {
|
||||
layer.add(star);
|
||||
stage.add(layer);
|
||||
|
||||
console.log('call toImage')
|
||||
console.log('call toImage')
|
||||
star.toImage(function(img) {
|
||||
startTimer();
|
||||
for(var n = 0; n < 1000; n++) {
|
||||
|
@ -1991,6 +1991,39 @@ Test.prototype.tests = {
|
||||
};
|
||||
imageObj.src = '../darth-vader.jpg';
|
||||
},
|
||||
'SHAPE - filter image': function(containerId) {
|
||||
var imageObj = new Image();
|
||||
imageObj.onload = function() {
|
||||
var stage = new Kinetic.Stage({
|
||||
container: containerId,
|
||||
width: 578,
|
||||
height: 200
|
||||
});
|
||||
var layer = new Kinetic.Layer({
|
||||
throttle: 999
|
||||
});
|
||||
darth = new Kinetic.Image({
|
||||
x: 10,
|
||||
y: 10,
|
||||
image: imageObj,
|
||||
draggable: true
|
||||
});
|
||||
|
||||
layer.add(darth);
|
||||
stage.add(layer);
|
||||
|
||||
test(darth.getWidth() === 438, 'image width should be 438');
|
||||
test(darth.getHeight() === 300, 'image height should be 300');
|
||||
|
||||
darth.applyFilter({
|
||||
filter: Kinetic.Filters.Grayscale,
|
||||
callback: function() {
|
||||
layer.draw();
|
||||
}
|
||||
});
|
||||
};
|
||||
imageObj.src = '../darth-vader.jpg';
|
||||
},
|
||||
'SHAPE - set image fill to color then image': function(containerId) {
|
||||
var imageObj = new Image();
|
||||
imageObj.onload = function() {
|
||||
|
Loading…
Reference in New Issue
Block a user