From 632b81137afba5a7af5e5aa99f9b5d21d8f87582 Mon Sep 17 00:00:00 2001 From: ippo615 Date: Tue, 3 Dec 2013 18:34:24 -0500 Subject: [PATCH 1/5] Added tweening to HSV filter --- src/filters/ColorPack.js | 64 +++++++++++ test/unit/filters/ColorPack-test.js | 165 +++++++++++++++++++++++++++- 2 files changed, 226 insertions(+), 3 deletions(-) diff --git a/src/filters/ColorPack.js b/src/filters/ColorPack.js index 6c18f43f..ad0742d8 100644 --- a/src/filters/ColorPack.js +++ b/src/filters/ColorPack.js @@ -72,6 +72,70 @@ Kinetic.Filters.HSV = Kinetic.Util._FilterWrapSingleBuffer(HSV); + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterHue', 0); + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterSaturation', 1); + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterValue', 1); + + Kinetic.Filters.HSV = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + HSV(src, dst||src, opt ); + }else{ + HSV.call(this, src, dst||src, opt || { + hue: this.getFilterHue(), + saturation: this.getFilterSaturation(), + value: this.getFilterValue() + }); + } + }; + + /** + * get filter hue. Returns the hue shift for the HSV filter. + * 0 is no change, 359 is the maximum shift. + * @name getFilterHue + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * set filter hue. Sets the hue shift for the HSV filter. + * 0 is no change, 359 is the maximum shift. + * @name setFilterHue + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * get filter saturation. Returns the saturation scale for the HSV + * filter. 1 is no change, 0.5 halves the saturation, 2.0 doubles, etc.. + * @name getFilterSaturation + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * set filter saturation. Set the saturation scale for the HSV + * filter. 1 is no change, 0.5 halves the saturation, 2.0 doubles, etc.. + * @name setFilterSaturation + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * get filter value. Returns the value scale for the HSV + * filter. 1 is no change, 0.5 halves the value, 2.0 doubles, etc.. + * @name getFilterValue + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * set filter value. Set the value scale for the HSV + * filter. 1 is no change, 0.5 halves the value, 2.0 doubles, etc.. + * @name setFilterValue + * @method + * @memberof Kinetic.Image.prototype + */ + })(); (function() { diff --git a/test/unit/filters/ColorPack-test.js b/test/unit/filters/ColorPack-test.js index 3bd1243c..d1052b56 100644 --- a/test/unit/filters/ColorPack-test.js +++ b/test/unit/filters/ColorPack-test.js @@ -108,14 +108,100 @@ suite('Color Pack', function() { layer.add(darth); stage.add(layer); - darth.setFilter(Kinetic.Filters.ShiftHue); - darth.setFilterHueShiftDeg(360); + darth.setFilter(Kinetic.Filters.HSV); + darth.setFilterHue(360); layer.draw(); var tween = new Kinetic.Tween({ node: darth, duration: 5.0, - filterHueShiftDeg: 0, + filterHue: 0, + easing: Kinetic.Easings.EaseInOut + }); + + darth.on('mouseover', function() { + tween.play(); + }); + + darth.on('mouseout', function() { + tween.reverse(); + }); + + done(); + }; + imageObj.src = 'assets/lion.png'; + + }); + + // ====================================================== + test('saturation tween transparancy', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + darth = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(darth); + stage.add(layer); + + darth.setFilter(Kinetic.Filters.HSV); + darth.setFilterSaturation(2.0); + layer.draw(); + + var tween = new Kinetic.Tween({ + node: darth, + duration: 5.0, + filterSaturation: 0.001, + easing: Kinetic.Easings.EaseInOut + }); + + darth.on('mouseover', function() { + tween.play(); + }); + + darth.on('mouseout', function() { + tween.reverse(); + }); + + done(); + }; + imageObj.src = 'assets/lion.png'; + + }); + + // ====================================================== + test('value tween transparancy', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + darth = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(darth); + stage.add(layer); + + darth.setFilter(Kinetic.Filters.HSV); + darth.setFilterValue(2.0); + layer.draw(); + + var tween = new Kinetic.Tween({ + node: darth, + duration: 5.0, + filterValue: 0.001, easing: Kinetic.Easings.EaseInOut }); @@ -279,4 +365,77 @@ suite('Color Pack', function() { done(); }); + // ====================================================== + test('value gradient', function (done) { + var stage = addStage(); + + var shapesLayer = new Kinetic.Layer(); + + // The important line! + shapesLayer.on('draw', function () { + var src, dst, i, w=40; + var ctx = this.getContext(); + var ctxWidth = this.getCanvas().width; + var ctxHeight = this.getCanvas().height; + var xSize = Math.floor(ctxWidth/w); + var ySize = Math.floor(ctxHeight); + for( i=0; i Date: Tue, 3 Dec 2013 18:37:17 -0500 Subject: [PATCH 2/5] Fixed jshint errors --- src/plugins/Path.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/plugins/Path.js b/src/plugins/Path.js index c9186098..a0f7db48 100644 --- a/src/plugins/Path.js +++ b/src/plugins/Path.js @@ -295,21 +295,21 @@ // Note: lineTo handlers need to be above this point case 'm': - var dx = p.shift(); - var dy = p.shift(); + var dx = p.shift(); + var dy = p.shift(); cpx += dx; cpy += dy; cmd = 'M'; // After closing the path move the current position // to the the first point of the path (if any). if(ca.length>2 && ca[ca.length-1].command==='z'){ - for(var idx=ca.length-2;idx>=0;idx--){ - if(ca[idx].command==='M'){ - cpx=ca[idx].points[0]+dx; - cpy=ca[idx].points[1]+dy; - break; - } - } + for(var idx=ca.length-2;idx>=0;idx--){ + if(ca[idx].command==='M'){ + cpx=ca[idx].points[0]+dx; + cpy=ca[idx].points[1]+dy; + break; + } + } } points.push(cpx, cpy); c = 'l'; From cfa6641d1aef5272798cd57e46c02f14aefb9433 Mon Sep 17 00:00:00 2001 From: ippo615 Date: Tue, 3 Dec 2013 19:12:17 -0500 Subject: [PATCH 3/5] Improved color stretch filter --- src/filters/ColorPack.js | 2 -- src/filters/ColorStretch.js | 8 +++++- test/unit/filters/ColorStretch-test.js | 36 +++++++++++++++++++++++++- 3 files changed, 42 insertions(+), 4 deletions(-) diff --git a/src/filters/ColorPack.js b/src/filters/ColorPack.js index ad0742d8..ae5c2dff 100644 --- a/src/filters/ColorPack.js +++ b/src/filters/ColorPack.js @@ -70,8 +70,6 @@ }; - Kinetic.Filters.HSV = Kinetic.Util._FilterWrapSingleBuffer(HSV); - Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterHue', 0); Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterSaturation', 1); Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'filterValue', 1); diff --git a/src/filters/ColorStretch.js b/src/filters/ColorStretch.js index d171290d..3b45cc27 100644 --- a/src/filters/ColorStretch.js +++ b/src/filters/ColorStretch.js @@ -90,6 +90,12 @@ }; - Kinetic.Filters.ColorStretch = Kinetic.Util._FilterWrapSingleBuffer(ColorStretch); + Kinetic.Filters.ColorStretch = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + ColorStretch(src, dst||src, opt ); + }else{ + ColorStretch.call(this, src, dst||src, opt); + } + }; })(); diff --git a/test/unit/filters/ColorStretch-test.js b/test/unit/filters/ColorStretch-test.js index 5ae56420..873a380e 100644 --- a/test/unit/filters/ColorStretch-test.js +++ b/test/unit/filters/ColorStretch-test.js @@ -1,6 +1,6 @@ suite('Color Stretch', function () { // ====================================================== - test('enhancing colors', function (done) { + test('enhancing colors on layer', function (done) { var stage = addStage(); var shapesLayer = new Kinetic.Layer(); @@ -46,4 +46,38 @@ suite('Color Stretch', function () { done(); }); + + // ====================================================== + test('on image', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + var filt = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + var orig = new Kinetic.Image({ + x: 200, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(filt); + layer.add(orig); + stage.add(layer); + + filt.setFilter(Kinetic.Filters.ColorStretch); + layer.draw(); + + done(); + }; + imageObj.src = 'assets/bamoon.jpg'; + + }); }); From b1b4eca3755ee0062a6d9595a377ebf26bd02d74 Mon Sep 17 00:00:00 2001 From: ippo615 Date: Tue, 3 Dec 2013 19:20:34 -0500 Subject: [PATCH 4/5] Fixed bug in Flip filter, works on single buffer --- src/filters/Flip.js | 48 +++++++++++++++++++++++++++++----- test/unit/filters/Flip-test.js | 42 +++++++++++++++++++++++++++++ 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/src/filters/Flip.js b/src/filters/Flip.js index aad863fb..8ba6adf8 100644 --- a/src/filters/Flip.js +++ b/src/filters/Flip.js @@ -16,16 +16,27 @@ var srcPixels = src.data, dstPixels = dst.data, xSize = src.width, + xEnd = Math.ceil(0.5*xSize), ySize = src.height, - i, m, x, y; - for (x = 0; x < xSize; x += 1) { + i, m, x, y, r,g,b,a; + for (x = 0; x < xEnd; x += 1) { for (y = 0; y < ySize; y += 1) { i = (y * xSize + x) * 4; // original m = (y * xSize + (xSize-1) - x) * 4; // flipped + // Instead of copying each row from the source to the destiation + // swap rows - this let's us achive a full flip in a single buffer + r = srcPixels[m + 0]; + g = srcPixels[m + 1]; + b = srcPixels[m + 2]; + a = srcPixels[m + 3]; dstPixels[m + 0] = srcPixels[i + 0]; dstPixels[m + 1] = srcPixels[i + 1]; dstPixels[m + 2] = srcPixels[i + 2]; dstPixels[m + 3] = srcPixels[i + 3]; + dstPixels[i + 0] = r; + dstPixels[i + 1] = g; + dstPixels[i + 2] = b; + dstPixels[i + 3] = a; } } }; @@ -47,19 +58,44 @@ dstPixels = dst.data, xSize = src.width, ySize = src.height, - i, m, x, y; + yEnd = Math.ceil(0.5*ySize), + i, m, x, y, r,g,b,a; for (x = 0; x < xSize; x += 1) { - for (y = 0; y < ySize; y += 1) { + for (y = 0; y < yEnd; y += 1) { i = (y * xSize + x) * 4; // original m = ((ySize-1 - y) * xSize + x) * 4; // flipped + // Instead of copying each row from the source to the destiation + // swap rows - this let's us achive a full flip in a single buffer + r = srcPixels[m + 0]; + g = srcPixels[m + 1]; + b = srcPixels[m + 2]; + a = srcPixels[m + 3]; dstPixels[m + 0] = srcPixels[i + 0]; dstPixels[m + 1] = srcPixels[i + 1]; dstPixels[m + 2] = srcPixels[i + 2]; dstPixels[m + 3] = srcPixels[i + 3]; + dstPixels[i + 0] = r; + dstPixels[i + 1] = g; + dstPixels[i + 2] = b; + dstPixels[i + 3] = a; } } }; - Kinetic.Filters.FlipX = Kinetic.Util._FilterWrapSingleBuffer(FlipX); - Kinetic.Filters.FlipY = Kinetic.Util._FilterWrapSingleBuffer(FlipY); + Kinetic.Filters.FlipX = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + FlipX(src, dst||src, opt ); + }else{ + FlipX.call(this, src, dst||src, opt); + } + }; + + Kinetic.Filters.FlipY = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + FlipY(src, dst||src, opt ); + }else{ + FlipY.call(this, src, dst||src, opt); + } + }; + })(); diff --git a/test/unit/filters/Flip-test.js b/test/unit/filters/Flip-test.js index 437112e2..d1750cbb 100644 --- a/test/unit/filters/Flip-test.js +++ b/test/unit/filters/Flip-test.js @@ -224,4 +224,46 @@ suite('Flip', function () { done(); }); + // ====================================================== + test('on image', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + var xFlip = new Kinetic.Image({ + x: 160, + y: 10, + image: imageObj, + draggable: true, + filter: Kinetic.Filters.FlipX + }); + var yFlip = new Kinetic.Image({ + x: 320, + y: 10, + image: imageObj, + draggable: true, + filter: Kinetic.Filters.FlipY + }); + var noFlip = new Kinetic.Image({ + x: 0, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(noFlip); + layer.add(xFlip); + layer.add(yFlip); + stage.add(layer); + + layer.draw(); + + done(); + }; + imageObj.src = 'assets/lion.png'; + + }); + }); From 21b0bb85748500884ae495e2a0c23a1b2937b74c Mon Sep 17 00:00:00 2001 From: ippo615 Date: Tue, 3 Dec 2013 19:59:43 -0500 Subject: [PATCH 5/5] Made filters (Levels, Noise, Threshold) tweenable --- src/filters/Levels.js | 30 ++++++++++++++++++-- src/filters/Mirror.js | 17 ++++++++++-- src/filters/Noise.js | 31 +++++++++++++++++++-- src/filters/Threshold.js | 31 +++++++++++++++++++-- test/unit/filters/Levels-test.js | 43 +++++++++++++++++++++++++++++ test/unit/filters/Mirror-test.js | 42 ++++++++++++++++++++++++++++ test/unit/filters/Noise-test.js | 43 +++++++++++++++++++++++++++++ test/unit/filters/Threshold-test.js | 43 +++++++++++++++++++++++++++++ 8 files changed, 271 insertions(+), 9 deletions(-) diff --git a/src/filters/Levels.js b/src/filters/Levels.js index 0ab28b24..2a41beb7 100644 --- a/src/filters/Levels.js +++ b/src/filters/Levels.js @@ -16,7 +16,7 @@ */ var Levels = function (src, dst, opt) { - var nLevels = opt.quantizationLevels || 2; + var nLevels = Math.round(opt.quantizationLevels || 2); var srcPixels = src.data, dstPixels = dst.data, nPixels = srcPixels.length, @@ -27,5 +27,31 @@ } }; - Kinetic.Filters.Levels = Kinetic.Util._FilterWrapSingleBuffer(Levels); + Kinetic.Filters.Levels = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + Levels(src, dst||src, opt ); + }else{ + Levels.call(this, src, dst||src, { + quantizationLevels: this.getQuantizationLevels() + }); + } + }; + + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'quantizationLevels', 4); + + /** + * get quantization levels. Returns the number of unique levels for each color + * channel. 2 is the minimum, 255 is the maximum. For Kinetic.Filters.Levels + * @name getQuantizationLevels + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * get quantization levels. Sets the number of unique levels for each color + * channel. 2 is the minimum, 255 is the maximum. For Kinetic.Filters.Levels + * @name setQuantizationLevels + * @method + * @memberof Kinetic.Image.prototype + */ })(); \ No newline at end of file diff --git a/src/filters/Mirror.js b/src/filters/Mirror.js index 04945ee7..2de1fd88 100644 --- a/src/filters/Mirror.js +++ b/src/filters/Mirror.js @@ -73,7 +73,20 @@ } }; - Kinetic.Filters.MirrorX = Kinetic.Util._FilterWrapSingleBuffer(MirrorX); - Kinetic.Filters.MirrorY = Kinetic.Util._FilterWrapSingleBuffer(MirrorY); + Kinetic.Filters.MirrorX = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + MirrorX(src, dst||src, opt ); + }else{ + MirrorX.call(this, src, dst||src, opt); + } + }; + + Kinetic.Filters.MirrorY = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + MirrorY(src, dst||src, opt ); + }else{ + MirrorY.call(this, src, dst||src, opt); + } + }; })(); diff --git a/src/filters/Noise.js b/src/filters/Noise.js index ed8082ef..6bdaa194 100644 --- a/src/filters/Noise.js +++ b/src/filters/Noise.js @@ -11,12 +11,12 @@ * @param {Object} opt * @param {Number} [opt.noiseAmount] The amount of noise to add. Between 0 and 255. * Each channel of each pixel will change by a random amount - * between +- amount/2. Default is 32. + * between +- amount/2. Default is 0. * @param {Number} [opt.affectAlpha] 1 to add noise to the alpha channel. * Default is 0. */ var Noise = function (src, dst, opt) { - var amount = opt.noiseAmount || 32, + var amount = opt.noiseAmount || 0, affectAlpha = opt.affectAlpha || 0; var srcPixels = src.data, dstPixels = dst.data, @@ -40,5 +40,30 @@ } }; - Kinetic.Filters.Noise = Kinetic.Util._FilterWrapSingleBuffer(Noise); + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'noiseAmount', 32); + + Kinetic.Filters.Noise = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + Noise(src, dst||src, opt ); + }else{ + Noise.call(this, src, dst||src, opt || { + noiseAmount: this.getNoiseAmount() + }); + } + }; + + /** + * get noise amount. Returns the amount of noise. Between 0 and 255. + * @name getNoiseAmount + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * set noise amount. Sets the amount of noise. Between 0 and 255. + * @name setNoiseAmount + * @method + * @memberof Kinetic.Image.prototype + */ + })(); diff --git a/src/filters/Threshold.js b/src/filters/Threshold.js index 72b6bb41..9b60a766 100644 --- a/src/filters/Threshold.js +++ b/src/filters/Threshold.js @@ -16,7 +16,10 @@ */ var Threshold = function (src, dst, opt) { - var level = opt.thresholdLevel || 128; + var level = 128; + if( opt.hasOwnProperty ){ + level = opt.thresholdLevel; + } var srcPixels = src.data, dstPixels = dst.data, nPixels = srcPixels.length, @@ -30,5 +33,29 @@ } }; - Kinetic.Filters.Threshold = Kinetic.Util._FilterWrapSingleBuffer(Threshold); + Kinetic.Factory.addFilterGetterSetter(Kinetic.Image, 'thresholdLevel', 128); + + Kinetic.Filters.Threshold = function(src,dst,opt){ + if( this === Kinetic.Filters ){ + Threshold(src, dst||src, opt ); + }else{ + Threshold.call(this, src, dst||src, opt || { + thresholdLevel: this.getThresholdLevel() + }); + } + }; + + /** + * get threshold level. Returns the level which divides the color channel (0-255). + * @name getThresholdLevel + * @method + * @memberof Kinetic.Image.prototype + */ + + /** + * set threshold level. Sets the level which divides the color channel (0-255). + * @name setThresholdLevel + * @method + * @memberof Kinetic.Image.prototype + */ })(); \ No newline at end of file diff --git a/test/unit/filters/Levels-test.js b/test/unit/filters/Levels-test.js index e03a17b6..1b8dfef2 100644 --- a/test/unit/filters/Levels-test.js +++ b/test/unit/filters/Levels-test.js @@ -127,4 +127,47 @@ suite('Levels', function () { done(); }); + // ====================================================== + test('on image tween', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + darth = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(darth); + stage.add(layer); + + darth.setFilter(Kinetic.Filters.Levels); + darth.setQuantizationLevels(16); + layer.draw(); + + var tween = new Kinetic.Tween({ + node: darth, + duration: 5.0, + quantizationLevels: 2, + easing: Kinetic.Easings.EaseInOut + }); + + darth.on('mouseover', function() { + tween.play(); + }); + + darth.on('mouseout', function() { + tween.reverse(); + }); + + done(); + }; + imageObj.src = 'assets/darth-vader.jpg'; + + }); + }); diff --git a/test/unit/filters/Mirror-test.js b/test/unit/filters/Mirror-test.js index 3fc802c4..6f556af5 100644 --- a/test/unit/filters/Mirror-test.js +++ b/test/unit/filters/Mirror-test.js @@ -193,4 +193,46 @@ suite('Mirror', function () { done(); }); + // ====================================================== + test('on image', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + var xMirror = new Kinetic.Image({ + x: 160, + y: 10, + image: imageObj, + draggable: true, + filter: Kinetic.Filters.MirrorX + }); + var yMirror = new Kinetic.Image({ + x: 320, + y: 10, + image: imageObj, + draggable: true, + filter: Kinetic.Filters.MirrorY + }); + var noMirror = new Kinetic.Image({ + x: 0, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(noMirror); + layer.add(xMirror); + layer.add(yMirror); + stage.add(layer); + + layer.draw(); + + done(); + }; + imageObj.src = 'assets/lion.png'; + + }); + }); diff --git a/test/unit/filters/Noise-test.js b/test/unit/filters/Noise-test.js index 3086b391..03363d7b 100644 --- a/test/unit/filters/Noise-test.js +++ b/test/unit/filters/Noise-test.js @@ -63,4 +63,47 @@ suite('Noise', function () { done(); }); + // ====================================================== + test('noise tween', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + darth = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(darth); + stage.add(layer); + + darth.setFilter(Kinetic.Filters.Noise); + darth.setNoiseAmount(128); + layer.draw(); + + var tween = new Kinetic.Tween({ + node: darth, + duration: 5.0, + noiseAmount: 0, + easing: Kinetic.Easings.EaseInOut + }); + + darth.on('mouseover', function() { + tween.play(); + }); + + darth.on('mouseout', function() { + tween.reverse(); + }); + + done(); + }; + imageObj.src = 'assets/lion.png'; + + }); + }); diff --git a/test/unit/filters/Threshold-test.js b/test/unit/filters/Threshold-test.js index 18261278..b34d3add 100644 --- a/test/unit/filters/Threshold-test.js +++ b/test/unit/filters/Threshold-test.js @@ -63,4 +63,47 @@ suite('Threshold', function () { done(); }); + // ====================================================== + test('image tween', function(done) { + var stage = addStage(); + + var imageObj = new Image(); + imageObj.onload = function() { + + var layer = new Kinetic.Layer(); + darth = new Kinetic.Image({ + x: 10, + y: 10, + image: imageObj, + draggable: true + }); + + layer.add(darth); + stage.add(layer); + + darth.setFilter(Kinetic.Filters.Threshold); + darth.setThresholdLevel(255); + layer.draw(); + + var tween = new Kinetic.Tween({ + node: darth, + duration: 5.0, + thresholdLevel: 0, + easing: Kinetic.Easings.EaseInOut + }); + + darth.on('mouseover', function() { + tween.play(); + }); + + darth.on('mouseout', function() { + tween.reverse(); + }); + + done(); + }; + imageObj.src = 'assets/darth-vader.jpg'; + + }); + });