mirror of
https://github.com/konvajs/konva.git
synced 2025-04-05 20:48:28 +08:00
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:
parent
63c6e9eea3
commit
4cf15cedb8
142
src/Context.js
142
src/Context.js
@ -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);
|
||||
|
48
src/Shape.js
48
src/Shape.js
@ -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() {
|
||||
|
10
src/Util.js
10
src/Util.js
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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');
|
||||
|
@ -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();');
|
||||
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
|
@ -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();');
|
||||
});
|
||||
|
||||
// ======================================================
|
||||
|
@ -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();');
|
||||
|
||||
});
|
||||
});
|
@ -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();');
|
||||
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user