fixed new bug with stage toDataURL that was introduced with the new Canvas class, and added new filter unit tests

This commit is contained in:
Eric Rowell 2012-07-21 13:29:22 -07:00
parent 4b0b3a2a20
commit d74ec8ab06
15 changed files with 156 additions and 122 deletions

88
dist/kinetic-core.js vendored
View File

@ -3,7 +3,7 @@
* http://www.kineticjs.com/ * http://www.kineticjs.com/
* Copyright 2012, Eric Rowell * Copyright 2012, Eric Rowell
* Licensed under the MIT or GPL Version 2 licenses. * Licensed under the MIT or GPL Version 2 licenses.
* Date: Jul 19 2012 * Date: Jul 21 2012
* *
* Copyright (C) 2011 - 2012 by Eric Rowell * Copyright (C) 2011 - 2012 by Eric Rowell
* *
@ -433,6 +433,19 @@ Kinetic.Canvas.prototype = {
}; };
context.strokeText = function() { context.strokeText = function() {
}; };
},
/**
* toDataURL
*/
toDataURL: function(mimeType, quality) {
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return this.element.toDataURL(mimeType, quality);
}
catch(e) {
return this.element.toDataURL();
}
} }
}; };
@ -1329,7 +1342,6 @@ Kinetic.Node = Kinetic.Class.extend({
if(this.attrs.scale.x !== 1 || this.attrs.scale.y !== 1) { if(this.attrs.scale.x !== 1 || this.attrs.scale.y !== 1) {
m.scale(this.attrs.scale.x, this.attrs.scale.y); m.scale(this.attrs.scale.x, this.attrs.scale.y);
} }
// center offset
if(this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0) { if(this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0) {
m.translate(-1 * this.attrs.offset.x, -1 * this.attrs.offset.y); m.translate(-1 * this.attrs.offset.x, -1 * this.attrs.offset.y);
} }
@ -1429,15 +1441,7 @@ Kinetic.Node = Kinetic.Class.extend({
var bufferContext = bufferCanvas.getContext(); var bufferContext = bufferCanvas.getContext();
bufferCanvas.clear(); bufferCanvas.clear();
this._draw(bufferCanvas); this._draw(bufferCanvas);
return bufferCanvas.toDataURL(mimeType, quality);
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return bufferCanvas.element.toDataURL(mimeType, quality);
}
catch(e) {
return bufferCanvas.element.toDataURL();
}
}, },
/** /**
* converts node into an image. Since the toImage * converts node into an image. Since the toImage
@ -2345,22 +2349,18 @@ Kinetic.Stage = Kinetic.Container.extend({
* @param {Number} [quality] * @param {Number} [quality]
*/ */
toDataURL: function(callback, mimeType, quality) { toDataURL: function(callback, mimeType, quality) {
/*
* need to create a canvas element rather than using the buffer canvas
* because this method is asynchonous which means that other parts of the
* code could modify the buffer canvas before it's finished
*/
var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height); var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height);
var context = canvas.getContext(); var context = canvas.getContext();
var layers = this.children; var layers = this.children;
function drawLayer(n) { function drawLayer(n) {
var layer = layers[n]; var layer = layers[n];
var canvasUrl; var layerUrl = layer.getCanvas().toDataURL(mimeType, quality);
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
canvasUrl = canvas.getElement().toDataURL(mimeType, quality);
}
catch(e) {
canvasUrl = canvas.getElement().toDataURL();
}
var imageObj = new Image(); var imageObj = new Image();
imageObj.onload = function() { imageObj.onload = function() {
context.drawImage(imageObj, 0, 0); context.drawImage(imageObj, 0, 0);
@ -2369,17 +2369,10 @@ Kinetic.Stage = Kinetic.Container.extend({
drawLayer(n + 1); drawLayer(n + 1);
} }
else { else {
try { callback(canvas.toDataURL(mimeType, quality));
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
callback(canvas.getElement().toDataURL(mimeType, quality));
}
catch(e) {
callback(canvas.getElement().toDataURL());
}
} }
}; };
imageObj.src = canvasUrl; imageObj.src = layerUrl;
} }
drawLayer(0); drawLayer(0);
}, },
@ -3168,14 +3161,7 @@ Kinetic.Layer = Kinetic.Container.extend({
* @param {Number} [quality] * @param {Number} [quality]
*/ */
toDataURL: function(mimeType, quality) { toDataURL: function(mimeType, quality) {
try { return this.getCanvas().toDataURL(mimeType, quality);
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return this.getCanvas().element.toDataURL(mimeType, quality);
}
catch(e) {
return this.getCanvas().element.toDataURL();
}
}, },
/** /**
* private draw children * private draw children
@ -3607,7 +3593,6 @@ Kinetic.Shape = Kinetic.Node.extend({
for(var n = 0; n < family.length; n++) { for(var n = 0; n < family.length; n++) {
var node = family[n]; var node = family[n];
var t = node.getTransform(); var t = node.getTransform();
var m = t.getMatrix(); var m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
} }
@ -5353,21 +5338,20 @@ Kinetic.Node.addGettersSetters(Kinetic.Path, ['data']);
// Transform // Transform
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
/* /*
* Last updated November 2011 * Last updated November 2011
* By Simon Sarris * By Simon Sarris
* www.simonsarris.com * www.simonsarris.com
* sarris@acm.org * sarris@acm.org
* *
* Free to use and distribute at will * Free to use and distribute at will
* So long as you are nice to people, etc * So long as you are nice to people, etc
*/ */
/* /*
* The usage of this class was inspired by some of the work done by a forked * The usage of this class was inspired by some of the work done by a forked
* project, KineticJS-Ext by Wappworks, which is based on Simon's Transform * project, KineticJS-Ext by Wappworks, which is based on Simon's Transform
* class. * class.
*/ */
Kinetic.Transform = function() { Kinetic.Transform = function() {
this.m = [1, 0, 0, 1, 0, 0]; this.m = [1, 0, 0, 1, 0, 0];

File diff suppressed because one or more lines are too long

View File

@ -106,14 +106,7 @@ Kinetic.Layer = Kinetic.Container.extend({
* @param {Number} [quality] * @param {Number} [quality]
*/ */
toDataURL: function(mimeType, quality) { toDataURL: function(mimeType, quality) {
try { return this.getCanvas().toDataURL(mimeType, quality);
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return this.getCanvas().element.toDataURL(mimeType, quality);
}
catch(e) {
return this.getCanvas().element.toDataURL();
}
}, },
/** /**
* private draw children * private draw children

View File

@ -735,7 +735,6 @@ Kinetic.Node = Kinetic.Class.extend({
if(this.attrs.scale.x !== 1 || this.attrs.scale.y !== 1) { if(this.attrs.scale.x !== 1 || this.attrs.scale.y !== 1) {
m.scale(this.attrs.scale.x, this.attrs.scale.y); m.scale(this.attrs.scale.x, this.attrs.scale.y);
} }
// center offset
if(this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0) { if(this.attrs.offset.x !== 0 || this.attrs.offset.y !== 0) {
m.translate(-1 * this.attrs.offset.x, -1 * this.attrs.offset.y); m.translate(-1 * this.attrs.offset.x, -1 * this.attrs.offset.y);
} }
@ -835,15 +834,7 @@ Kinetic.Node = Kinetic.Class.extend({
var bufferContext = bufferCanvas.getContext(); var bufferContext = bufferCanvas.getContext();
bufferCanvas.clear(); bufferCanvas.clear();
this._draw(bufferCanvas); this._draw(bufferCanvas);
return bufferCanvas.toDataURL(mimeType, quality);
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return bufferCanvas.element.toDataURL(mimeType, quality);
}
catch(e) {
return bufferCanvas.element.toDataURL();
}
}, },
/** /**
* converts node into an image. Since the toImage * converts node into an image. Since the toImage

View File

@ -330,7 +330,6 @@ Kinetic.Shape = Kinetic.Node.extend({
for(var n = 0; n < family.length; n++) { for(var n = 0; n < family.length; n++) {
var node = family[n]; var node = family[n];
var t = node.getTransform(); var t = node.getTransform();
var m = t.getMatrix(); var m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]); context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
} }

View File

@ -288,22 +288,18 @@ Kinetic.Stage = Kinetic.Container.extend({
* @param {Number} [quality] * @param {Number} [quality]
*/ */
toDataURL: function(callback, mimeType, quality) { toDataURL: function(callback, mimeType, quality) {
/*
* need to create a canvas element rather than using the buffer canvas
* because this method is asynchonous which means that other parts of the
* code could modify the buffer canvas before it's finished
*/
var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height); var canvas = new Kinetic.Canvas(this.attrs.width, this.attrs.height);
var context = canvas.getContext(); var context = canvas.getContext();
var layers = this.children; var layers = this.children;
function drawLayer(n) { function drawLayer(n) {
var layer = layers[n]; var layer = layers[n];
var canvasUrl; var layerUrl = layer.getCanvas().toDataURL(mimeType, quality);
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
canvasUrl = canvas.getElement().toDataURL(mimeType, quality);
}
catch(e) {
canvasUrl = canvas.getElement().toDataURL();
}
var imageObj = new Image(); var imageObj = new Image();
imageObj.onload = function() { imageObj.onload = function() {
context.drawImage(imageObj, 0, 0); context.drawImage(imageObj, 0, 0);
@ -312,17 +308,10 @@ Kinetic.Stage = Kinetic.Container.extend({
drawLayer(n + 1); drawLayer(n + 1);
} }
else { else {
try { callback(canvas.toDataURL(mimeType, quality));
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
callback(canvas.getElement().toDataURL(mimeType, quality));
}
catch(e) {
callback(canvas.getElement().toDataURL());
}
} }
}; };
imageObj.src = canvasUrl; imageObj.src = layerUrl;
} }
drawLayer(0); drawLayer(0);
}, },

View File

@ -108,5 +108,18 @@ Kinetic.Canvas.prototype = {
}; };
context.strokeText = function() { context.strokeText = function() {
}; };
},
/**
* toDataURL
*/
toDataURL: function(mimeType, quality) {
try {
// If this call fails (due to browser bug, like in Firefox 3.6),
// then revert to previous no-parameter image/png behavior
return this.element.toDataURL(mimeType, quality);
}
catch(e) {
return this.element.toDataURL();
}
} }
}; };

View File

@ -2,21 +2,20 @@
// Transform // Transform
/////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////
/* /*
* Last updated November 2011 * Last updated November 2011
* By Simon Sarris * By Simon Sarris
* www.simonsarris.com * www.simonsarris.com
* sarris@acm.org * sarris@acm.org
* *
* Free to use and distribute at will * Free to use and distribute at will
* So long as you are nice to people, etc * So long as you are nice to people, etc
*/ */
/* /*
* The usage of this class was inspired by some of the work done by a forked * The usage of this class was inspired by some of the work done by a forked
* project, KineticJS-Ext by Wappworks, which is based on Simon's Transform * project, KineticJS-Ext by Wappworks, which is based on Simon's Transform
* class. * class.
*/ */
Kinetic.Transform = function() { Kinetic.Transform = function() {
this.m = [1, 0, 0, 1, 0, 0]; this.m = [1, 0, 0, 1, 0, 0];

View File

Before

Width:  |  Height:  |  Size: 114 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

File diff suppressed because one or more lines are too long

View File

@ -21,7 +21,7 @@ function test(condition, message, warn) {
if(warn) { if(warn) {
testCounter.style.backgroundColor = 'orange'; testCounter.style.backgroundColor = 'orange';
testCounter.style.color = 'black'; testCounter.style.color = 'black';
console.warn(message + ' (NOTE: use Google Chrome for data url comparisons)'); console.warn(message + ' (NOTE: use Google Chrome for data url comparisons, run on web server for caching and filtering)');
} }
else { else {
testCounter.style.backgroundColor = 'red'; testCounter.style.backgroundColor = 'red';

View File

@ -325,7 +325,7 @@ Test.prototype.tests = {
layer.add(darth); layer.add(darth);
stage.add(layer); stage.add(layer);
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
'EVENTS - star pixel detection': function(containerId) { 'EVENTS - star pixel detection': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({

View File

@ -893,7 +893,7 @@ Test.prototype.tests = {
var expectedJson = '{"attrs":{"width":578,"height":200,"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"clearBeforeDraw":true,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":200,"y":60,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":50,"y":150},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"darth"},"nodeType":"Shape","shapeType":"Image"}]}]}'; var expectedJson = '{"attrs":{"width":578,"height":200,"throttle":80,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Stage","children":[{"attrs":{"throttle":80,"clearBeforeDraw":true,"visible":true,"listening":true,"alpha":1,"x":0,"y":0,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":0,"y":0},"dragConstraint":"none","dragBounds":{},"draggable":false},"nodeType":"Layer","children":[{"attrs":{"detectionType":"path","visible":true,"listening":true,"alpha":1,"x":200,"y":60,"scale":{"x":1,"y":1},"rotation":0,"offset":{"x":50,"y":150},"dragConstraint":"none","dragBounds":{},"draggable":false,"id":"darth"},"nodeType":"Shape","shapeType":"Image"}]}]}';
test(stage.toJSON() === expectedJson, 'problem with serializing stage with image'); test(stage.toJSON() === expectedJson, 'problem with serializing stage with image');
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
'STAGE - load stage with an image': function(containerId) { 'STAGE - load stage with an image': function(containerId) {
var imageObj = new Image(); var imageObj = new Image();
@ -910,7 +910,7 @@ Test.prototype.tests = {
image.setImage(imageObj); image.setImage(imageObj);
stage.draw(); stage.draw();
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
//////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////
// LAYERS tests // LAYERS tests
@ -1310,7 +1310,7 @@ Test.prototype.tests = {
offset: [-200, -70] offset: [-200, -70]
}); });
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
'SHAPE - add circle with radial gradient fill': function(containerId) { 'SHAPE - add circle with radial gradient fill': function(containerId) {
@ -1987,9 +1987,10 @@ Test.prototype.tests = {
test(crop.height === 15, 'crop height should be 15'); test(crop.height === 15, 'crop height should be 15');
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
'SHAPE - filter image': function(containerId) { 'SHAPE - filter image': function(containerId) {
var urls = dataUrls['SHAPE - filter image'];
var imageObj = new Image(); var imageObj = new Image();
imageObj.onload = function() { imageObj.onload = function() {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({
@ -2005,7 +2006,7 @@ Test.prototype.tests = {
y: 10, y: 10,
image: imageObj, image: imageObj,
draggable: true, draggable: true,
stroke: 'blue' stroke: 'red'
}); });
layer.add(darth); layer.add(darth);
@ -2018,10 +2019,60 @@ Test.prototype.tests = {
filter: Kinetic.Filters.Grayscale, filter: Kinetic.Filters.Grayscale,
callback: function() { callback: function() {
layer.draw(); layer.draw();
warn(layer.toDataURL() === urls[0], 'data url is incorrect');
} }
}); });
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
},
'SHAPE - filter transformed image': function(containerId) {
var urls = dataUrls['SHAPE - filter transformed image'];
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: 50,
y: 50,
//width: 438,
//height: 300,
image: imageObj,
draggable: true,
stroke: 'red',
strokeWidth: 5,
rotationDeg: 10,
scale: 0.3
});
darth.setOffset(darth.getWidth() / 2, darth.getHeight() / 2);
layer.add(darth);
stage.add(layer);
test(darth.getWidth() === 438, 'image width should be 438');
test(darth.getHeight() === 300, 'image height should be 300');
stage.onFrame(function() {
darth.rotate(0.1);
layer.draw();
});
darth.applyFilter({
filter: Kinetic.Filters.Grayscale,
callback: function() {
//stage.start();
layer.draw();
warn(layer.toDataURL() === urls[0], 'data url is incorrect');
}
});
};
imageObj.src = '../assets/darth-vader.jpg';
}, },
'SHAPE - set image fill to color then image': function(containerId) { 'SHAPE - set image fill to color then image': function(containerId) {
var imageObj = new Image(); var imageObj = new Image();
@ -2057,7 +2108,7 @@ Test.prototype.tests = {
layer.draw(); layer.draw();
}; };
imageObj.src = '../darth-vader.jpg'; imageObj.src = '../assets/darth-vader.jpg';
}, },
'SHAPE - add sprite': function(containerId) { 'SHAPE - add sprite': function(containerId) {
var imageObj = new Image(); var imageObj = new Image();
@ -2174,7 +2225,7 @@ Test.prototype.tests = {
sprite.stop(); sprite.stop();
}, 3000); }, 3000);
}; };
imageObj.src = '../scorpion-sprite.png'; imageObj.src = '../assets/scorpion-sprite.png';
}, },
'Node - shape caching': function(containerId) { 'Node - shape caching': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({
@ -2709,7 +2760,7 @@ Test.prototype.tests = {
stage.add(layer); stage.add(layer);
}; };
imageObj.src = '../lion.png'; imageObj.src = '../assets/lion.png';
}, },
'SHAPE - custom shape with fill, stroke, and strokeWidth': function(containerId) { 'SHAPE - custom shape with fill, stroke, and strokeWidth': function(containerId) {
var stage = new Kinetic.Stage({ var stage = new Kinetic.Stage({