refactored filter API so that transitions can hook into the filter controls. Filter transitons are now working. Filters can now also have an unlimited number of parameters. added _applyFilter flag to ensure that new filters are only applied once, when needed, right before a redraw

This commit is contained in:
Eric Rowell
2013-05-04 00:40:46 -07:00
parent e22f5c4bcf
commit d75fd4b40a
9 changed files with 129 additions and 57 deletions

View File

@@ -5,9 +5,9 @@ class Build < Thor
# This is the list of files to concatenate. The first file will appear at the top of the final file. All files are relative to the lib directory.
FILES = [
"src/Global.js", "src/util/Type.js", "src/Canvas.js", "src/util/Tween.js", "src/util/Transform.js", "src/util/Collection.js",
"src/filters/Grayscale.js", "src/filters/Brighten.js", "src/filters/Invert.js", "src/filters/Blur.js", "src/filters/Mask.js",
"src/Node.js", "src/Animation.js", "src/DragAndDrop.js", "src/Transition.js", "src/Container.js", "src/Shape.js", "src/Stage.js", "src/Layer.js", "src/Group.js",
"src/shapes/Rect.js", "src/shapes/Circle.js", "src/shapes/Wedge.js", "src/shapes/Ellipse.js", "src/shapes/Image.js", "src/shapes/Polygon.js", "src/shapes/Text.js", "src/shapes/Line.js", "src/shapes/Spline.js", "src/shapes/Blob.js", "src/shapes/Sprite.js",
"src/filters/Grayscale.js", "src/filters/Brighten.js", "src/filters/Invert.js", "src/filters/Blur.js", "src/filters/Mask.js",
"src/plugins/Path.js", "src/plugins/TextPath.js", "src/plugins/RegularPolygon.js", "src/plugins/Star.js", "src/plugins/Label.js"
]

View File

@@ -2,7 +2,7 @@
the Gauss filter
master repo: https://github.com/pavelpower/kineticjsGaussFilter/
*/
(function(Kinetic) {
(function() {
/*
StackBlur - a fast almost Gaussian Blur For Canvas
@@ -111,7 +111,6 @@
mul_sum = mul_table[radius],
shg_sum = shg_table[radius];
for ( i = 1; i < div; i++ ) {
stack = stack.next = new BlurStack();
if ( i == radiusPlus1 ) var stackEnd = stack;
@@ -323,21 +322,20 @@
}
}
Kinetic = Kinetic || {};
Kinetic.Filters = Kinetic.Filters || {};
/**
* Blur Filter
* @function
* @memberOf Kinetic.Filters
* @param {Object} imageData
* @param {Integer} radius
*/
Kinetic.Filters.Blur = function(imageData, radius) {
radius = radius || 0;
filterGaussBlurRGBA(imageData, radius);
Kinetic.Filters.Blur = function(imageData) {
var radius = this.getFilterRadius() | 0;
if (radius > 0) {
filterGaussBlurRGBA(imageData, radius);
}
};
window['Kinetic'] = Kinetic;
Kinetic.Node.addFilterGetterSetter(Kinetic.Image, 'filterRadius', 0);
})(Kinetic);
})();

View File

@@ -1,13 +1,12 @@
(function() {
/**
* Brighten Filter
* Brighten Filter.
* @function
* @memberOf Kinetic.Filters
* @param {Object} imageData
* @param {Integer} brightness number from -255 to 255.&nbsp; Positive values increase the brightness and negative values decrease the brightness, making the image darker
*/
Kinetic.Filters.Brighten = function(imageData, brightness) {
var brightness = brightness || 0;
Kinetic.Filters.Brighten = function(imageData) {
var brightness = this.getFilterBrightness();
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
// red
@@ -18,4 +17,18 @@
data[i + 2] += brightness;
}
};
Kinetic.Node.addFilterGetterSetter(Kinetic.Image, 'filterBrightness', 0);
/**
* get filter brightness. The brightness is a number between -255 and 255.&nbsp; Positive values
* increase the brightness and negative values decrease the brightness, making the image darker
* @name getFilterBrightness
* @methodOf Kinetic.Image.prototype
*/
/**
* set filter brightness
* @name setFilterBrightness
* @methodOf Kinetic.Image.prototype
*/
})();

View File

@@ -4,9 +4,8 @@
* @function
* @memberOf Kinetic.Filters
* @param {Object} imageData
* @param {Object} config
*/
Kinetic.Filters.Grayscale = function(imageData, config) {
Kinetic.Filters.Grayscale = function(imageData) {
var data = 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];

View File

@@ -4,9 +4,8 @@
* @function
* @memberOf Kinetic.Filters
* @param {Object} imageData
* @param {Object} config
*/
Kinetic.Filters.Invert = function(imageData, config) {
Kinetic.Filters.Invert = function(imageData) {
var data = imageData.data;
for(var i = 0; i < data.length; i += 4) {
// red

View File

@@ -1,4 +1,4 @@
(function(Kinetic) {
(function() {
function pixelAt(idata, x, y) {
var idx = (y * idata.width + x) * 4;
@@ -159,9 +159,6 @@
return maskResult;
}
Kinetic = Kinetic || {};
Kinetic.Filters = Kinetic.Filters || {};
/**
* Mask Filter
*
@@ -170,11 +167,11 @@
* @function
* @memberOf Kinetic.Filters
* @param {Object} imageData
* @param {Integer} threshold The RGB euclidian distance threshold (default : 10)
*/
Kinetic.Filters.Mask = function(idata, threshold) {
Kinetic.Filters.Mask = function(idata) {
// Detect pixels close to the background color
var mask = backgroundMask(idata, threshold);
var threshold = this.getFilterThreshold(),
mask = backgroundMask(idata, threshold);
if (mask) {
// Erode
mask = erodeMask(mask, idata.width, idata.height);
@@ -194,6 +191,8 @@
return idata;
};
window['Kinetic'] = Kinetic;
Kinetic.Node.addFilterGetterSetter(Kinetic.Image, 'filterThreshold', 0);
})(Kinetic);
//threshold The RGB euclidian distance threshold (default : 10)
})();

View File

@@ -1,7 +1,8 @@
(function() {
// CONSTANTS
var IMAGE = 'Image',
CROP = 'crop';
CROP = 'crop',
SET = 'set';
/**
* Image constructor
@@ -33,12 +34,17 @@
that = this,
context = canvas.getContext(),
crop = this.getCrop(),
cropX, cropY, cropWidth, cropHeight,
filterCanvas = this.filterCanvas,
image;
cropX, cropY, cropWidth, cropHeight, image;
if (filterCanvas) {
image = filterCanvas.getElement();
// 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();
}
else {
image = this.getImage();
@@ -97,16 +103,13 @@
* apply filter
* @name applyFilter
* @methodOf Kinetic.Image.prototype
* @param {Object} config
* @param {Function} filter filter function
* @param {*} [val] optional val parameter that can be any data type. See the
* docs for the filter in question
*/
applyFilter: function(filter, val) {
applyFilter: function() {
var image = this.getImage(),
that = this,
width = this.getWidth(),
height = this.getHeight(),
filter = this.getFilter(),
filterCanvas, context, imageData;
if (this.filterCanvas){
@@ -124,7 +127,7 @@
try {
this._drawImage(context, [image, 0, 0, width, height]);
imageData = context.getImageData(0, 0, filterCanvas.getWidth(), filterCanvas.getHeight());
filter(imageData, val);
filter.call(this, imageData);
context.putImageData(imageData, 0, 0);
}
catch(e) {
@@ -139,6 +142,7 @@
*/
clearFilter: function() {
this.filterCanvas = null;
this._applyFilter = false;
},
/**
* set crop
@@ -232,6 +236,22 @@
};
Kinetic.Global.extend(Kinetic.Image, Kinetic.Shape);
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;
};
};
// add getters setters
Kinetic.Node.addGetterSetter(Kinetic.Image, 'image');
@@ -256,4 +276,7 @@
* @methodOf Kinetic.Image.prototype
*/
Kinetic.Node.addFilterGetterSetter(Kinetic.Image, 'filter');
})();

View File

@@ -52,7 +52,6 @@ Test.Modules.TRANSITION = {
easing: 'bounce-ease-out'
});
},
'all transition types': function(containerId) {
document.getElementById(containerId).style.height = '300px';
@@ -1438,5 +1437,46 @@ Test.Modules.DRAG_AND_DROP = {
});
},
'transition gaussian blur filter': 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();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true,
filter: Kinetic.Filters.Blur,
filterRadius: 20
});
layer.add(darth);
stage.add(layer);
darth.on('mouseover', function() {
darth.transitionTo({
easing: 'ease-in-out',
duration: 0.5,
filterRadius: 0
});
});
darth.on('mouseout', function() {
darth.transitionTo({
easing: 'ease-in-out',
duration: 0.5,
filterRadius: 20
});
});
};
imageObj.src = '../assets/darth-vader.jpg';
}
};

View File

@@ -218,12 +218,13 @@ Test.Modules.IMAGE = {
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
darth.applyFilter(Kinetic.Filters.Grayscale, null, function() {
layer.draw();
var dataUrl = layer.toDataURL();
//console.log(dataUrl);
warn(dataUrl === dataUrls['grayscale image'], 'problem with Grayscale filter.');
});
darth.setFilter(Kinetic.Filters.Grayscale);
layer.draw();
var dataUrl = layer.toDataURL();
//console.log(dataUrl);
warn(dataUrl === dataUrls['grayscale image'], 'problem with Grayscale filter.');
};
imageObj.src = '../assets/darth-vader.jpg';
},
@@ -251,7 +252,7 @@ Test.Modules.IMAGE = {
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
darth.applyFilter(Kinetic.Filters.Invert);
darth.setFilter(Kinetic.Filters.Invert);
layer.draw();
var dataUrl = layer.toDataURL();
@@ -285,7 +286,8 @@ Test.Modules.IMAGE = {
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
darth.applyFilter(Kinetic.Filters.Brighten, 100);
darth.setFilter(Kinetic.Filters.Brighten);
darth.setFilterBrightness(100);
layer.draw();
var dataUrl = layer.toDataURL();
@@ -302,9 +304,7 @@ Test.Modules.IMAGE = {
width: 578,
height: 200
});
var layer = new Kinetic.Layer({
throttle: 999
});
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
@@ -318,8 +318,8 @@ Test.Modules.IMAGE = {
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
darth.applyFilter(Kinetic.Filters.Blur, 10);
darth.setFilter(Kinetic.Filters.Blur);
darth.setFilterRadius(10);
layer.draw();
var dataUrl = layer.toDataURL();
//console.log(dataUrl);
@@ -357,7 +357,7 @@ Test.Modules.IMAGE = {
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
darth.applyFilter(Kinetic.Filters.Grayscale);
darth.setFilter(Kinetic.Filters.Grayscale);
layer.draw();
//console.log(layer.toDataURL());
@@ -428,7 +428,8 @@ Test.Modules.IMAGE = {
layer.add(filtered);
stage.add(layer);
filtered.applyFilter(Kinetic.Filters.Mask, 10);
filtered.setFilter(Kinetic.Filters.Mask);
filtered.setFilterThreshold(10);
layer.draw();
var dataUrl = layer.toDataURL();