rewrote shadow logic. fill and strokes are now both taken into account. shape and shadow opacities now work well together

This commit is contained in:
Eric Rowell 2013-09-26 01:39:50 -07:00
parent 63c6e9eea3
commit 4cf15cedb8
9 changed files with 112 additions and 120 deletions

View File

@ -61,6 +61,43 @@
this._enableTrace();
}
},
/**
* fill shape
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
fillShape: function(shape) {
if(shape.getFillEnabled()) {
this._fill(shape);
}
},
/**
* stroke shape
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
strokeShape: function(shape) {
if(shape.getStrokeEnabled()) {
this._stroke(shape);
}
},
/**
* fill then stroke
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
fillStrokeShape: function(shape) {
var fillEnabled = shape.getFillEnabled();
if(fillEnabled) {
this._fill(shape);
}
if(shape.getStrokeEnabled()) {
this._stroke(shape);
}
},
/**
* get context trace if trace is enabled
* @method
@ -165,46 +202,6 @@
this.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
}
},
/**
* fill shape
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
fillShape: function(shape) {
if(shape.getFillEnabled()) {
this._fill(shape);
}
},
/**
* stroke shape
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
strokeShape: function(shape) {
if(shape.getStrokeEnabled()) {
this._stroke(shape);
}
},
/**
* fill, stroke, and apply shadows to shape. Shadows
* will only be applied to either the fill or stroke.  Fill
* is given priority over stroke.
* @method
* @memberof Kinetic.Context.prototype
* @param {Kinetic.Shape} shape
*/
fillStrokeShape: function(shape) {
var fillEnabled = shape.getFillEnabled();
if(fillEnabled) {
this._fill(shape);
}
if(shape.getStrokeEnabled()) {
this._stroke(shape, shape.hasShadow() && shape.hasFill() && fillEnabled);
}
},
_applyLineCap: function(shape) {
var lineCap = shape.getLineCap();
if(lineCap) {
@ -381,7 +378,7 @@
_enableTrace: function() {
var that = this,
len = CONTEXT_METHODS.length,
_roundArrValues = Kinetic.Util._roundArrValues,
_simplifyArray = Kinetic.Util._simplifyArray,
origSetter = this.setAttr,
n, args;
@ -392,7 +389,7 @@
ret;
that[methodName] = function() {
args = _roundArrValues(Array.prototype.slice.call(arguments, 0));
args = _simplifyArray(Array.prototype.slice.call(arguments, 0));
ret = origMethod.apply(that, arguments);
that._trace({
@ -482,18 +479,13 @@
this.setAttr('fillStyle', grd);
this.fill();
},
_fill: function(shape, skipShadow) {
_fill: function(shape) {
var hasColor = shape.getFill(),
hasPattern = shape.getFillPatternImage(),
hasLinearGradient = shape.getFillLinearGradientColorStops(),
hasRadialGradient = shape.getFillRadialGradientColorStops(),
fillPriority = shape.getFillPriority();
if(!skipShadow && shape.hasShadow()) {
this.save();
this._applyShadow(shape);
}
// priority fills
if(hasColor && fillPriority === 'color') {
this._fillColor(shape);
@ -520,13 +512,8 @@
else if(hasRadialGradient) {
this._fillRadialGradient(shape);
}
if(!skipShadow && shape.hasShadow()) {
this.restore();
this._fill(shape, true);
}
},
_stroke: function(shape, skipShadow) {
_stroke: function(shape) {
var stroke = shape.getStroke(),
strokeWidth = shape.getStrokeWidth(),
dashArray = shape.getDashArray(),
@ -543,55 +530,36 @@
if(dashArray && shape.getDashArrayEnabled()) {
this.setLineDash(dashArray);
}
if(!skipShadow && shape.hasShadow()) {
this.save();
this._applyShadow(shape);
}
this.setAttr('lineWidth', strokeWidth || 2);
this.setAttr('strokeStyle', stroke || 'black');
shape._strokeFunc(this);
if(!skipShadow && shape.hasShadow()) {
this.restore();
this._stroke(shape, true);
}
/////////////////////
if (!strokeScaleEnabled) {
this.restore();
}
}
},
applyShadow: function(shape, drawFunc) {
this.save();
this._applyShadow(shape);
drawFunc();
this.restore();
drawFunc();
},
_applyShadow: function(shape) {
var util, absOpacity, color, blur, offset, shadowOpacity;
if(shape.hasShadow() && shape.getShadowEnabled()) {
util = Kinetic.Util;
absOpacity = shape.getAbsoluteOpacity();
color = util.get(shape.getShadowColor(), 'black');
blur = util.get(shape.getShadowBlur(), 5);
shadowOpacity = util.get(shape.getShadowOpacity(), 0);
var util = Kinetic.Util,
absOpacity = shape.getAbsoluteOpacity(),
color = util.get(shape.getShadowColor(), 'black'),
blur = util.get(shape.getShadowBlur(), 5),
shadowOpacity = util.get(shape.getShadowOpacity(), 0),
offset = util.get(shape.getShadowOffset(), {
x: 0,
y: 0
});
if(shadowOpacity) {
this.setAttr('globalAlpha', shadowOpacity * absOpacity);
}
this.setAttr('shadowColor', color);
this.setAttr('shadowBlur', blur);
this.setAttr('shadowOffsetX', offset.x);
this.setAttr('shadowOffsetY', offset.y);
if(shadowOpacity) {
this.setAttr('globalAlpha', shadowOpacity * absOpacity);
}
this.setAttr('shadowColor', color);
this.setAttr('shadowBlur', blur);
this.setAttr('shadowOffsetX', offset.x);
this.setAttr('shadowOffsetY', offset.y);
}
};
Kinetic.Util.extend(Kinetic.SceneContext, Kinetic.Context);

View File

@ -208,20 +208,46 @@
delete Kinetic.shapes[this.colorKey];
return this;
},
drawScene: function(canvas) {
canvas = canvas || this.getLayer().getCanvas();
var drawFunc = this.getDrawFunc(),
context = canvas.getContext();
drawScene: function(can) {
var canvas = can || this.getLayer().getCanvas(),
context = canvas.getContext(),
drawFunc = this.getDrawFunc(),
applyShadow = this.hasShadow() && this.getShadowEnabled(),
stage, tempCanvas, tempContext;
if(drawFunc && this.isVisible()) {
context.save();
context._applyOpacity(this);
context._applyLineJoin(this);
context._applyAncestorTransforms(this);
drawFunc.call(this, context);
context.restore();
if (applyShadow) {
stage = this.getStage();
tempCanvas = new Kinetic.SceneCanvas({
width: stage.getWidth(),
height: stage.getHeight()
});
tempContext = tempCanvas.getContext();
tempContext.save();
tempContext._applyLineJoin(this);
tempContext._applyAncestorTransforms(this);
drawFunc.call(this, tempContext);
tempContext.restore();
context.save();
context.save();
context._applyShadow(this);
context.drawImage(tempCanvas._canvas, 0, 0);
context.restore();
context._applyOpacity(this);
context.drawImage(tempCanvas._canvas, 0, 0);
context.restore();
}
else {
context.save();
context._applyOpacity(this);
context._applyLineJoin(this);
context._applyAncestorTransforms(this);
drawFunc.call(this, context);
context.restore();
}
}
return this;
},
drawHit: function() {

View File

@ -340,17 +340,21 @@
}
return false;
},
_roundArrValues: function(arr) {
_simplifyArray: function(arr) {
var retArr = [],
len = arr.length,
_isNumber = Kinetic.Util._isNumber,
util = Kinetic.Util,
n, val;
for (n=0; n<len; n++) {
val = arr[n];
if (_isNumber(val)) {
if (util._isNumber(val)) {
val = Math.round(val * 1000) / 1000;
}
else if (!util._isString(val)) {
val = val.toString();
}
retArr.push(val);
}

View File

@ -82,14 +82,7 @@
params = [image, 0, 0, width, height];
}
if(this.hasShadow()) {
context.applyShadow(this, function() {
context.drawImage.apply(context, params);
});
}
else {
context.drawImage.apply(context, params);
}
context.drawImage.apply(context, params);
}
},
drawHitFunc: function(context) {

View File

@ -357,7 +357,7 @@ suite('Shape-test', function() {
layer.draw();
var trace = layer.getContext().getTrace();
//console.log(trace);
assert.equal(trace, 'clearRect(0,0,578,200);save();transform(3,0,0,1,289,100);beginPath();arc(0,0,70,0,6.283,false);closePath();save();shadowColor=black;shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;fillStyle=green;fill();restore();fillStyle=green;fill();setLineDash([10,10]);lineWidth=4;strokeStyle=black;stroke();restore();clearRect(0,0,578,200);save();transform(3,0,0,1,289,100);beginPath();arc(0,0,70,0,6.283,false);closePath();save();shadowColor=black;shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;fillStyle=green;fill();restore();fillStyle=green;fill();save();setTransform(1,0,0,1,0,0);setLineDash([10,10]);lineWidth=4;strokeStyle=black;stroke();restore();restore();');
assert.equal(trace, 'clearRect(0,0,578,200);save();save();shadowColor=black;shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;drawImage([object HTMLCanvasElement],0,0);restore();drawImage([object HTMLCanvasElement],0,0);restore();clearRect(0,0,578,200);save();save();shadowColor=black;shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;drawImage([object HTMLCanvasElement],0,0);restore();drawImage([object HTMLCanvasElement],0,0);restore();');
circle.disableFill();
assert.equal(circle.getFillEnabled(), false, 'fillEnabled should be false');

View File

@ -64,7 +64,8 @@ suite('Label', function() {
var relaxedTrace = layer.getContext().getTrace(true);
//console.log(relaxedTrace);
assert.equal(relaxedTrace, 'clearRect();save();lineJoin;transform();beginPath();moveTo();lineTo();lineTo();lineTo();lineTo();lineTo();lineTo();closePath();save();globalAlpha;shadowColor;shadowBlur;shadowOffsetX;shadowOffsetY;fillStyle;fill();restore();fillStyle;fill();lineWidth;strokeStyle;stroke();restore();save();transform();font;textBaseline;textAlign;save();translate();translate();save();fillStyle;fillText();restore();translate();restore();restore();clearRect();save();lineJoin;transform();beginPath();moveTo();lineTo();lineTo();lineTo();lineTo();lineTo();lineTo();closePath();save();globalAlpha;shadowColor;shadowBlur;shadowOffsetX;shadowOffsetY;fillStyle;fill();restore();fillStyle;fill();lineWidth;strokeStyle;stroke();restore();save();transform();font;textBaseline;textAlign;save();translate();translate();save();fillStyle;fillText();restore();translate();restore();restore();');
assert.equal(relaxedTrace, 'clearRect();save();save();globalAlpha;shadowColor;shadowBlur;shadowOffsetX;shadowOffsetY;drawImage();restore();drawImage();restore();save();transform();font;textBaseline;textAlign;save();translate();translate();save();fillStyle;fillText();restore();translate();restore();restore();clearRect();save();save();globalAlpha;shadowColor;shadowBlur;shadowOffsetX;shadowOffsetY;drawImage();restore();drawImage();restore();save();transform();font;textBaseline;textAlign;save();translate();translate();save();fillStyle;fillText();restore();translate();restore();restore();');
});
// ======================================================

View File

@ -104,7 +104,7 @@ suite('Path', function() {
var trace = layer.getContext().getTrace();
//console.log(trace);
assert.equal(trace, 'clearRect(0,0,578,200);save();transform(1,0,0,1,0,0);beginPath();moveTo(200,100);lineTo(300,100);lineTo(300,150);closePath();save();globalAlpha=0.5;shadowColor=maroon;shadowBlur=2;shadowOffsetX=10;shadowOffsetY=10;fillStyle=#fcc;fill();restore();fillStyle=#fcc;fill();lineWidth=2;strokeStyle=#333;stroke();restore();');
assert.equal(trace, 'clearRect(0,0,578,200);save();save();globalAlpha=0.5;shadowColor=maroon;shadowBlur=2;shadowOffsetX=10;shadowOffsetY=10;drawImage([object HTMLCanvasElement],0,0);restore();drawImage([object HTMLCanvasElement],0,0);restore();');
});
// ======================================================

View File

@ -147,17 +147,17 @@ suite('Line', function() {
shadowColor: 'black',
shadowBlur: 20,
shadowOffset: 10,
shadowOpacity: 0.3
shadowOpacity: 0.5,
draggable: true
});
layer.add(line);
stage.add(layer);
var trace = layer.getContext().getTrace();
//console.log(trace);
assert.equal(trace, 'clearRect(0,0,578,200);save();lineJoin=round;transform(1,0,0,1,0,0);beginPath();moveTo(73,160);lineTo(340,23);lineCap=round;save();globalAlpha=0.3;shadowColor=black;shadowBlur=20;shadowOffsetX=10;shadowOffsetY=10;lineWidth=20;strokeStyle=blue;stroke();restore();lineCap=round;lineWidth=20;strokeStyle=blue;stroke();restore();');
var relaxedTrace = layer.getContext().getTrace(true);
//console.log(relaxedTrace);
assert.equal(relaxedTrace, 'clearRect();save();save();globalAlpha;shadowColor;shadowBlur;shadowOffsetX;shadowOffsetY;drawImage();restore();drawImage();restore();');
});
});

View File

@ -31,7 +31,7 @@ suite('Rect', function(){
});
// ======================================================
test('add rect with shadow, rotation, corner radius, and opacity', function(){
test('add rect with shadow, corner radius, and opacity', function(){
var stage = addStage();
var layer = new Kinetic.Layer();
@ -63,8 +63,8 @@ suite('Rect', function(){
assert.equal(rect.getCornerRadius(), 5);
var trace = layer.getContext().getTrace();
//console.log(layer.getContext().traceArr);
assert.equal(trace, 'clearRect(0,0,578,200);save();globalAlpha=0.4;transform(1,0,0,1,100,50);beginPath();moveTo(5,0);lineTo(95,0);arc(95,5,5,4.712,0,false);lineTo(100,45);arc(95,45,5,0,1.571,false);lineTo(5,50);arc(5,45,5,1.571,3.142,false);lineTo(0,5);arc(5,5,5,3.142,4.712,false);closePath();save();globalAlpha=0.2;shadowColor=red;shadowBlur=10;shadowOffsetX=5;shadowOffsetY=5;fillStyle=green;fill();restore();fillStyle=green;fill();lineWidth=2;strokeStyle=blue;stroke();restore();');
//console.log(trace);
assert.equal(trace, 'clearRect(0,0,578,200);save();save();globalAlpha=0.2;shadowColor=red;shadowBlur=10;shadowOffsetX=5;shadowOffsetY=5;drawImage([object HTMLCanvasElement],0,0);restore();globalAlpha=0.4;drawImage([object HTMLCanvasElement],0,0);restore();');
});