mirror of
https://github.com/konvajs/konva.git
synced 2025-04-24 19:03:56 +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
src
test/unit
142
src/Context.js
142
src/Context.js
@ -61,6 +61,43 @@
|
|||||||
this._enableTrace();
|
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
|
* get context trace if trace is enabled
|
||||||
* @method
|
* @method
|
||||||
@ -165,46 +202,6 @@
|
|||||||
this.clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
|
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) {
|
_applyLineCap: function(shape) {
|
||||||
var lineCap = shape.getLineCap();
|
var lineCap = shape.getLineCap();
|
||||||
if(lineCap) {
|
if(lineCap) {
|
||||||
@ -381,7 +378,7 @@
|
|||||||
_enableTrace: function() {
|
_enableTrace: function() {
|
||||||
var that = this,
|
var that = this,
|
||||||
len = CONTEXT_METHODS.length,
|
len = CONTEXT_METHODS.length,
|
||||||
_roundArrValues = Kinetic.Util._roundArrValues,
|
_simplifyArray = Kinetic.Util._simplifyArray,
|
||||||
origSetter = this.setAttr,
|
origSetter = this.setAttr,
|
||||||
n, args;
|
n, args;
|
||||||
|
|
||||||
@ -392,7 +389,7 @@
|
|||||||
ret;
|
ret;
|
||||||
|
|
||||||
that[methodName] = function() {
|
that[methodName] = function() {
|
||||||
args = _roundArrValues(Array.prototype.slice.call(arguments, 0));
|
args = _simplifyArray(Array.prototype.slice.call(arguments, 0));
|
||||||
ret = origMethod.apply(that, arguments);
|
ret = origMethod.apply(that, arguments);
|
||||||
|
|
||||||
that._trace({
|
that._trace({
|
||||||
@ -482,18 +479,13 @@
|
|||||||
this.setAttr('fillStyle', grd);
|
this.setAttr('fillStyle', grd);
|
||||||
this.fill();
|
this.fill();
|
||||||
},
|
},
|
||||||
_fill: function(shape, skipShadow) {
|
_fill: function(shape) {
|
||||||
var hasColor = shape.getFill(),
|
var hasColor = shape.getFill(),
|
||||||
hasPattern = shape.getFillPatternImage(),
|
hasPattern = shape.getFillPatternImage(),
|
||||||
hasLinearGradient = shape.getFillLinearGradientColorStops(),
|
hasLinearGradient = shape.getFillLinearGradientColorStops(),
|
||||||
hasRadialGradient = shape.getFillRadialGradientColorStops(),
|
hasRadialGradient = shape.getFillRadialGradientColorStops(),
|
||||||
fillPriority = shape.getFillPriority();
|
fillPriority = shape.getFillPriority();
|
||||||
|
|
||||||
if(!skipShadow && shape.hasShadow()) {
|
|
||||||
this.save();
|
|
||||||
this._applyShadow(shape);
|
|
||||||
}
|
|
||||||
|
|
||||||
// priority fills
|
// priority fills
|
||||||
if(hasColor && fillPriority === 'color') {
|
if(hasColor && fillPriority === 'color') {
|
||||||
this._fillColor(shape);
|
this._fillColor(shape);
|
||||||
@ -520,13 +512,8 @@
|
|||||||
else if(hasRadialGradient) {
|
else if(hasRadialGradient) {
|
||||||
this._fillRadialGradient(shape);
|
this._fillRadialGradient(shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!skipShadow && shape.hasShadow()) {
|
|
||||||
this.restore();
|
|
||||||
this._fill(shape, true);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
_stroke: function(shape, skipShadow) {
|
_stroke: function(shape) {
|
||||||
var stroke = shape.getStroke(),
|
var stroke = shape.getStroke(),
|
||||||
strokeWidth = shape.getStrokeWidth(),
|
strokeWidth = shape.getStrokeWidth(),
|
||||||
dashArray = shape.getDashArray(),
|
dashArray = shape.getDashArray(),
|
||||||
@ -543,55 +530,36 @@
|
|||||||
if(dashArray && shape.getDashArrayEnabled()) {
|
if(dashArray && shape.getDashArrayEnabled()) {
|
||||||
this.setLineDash(dashArray);
|
this.setLineDash(dashArray);
|
||||||
}
|
}
|
||||||
if(!skipShadow && shape.hasShadow()) {
|
|
||||||
this.save();
|
|
||||||
this._applyShadow(shape);
|
|
||||||
}
|
|
||||||
this.setAttr('lineWidth', strokeWidth || 2);
|
this.setAttr('lineWidth', strokeWidth || 2);
|
||||||
this.setAttr('strokeStyle', stroke || 'black');
|
this.setAttr('strokeStyle', stroke || 'black');
|
||||||
shape._strokeFunc(this);
|
shape._strokeFunc(this);
|
||||||
|
|
||||||
if(!skipShadow && shape.hasShadow()) {
|
|
||||||
this.restore();
|
|
||||||
this._stroke(shape, true);
|
|
||||||
}
|
|
||||||
/////////////////////
|
|
||||||
|
|
||||||
if (!strokeScaleEnabled) {
|
if (!strokeScaleEnabled) {
|
||||||
this.restore();
|
this.restore();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
applyShadow: function(shape, drawFunc) {
|
|
||||||
this.save();
|
|
||||||
this._applyShadow(shape);
|
|
||||||
drawFunc();
|
|
||||||
this.restore();
|
|
||||||
drawFunc();
|
|
||||||
},
|
|
||||||
_applyShadow: function(shape) {
|
_applyShadow: function(shape) {
|
||||||
var util, absOpacity, color, blur, offset, shadowOpacity;
|
var util = Kinetic.Util,
|
||||||
|
absOpacity = shape.getAbsoluteOpacity(),
|
||||||
if(shape.hasShadow() && shape.getShadowEnabled()) {
|
color = util.get(shape.getShadowColor(), 'black'),
|
||||||
util = Kinetic.Util;
|
blur = util.get(shape.getShadowBlur(), 5),
|
||||||
absOpacity = shape.getAbsoluteOpacity();
|
shadowOpacity = util.get(shape.getShadowOpacity(), 0),
|
||||||
color = util.get(shape.getShadowColor(), 'black');
|
|
||||||
blur = util.get(shape.getShadowBlur(), 5);
|
|
||||||
shadowOpacity = util.get(shape.getShadowOpacity(), 0);
|
|
||||||
offset = util.get(shape.getShadowOffset(), {
|
offset = util.get(shape.getShadowOffset(), {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 0
|
y: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
if(shadowOpacity) {
|
if(shadowOpacity) {
|
||||||
this.setAttr('globalAlpha', shadowOpacity * absOpacity);
|
this.setAttr('globalAlpha', shadowOpacity * absOpacity);
|
||||||
}
|
|
||||||
|
|
||||||
this.setAttr('shadowColor', color);
|
|
||||||
this.setAttr('shadowBlur', blur);
|
|
||||||
this.setAttr('shadowOffsetX', offset.x);
|
|
||||||
this.setAttr('shadowOffsetY', offset.y);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
Kinetic.Util.extend(Kinetic.SceneContext, Kinetic.Context);
|
||||||
|
48
src/Shape.js
48
src/Shape.js
@ -208,20 +208,46 @@
|
|||||||
delete Kinetic.shapes[this.colorKey];
|
delete Kinetic.shapes[this.colorKey];
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
drawScene: function(canvas) {
|
drawScene: function(can) {
|
||||||
canvas = canvas || this.getLayer().getCanvas();
|
var canvas = can || this.getLayer().getCanvas(),
|
||||||
|
context = canvas.getContext(),
|
||||||
var drawFunc = this.getDrawFunc(),
|
drawFunc = this.getDrawFunc(),
|
||||||
context = canvas.getContext();
|
applyShadow = this.hasShadow() && this.getShadowEnabled(),
|
||||||
|
stage, tempCanvas, tempContext;
|
||||||
|
|
||||||
if(drawFunc && this.isVisible()) {
|
if(drawFunc && this.isVisible()) {
|
||||||
context.save();
|
if (applyShadow) {
|
||||||
context._applyOpacity(this);
|
stage = this.getStage();
|
||||||
context._applyLineJoin(this);
|
tempCanvas = new Kinetic.SceneCanvas({
|
||||||
context._applyAncestorTransforms(this);
|
width: stage.getWidth(),
|
||||||
drawFunc.call(this, context);
|
height: stage.getHeight()
|
||||||
context.restore();
|
});
|
||||||
|
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;
|
return this;
|
||||||
},
|
},
|
||||||
drawHit: function() {
|
drawHit: function() {
|
||||||
|
10
src/Util.js
10
src/Util.js
@ -340,17 +340,21 @@
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
},
|
},
|
||||||
_roundArrValues: function(arr) {
|
_simplifyArray: function(arr) {
|
||||||
var retArr = [],
|
var retArr = [],
|
||||||
len = arr.length,
|
len = arr.length,
|
||||||
_isNumber = Kinetic.Util._isNumber,
|
util = Kinetic.Util,
|
||||||
n, val;
|
n, val;
|
||||||
|
|
||||||
for (n=0; n<len; n++) {
|
for (n=0; n<len; n++) {
|
||||||
val = arr[n];
|
val = arr[n];
|
||||||
if (_isNumber(val)) {
|
if (util._isNumber(val)) {
|
||||||
val = Math.round(val * 1000) / 1000;
|
val = Math.round(val * 1000) / 1000;
|
||||||
}
|
}
|
||||||
|
else if (!util._isString(val)) {
|
||||||
|
val = val.toString();
|
||||||
|
}
|
||||||
|
|
||||||
retArr.push(val);
|
retArr.push(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,14 +82,7 @@
|
|||||||
params = [image, 0, 0, width, height];
|
params = [image, 0, 0, width, height];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.hasShadow()) {
|
context.drawImage.apply(context, params);
|
||||||
context.applyShadow(this, function() {
|
|
||||||
context.drawImage.apply(context, params);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
context.drawImage.apply(context, params);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
drawHitFunc: function(context) {
|
drawHitFunc: function(context) {
|
||||||
|
@ -357,7 +357,7 @@ suite('Shape-test', function() {
|
|||||||
layer.draw();
|
layer.draw();
|
||||||
var trace = layer.getContext().getTrace();
|
var trace = layer.getContext().getTrace();
|
||||||
//console.log(trace);
|
//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();
|
circle.disableFill();
|
||||||
assert.equal(circle.getFillEnabled(), false, 'fillEnabled should be false');
|
assert.equal(circle.getFillEnabled(), false, 'fillEnabled should be false');
|
||||||
|
@ -64,7 +64,8 @@ suite('Label', function() {
|
|||||||
var relaxedTrace = layer.getContext().getTrace(true);
|
var relaxedTrace = layer.getContext().getTrace(true);
|
||||||
//console.log(relaxedTrace);
|
//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();
|
var trace = layer.getContext().getTrace();
|
||||||
|
|
||||||
//console.log(trace);
|
//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',
|
shadowColor: 'black',
|
||||||
shadowBlur: 20,
|
shadowBlur: 20,
|
||||||
shadowOffset: 10,
|
shadowOffset: 10,
|
||||||
shadowOpacity: 0.3
|
shadowOpacity: 0.5,
|
||||||
|
draggable: true
|
||||||
});
|
});
|
||||||
|
|
||||||
layer.add(line);
|
layer.add(line);
|
||||||
stage.add(layer);
|
stage.add(layer);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
var trace = layer.getContext().getTrace();
|
var relaxedTrace = layer.getContext().getTrace(true);
|
||||||
//console.log(trace);
|
//console.log(relaxedTrace);
|
||||||
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();');
|
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 stage = addStage();
|
||||||
|
|
||||||
var layer = new Kinetic.Layer();
|
var layer = new Kinetic.Layer();
|
||||||
@ -63,8 +63,8 @@ suite('Rect', function(){
|
|||||||
assert.equal(rect.getCornerRadius(), 5);
|
assert.equal(rect.getCornerRadius(), 5);
|
||||||
|
|
||||||
var trace = layer.getContext().getTrace();
|
var trace = layer.getContext().getTrace();
|
||||||
//console.log(layer.getContext().traceArr);
|
//console.log(trace);
|
||||||
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();');
|
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