fixed several bugs with toImage(). toImage() can now also accept x and y params. added extensive caching unit test. removed drawBuffer logic as it is no longer needed

This commit is contained in:
Eric Rowell
2012-12-11 00:08:59 -08:00
parent 9b7f0ea8ff
commit cb8d36c393
7 changed files with 135 additions and 107 deletions

View File

@@ -241,11 +241,11 @@
this.drawScene(); this.drawScene();
this.drawHit(); this.drawHit();
}, },
drawScene: function() { drawScene: function(canvas) {
if(this.isVisible()) { if(this.isVisible()) {
var children = this.children, len = children.length; var children = this.children, len = children.length;
for(var n = 0; n < len; n++) { for(var n = 0; n < len; n++) {
children[n].drawScene(); children[n].drawScene(canvas);
} }
} }
}, },
@@ -256,14 +256,6 @@
children[n].drawHit(); children[n].drawHit();
} }
} }
},
drawBuffer: function(canvas) {
if(this.isVisible()) {
var children = this.children, len = children.length;
for(var n = 0; n < len; n++) {
children[n].drawBuffer(canvas);
}
}
} }
}; };
Kinetic.Global.extend(Kinetic.Container, Kinetic.Node); Kinetic.Global.extend(Kinetic.Container, Kinetic.Node);

View File

@@ -81,11 +81,12 @@
* @methodOf Kinetic.Layer.prototype * @methodOf Kinetic.Layer.prototype
* @param {Kinetic.Canvas} [canvas] * @param {Kinetic.Canvas} [canvas]
*/ */
drawScene: function() { drawScene: function(canvas) {
canvas = canvas || this.getCanvas();
if(this.attrs.clearBeforeDraw) { if(this.attrs.clearBeforeDraw) {
this.getCanvas().clear(); canvas.clear();
} }
Kinetic.Container.prototype.drawScene.call(this); Kinetic.Container.prototype.drawScene.call(this, canvas);
}, },
/** /**
* set before draw handler * set before draw handler
@@ -201,47 +202,6 @@
getLayer: function() { getLayer: function() {
return this; return this;
}, },
/**
* Creates a composite data URL. If MIME type is not
* specified, then "image/png" will result. For "image/jpeg", specify a quality
* level as quality (range 0.0 - 1.0). Note that this method works
* differently from toDataURL() for other nodes because it generates an absolute dataURL
* based on what's currently drawn on the layer, rather than drawing
* the current state of each child node
* @name toDataURL
* @methodOf Kinetic.Layer.prototype
* @param {Object} config
* @param {String} [config.mimeType] mime type. can be "image/png" or "image/jpeg".
* "image/png" is the default
* @param {Number} [config.width] data url image width
* @param {Number} [config.height] data url image height
* @param {Number} [config.quality] jpeg quality. If using an "image/jpeg" mimeType,
* you can specify the quality from 0 to 1, where 0 is very poor quality and 1
* is very high quality
*/
toDataURL: function(config) {
var canvas;
var mimeType = config && config.mimeType ? config.mimeType : null;
var quality = config && config.quality ? config.quality : null;
/*
* if layer is hidden, return blank canvas
* else if width and height are defined, create blank canvas and draw onto it
* else return canvas as is
*/
if(!this.isVisible()) {
var stage = this.getStage();
canvas = new Kinetic.SceneCanvas(stage.getWidth(), stage.getHeight());
}
else if(config && config.width && config.height) {
canvas = new Kinetic.SceneCanvas(config.width, config.height);
this.draw(canvas);
}
else {
canvas = this.getCanvas();
}
return canvas.toDataURL(mimeType, quality);
},
/** /**
* remove layer from stage * remove layer from stage
*/ */

View File

@@ -738,20 +738,25 @@
* is very high quality * is very high quality
*/ */
toDataURL: function(config) { toDataURL: function(config) {
var mimeType = config && config.mimeType ? config.mimeType : null; config = config || {};
var quality = config && config.quality ? config.quality : null; var mimeType = config.mimeType || null, quality = config.quality || null, canvas, context, x = config.x || 0, y = config.y || 0;
var canvas;
//if width and height are defined, create new canvas to draw on, else reuse stage hit canvas //if width and height are defined, create new canvas to draw on, else reuse stage buffer canvas
if(config && config.width && config.height) { if(config.width && config.height) {
canvas = new Kinetic.SceneCanvas(config.width, config.height); canvas = new Kinetic.SceneCanvas(config.width, config.height);
} }
else { else {
canvas = this.getStage().bufferCanvas; canvas = this.getStage().bufferCanvas;
canvas.clear(); canvas.clear();
} }
context = canvas.getContext();
context.save();
if(x || y) {
context.translate(-1 * x, -1 * y);
}
this.drawScene(canvas);
context.restore();
this.drawBuffer(canvas);
return canvas.toDataURL(mimeType, quality); return canvas.toDataURL(mimeType, quality);
}, },
/** /**

View File

@@ -209,7 +209,7 @@
var stage = this.getStage(); var stage = this.getStage();
var hitCanvas = stage.hitCanvas; var hitCanvas = stage.hitCanvas;
hitCanvas.clear(); hitCanvas.clear();
this.drawBuffer(hitCanvas); this.drawScene(hitCanvas);
var p = hitCanvas.context.getImageData(Math.round(pos.x), Math.round(pos.y), 1, 1).data; var p = hitCanvas.context.getImageData(Math.round(pos.x), Math.round(pos.y), 1, 1).data;
return p[3] > 0; return p[3] > 0;
}, },
@@ -217,33 +217,8 @@
Kinetic.Node.prototype.remove.call(this); Kinetic.Node.prototype.remove.call(this);
delete Kinetic.Global.shapes[this.colorKey]; delete Kinetic.Global.shapes[this.colorKey];
}, },
drawBuffer: function(canvas) { drawScene: function(canvas) {
var attrs = this.attrs, drawFunc = attrs.drawFunc, context = canvas.getContext(); var attrs = this.attrs, drawFunc = attrs.drawFunc, canvas = canvas || this.getLayer().getCanvas(), context = canvas.getContext();
if(drawFunc && this.isVisible()) {
var stage = this.getStage(), family = [], parent = this.parent;
family.unshift(this);
while(parent) {
family.unshift(parent);
parent = parent.parent;
}
context.save();
canvas._applyOpacity(this);
canvas._applyLineJoin(this);
var len = family.length;
for(var n = 0; n < len; n++) {
var node = family[n], t = node.getTransform(), m = t.getMatrix();
context.transform(m[0], m[1], m[2], m[3], m[4], m[5]);
}
drawFunc.call(this, canvas);
context.restore();
}
},
drawScene: function() {
var attrs = this.attrs, drawFunc = attrs.drawFunc, canvas = this.getLayer().getCanvas(), context = canvas.getContext();
if(drawFunc && this.isVisible()) { if(drawFunc && this.isVisible()) {
var stage = this.getStage(), family = [], parent = this.parent; var stage = this.getStage(), family = [], parent = this.parent;

View File

@@ -193,6 +193,8 @@
var height = config && config.height ? config.height : this.attrs.height; var height = config && config.height ? config.height : this.attrs.height;
var canvas = new Kinetic.SceneCanvas(width, height); var canvas = new Kinetic.SceneCanvas(width, height);
var context = canvas.getContext(); var context = canvas.getContext();
var layers = this.children; var layers = this.children;
function drawLayer(n) { function drawLayer(n) {

File diff suppressed because one or more lines are too long

View File

@@ -770,23 +770,116 @@ Test.Modules.NODE = {
} }
}); });
/* showHit(layer);
group.toImage({ },
callback: function(imageObj) { 'cache shape, group, layer, and stage': function(containerId) {
test(Kinetic.Type._isElement(imageObj), 'group toImage() should be an image object'); var stage = new Kinetic.Stage({
} container: containerId,
}); width: 578,
layer.toImage({ height: 200
callback: function(imageObj) { });
test(Kinetic.Type._isElement(imageObj), 'layer toImage() should be an image object'); var layer = new Kinetic.Layer();
} var group = new Kinetic.Group();
}); var rect = new Kinetic.Rect({
stage.toImage({ x: 10,
callback: function(imageObj) { y: 10,
test(Kinetic.Type._isElement(imageObj), 'stage toImage() should be an image object'); width: 50,
} height: 30,
}); fill: 'green',
*/ stroke: 'black',
strokeWidth: 4,
draggable: true
});
group.add(rect);
layer.add(group);
stage.add(layer);
// cache shape
rect.toImage({
x: 8,
y: 8,
width: 54,
height: 34,
callback: function(imageObj) {
var cachedShape = new Kinetic.Image({
image: imageObj,
x: 60,
y: 60,
draggable: true
});
group.add(cachedShape);
layer.draw();
// cache group
group.toImage({
x: 8,
y: 8,
width: 106,
height: 86,
callback: function(imageObj) {
var cachedGroup = new Kinetic.Image({
image: imageObj,
x: 100,
y: 8,
draggable: true
});
group.add(cachedGroup);
layer.draw();
// cache layer
layer.toImage({
x: 8,
y: 8,
width: 200,
height: 86,
callback: function(imageObj) {
var cachedLayer = new Kinetic.Image({
image: imageObj,
x: 190,
y: 8,
draggable: true
});
group.add(cachedLayer);
layer.draw();
var dataUrl = layer.toDataURL();
// cache stage
stage.toImage({
x: 8,
y: 8,
width: 400,
height: 86,
callback: function(imageObj) {
var cachedStage = new Kinetic.Image({
image: imageObj,
x: 8,
y: 100,
draggable: true
});
group.add(cachedStage);
layer.draw();
var dataUrl = layer.toDataURL();
//console.log(dataUrl);
warn(dataUrl === dataUrls['cache shape, group, layer, and stage'], 'problem caching shape, group, layer, and stage');
}
});
}
});
}
});
}
});
showHit(layer); showHit(layer);
}, },
@@ -2009,7 +2102,7 @@ Test.Modules.NODE = {
var group = new Kinetic.Group(); var group = new Kinetic.Group();
var drawTriangle = function(canvas) { var drawTriangle = function(canvas) {
var context = canvas.getContext(); var context = canvas.getContext();
context.beginPath(); context.beginPath();
context.moveTo(200, 50); context.moveTo(200, 50);
context.lineTo(420, 80); context.lineTo(420, 80);
@@ -2053,7 +2146,7 @@ Test.Modules.NODE = {
}, },
'load stage with custom shape using json': function(containerId) { 'load stage with custom shape using json': function(containerId) {
var drawTriangle = function(canvas) { var drawTriangle = function(canvas) {
var context = canvas.getContext(); var context = canvas.getContext();
context.beginPath(); context.beginPath();
context.moveTo(200, 50); context.moveTo(200, 50);
context.lineTo(420, 80); context.lineTo(420, 80);