konva/test/unit/Shape-test.js

1969 lines
48 KiB
JavaScript

suite('Shape', function() {
// ======================================================
test('test intersects()', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 200,
y: 100,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 4
});
layer.add(rect);
stage.add(layer);
assert.equal(
rect.intersects({
x: 201,
y: 101
}),
true,
'(201,101) should intersect the shape'
);
assert.equal(
rect.intersects({
x: 197,
y: 97
}),
false,
'(197, 97) should not intersect the shape'
);
assert.equal(
rect.intersects({
x: 250,
y: 125
}),
true,
'(250, 125) should intersect the shape'
);
assert.equal(
rect.intersects({
x: 300,
y: 150
}),
true,
'(300, 150) should intersect the shape'
);
assert.equal(
rect.intersects({
x: 303,
y: 153
}),
false,
'(303, 153) should not intersect the shape'
);
});
// ======================================================
test('test hasShadow() method', function() {
var stage = addStage();
var layer = new Konva.Layer();
var shape = new Konva.Shape({
sceneFunc: function(context) {
context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 0);
context.lineTo(100, 100);
context.closePath();
context.fillStrokeShape(this);
},
x: 10,
y: 10,
fill: 'green',
stroke: 'blue',
strokeWidth: 5,
shadowColor: 'black',
shadowOffsetX: 10,
shadowOpacity: 0
});
layer.add(shape);
stage.add(layer);
assert.equal(
shape.hasShadow(),
false,
'shape should not have a shadow because opacity is 0'
);
shape.setShadowOpacity(0.5);
assert.equal(
shape.hasShadow(),
true,
'shape should have a shadow because opacity is nonzero'
);
shape.setShadowEnabled(false);
assert.equal(
shape.hasShadow(),
false,
'shape should not have a shadow because it is not enabled'
);
});
// ======================================================
test('custom shape with fill, stroke, and strokeWidth', function() {
var stage = addStage();
var layer = new Konva.Layer();
var shape = new Konva.Shape({
sceneFunc: function(context) {
context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 0);
context.lineTo(100, 100);
context.closePath();
context.fillStrokeShape(this);
},
x: 200,
y: 100,
fill: 'green',
stroke: 'blue',
strokeWidth: 5
});
layer.add(shape);
stage.add(layer);
});
// ======================================================
test('add star with translated, scaled, rotated fill', function(done) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillPatternImage: imageObj,
fillPatternX: -20,
fillPatternY: -30,
fillPatternScale: { x: 0.5, y: 0.5 },
fillPatternOffset: { x: 219, y: 150 },
fillPatternRotation: 90,
fillPatternRepeat: 'no-repeat',
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
/*
var anim = new Konva.Animation(function() {
star.attrs.fill.rotation += 0.02;
}, layer);
anim.start();
*/
assert.equal(star.getFillPatternX(), -20, 'star fill x should be -20');
assert.equal(star.getFillPatternY(), -30, 'star fill y should be -30');
assert.equal(
star.getFillPatternScale().x,
0.5,
'star fill scale x should be 0.5'
);
assert.equal(
star.getFillPatternScale().y,
0.5,
'star fill scale y should be 0.5'
);
assert.equal(
star.getFillPatternOffset().x,
219,
'star fill offset x should be 219'
);
assert.equal(
star.getFillPatternOffset().y,
150,
'star fill offset y should be 150'
);
assert.equal(
star.getFillPatternRotation(),
90,
'star fill rotation should be 90'
);
star.setFillPatternRotation(180);
assert.equal(
star.getFillPatternRotation(),
180,
'star fill rotation should be 180'
);
star.setFillPatternScale({ x: 1, y: 1 });
assert.equal(
star.getFillPatternScale().x,
1,
'star fill scale x should be 1'
);
assert.equal(
star.getFillPatternScale().y,
1,
'star fill scale y should be 1'
);
star.setFillPatternOffset({ x: 100, y: 120 });
assert.equal(
star.getFillPatternOffset().x,
100,
'star fill offset x should be 100'
);
assert.equal(
star.getFillPatternOffset().y,
120,
'star fill offset y should be 120'
);
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
// ======================================================
test('test size setters and getters', function() {
var stage = addStage();
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 50,
fill: 'red'
});
var ellipse = new Konva.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 50,
fill: 'yellow'
});
layer.add(ellipse);
layer.add(circle);
stage.add(layer);
// circle tests
assert.equal(circle.getWidth(), 100, 'circle width should be 100');
assert.equal(circle.getHeight(), 100, 'circle height should be 100');
assert.equal(circle.getSize().width, 100, 'circle width should be 100');
assert.equal(circle.getSize().height, 100, 'circle height should be 100');
assert.equal(circle.getRadius(), 50, 'circle radius should be 50');
circle.setWidth(200);
assert.equal(circle.getWidth(), 200, 'circle width should be 200');
assert.equal(circle.getHeight(), 200, 'circle height should be 200');
assert.equal(circle.getSize().width, 200, 'circle width should be 200');
assert.equal(circle.getSize().height, 200, 'circle height should be 200');
assert.equal(circle.getRadius(), 100, 'circle radius should be 100');
});
// ======================================================
test('set image fill to color then image then linear gradient then back to image', function(done) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = addStage();
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: 200,
y: 60,
radius: 50,
fill: 'blue'
});
layer.add(circle);
stage.add(layer);
assert.equal(circle.getFill(), 'blue', 'circle fill should be blue');
circle.setFill(null);
circle.setFillPatternImage(imageObj);
circle.setFillPatternRepeat('no-repeat');
circle.setFillPatternOffset({ x: -200, y: -70 });
assert.notEqual(
circle.getFillPatternImage(),
undefined,
'circle fill image should be defined'
);
assert.equal(
circle.getFillPatternRepeat(),
'no-repeat',
'circle fill repeat should be no-repeat'
);
assert.equal(
circle.getFillPatternOffset().x,
-200,
'circle fill offset x should be -200'
);
assert.equal(
circle.getFillPatternOffset().y,
-70,
'circle fill offset y should be -70'
);
circle.setFillPatternImage(null);
circle.setFillLinearGradientStartPoint({ x: -35, y: -35 });
circle.setFillLinearGradientEndPoint({ x: 35, y: 35 });
circle.setFillLinearGradientColorStops([0, 'red', 1, 'blue']);
circle.setFillLinearGradientStartPoint({ x: 0, y: 0 });
circle.setFillPatternImage(imageObj);
circle.setFillPatternRepeat('repeat');
circle.setFillPatternOffset({ x: 0, y: 0 });
layer.draw();
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
test('stroke gradient', function() {
var stage = addStage();
var layer = new Konva.Layer({
scaleY: 1.5
});
var shape = new Konva.Rect({
x: 10,
y: 10,
width: 100,
height: 100,
fillLinearGradientColorStops: [0, 'yellow', 0.5, 'red', 1, 'white'],
fillLinearGradientStartPoint: {
x: 0,
y: 0
},
scaleX: 3,
fillLinearGradientEndPoint: {
x: 100,
y: 100
},
strokeLinearGradientColorStops: [0, 'red', 0.5, 'blue', 1, 'green'],
strokeLinearGradientStartPoint: {
x: 0,
y: 0
},
strokeLinearGradientEndPoint: {
x: 100,
y: 100
}
});
layer.add(shape);
stage.add(layer);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(3,0,0,1.5,10,15);beginPath();rect(0,0,100,100);closePath();fillStyle=[object CanvasGradient];fill();lineWidth=2;createLinearGradient(0,0,100,100);strokeStyle=[object CanvasGradient];stroke();restore();'
);
});
// ======================================================
test('test enablers and disablers', function() {
var stage = addStage();
var layer = new Konva.Layer();
var circle = new Konva.Circle({
x: stage.getWidth() / 2,
y: stage.getHeight() / 2,
radius: 70,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: { x: 10, y: 10 },
dash: [10, 10],
scaleX: 3
});
layer.add(circle);
stage.add(layer);
assert.equal(circle.getStrokeScaleEnabled(), true);
assert.equal(circle.getFillEnabled(), true, 'fillEnabled should be true');
assert.equal(
circle.getStrokeEnabled(),
true,
'strokeEnabled should be true'
);
assert.equal(
circle.getShadowEnabled(),
true,
'shadowEnabled should be true'
);
assert.equal(circle.dashEnabled(), true, 'dashEnabled should be true');
circle.strokeScaleEnabled(false);
assert.equal(circle.getStrokeScaleEnabled(), false);
layer.draw();
// var trace = layer.getContext().getTrace();
circle.fillEnabled(false);
assert.equal(circle.getFillEnabled(), false, 'fillEnabled should be false');
circle.strokeEnabled(false);
assert.equal(
circle.getStrokeEnabled(),
false,
'strokeEnabled should be false'
);
circle.shadowEnabled(false);
assert.equal(
circle.getShadowEnabled(),
false,
'shadowEnabled should be false'
);
circle.dashEnabled(false);
assert.equal(circle.dashEnabled(), false, 'dashEnabled should be false');
// re-enable
circle.dashEnabled(true);
assert.equal(circle.getDashEnabled(), true, 'dashEnabled should be true');
circle.shadowEnabled(true);
assert.equal(
circle.getShadowEnabled(),
true,
'shadowEnabled should be true'
);
circle.strokeEnabled(true);
assert.equal(
circle.getStrokeEnabled(),
true,
'strokeEnabled should be true'
);
circle.fillEnabled(true);
assert.equal(circle.getFillEnabled(), true, 'fillEnabled should be true');
});
// ======================================================
test('fill with shadow and opacity', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
opacity: 0.5,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: { x: 10, y: 10 },
shadowOpacity: 0.5
});
layer.add(rect);
stage.add(layer);
assert.equal(rect.getX(), 100);
assert.equal(rect.getY(), 50);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
// rect
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'rgba(0,0,0,0.5)';
context.shadowBlur = 10 * canvas.ratio;
context.shadowOffsetX = 10 * canvas.ratio;
context.shadowOffsetY = 10 * canvas.ratio;
context.fill();
compareLayerAndCanvas(layer, canvas, 30);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);save();globalAlpha=0.5;shadowColor=rgba(0,0,0,0.5);shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();restore();restore();'
);
});
// ======================================================
test('test strokeWidth = 0', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
strokeWidth: 0,
stroke: 'black'
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.fillStyle = 'green';
context.fill();
var trace = layer.getContext().getTrace();
compareLayerAndCanvas(layer, canvas, 30);
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();restore();'
);
});
// ======================================================
test('stroke with shadow and opacity', function() {
Konva.pixelRatio = 1;
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
stroke: 'red',
strokeWidth: 20,
opacity: 0.5,
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: { x: 10, y: 10 },
shadowOpacity: 0.5
});
layer.add(rect);
stage.add(layer);
assert.equal(rect.getX(), 100);
assert.equal(rect.getY(), 50);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
// rect
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.strokeStyle = 'red';
context.lineWidth = 20;
context.shadowColor = 'rgba(0,0,0,0.5)';
context.shadowBlur = 10 * canvas.ratio;
context.shadowOffsetX = 10 * canvas.ratio;
context.shadowOffsetY = 10 * canvas.ratio;
context.stroke();
compareLayerAndCanvas(layer, canvas, 10);
var trace = layer.getContext().getTrace();
//console.log(trace);
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);save();globalAlpha=0.5;shadowColor=rgba(0,0,0,0.5);shadowBlur=10;shadowOffsetX=10;shadowOffsetY=10;beginPath();rect(0,0,100,50);closePath();lineWidth=20;strokeStyle=red;stroke();restore();restore();'
);
});
// ======================================================
test('fill and stroke with opacity', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
opacity: 0.5
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
// stroke
context.beginPath();
context.moveTo(100, 50);
context.lineTo(200, 50);
context.lineTo(200, 100);
context.lineTo(100, 100);
context.closePath();
context.lineWidth = 10;
context.strokeStyle = 'black';
context.stroke();
// rect
context.fillStyle = 'green';
context.fillRect(105, 55, 90, 40);
compareLayerAndCanvas(layer, canvas, 10);
});
// ======================================================
test('fill and stroke with shadow', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
shadowColor: 'grey',
shadowBlur: 10,
shadowOffset: {
x: 20,
y: 20
}
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'grey';
context.shadowBlur = 10 * canvas.ratio;
context.shadowOffsetX = 20 * canvas.ratio;
context.shadowOffsetY = 20 * canvas.ratio;
context.lineWidth = 10;
context.stroke();
context.fill();
// clear the shadow
context.shadowColor = 0;
context.shadowOffsetX = 0;
context.shadowOffsetY = 0;
context.shadowBlur = 0;
// restroke without the shaodw
context.stroke();
compareLayerAndCanvas(layer, canvas, 50);
var trace = layer.getContext().getTrace();
//console.log(trace);
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);save();shadowColor=rgba(128,128,128,1);shadowBlur=10;shadowOffsetX=20;shadowOffsetY=20;beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();lineWidth=10;strokeStyle=black;stroke();restore();beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();lineWidth=10;strokeStyle=black;stroke();restore();'
);
});
// ======================================================
// hard to emulate the same drawing
test('fill and stroke with shadow and opacity', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
shadowColor: 'grey',
opacity: 0.5,
shadowBlur: 5,
shadowOffset: {
x: 20,
y: 20
}
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.globalAlpha = 0.3;
// draw shadow
context.save();
context.beginPath();
context.rect(95, 45, 110, 60);
context.closePath();
context.shadowColor = 'grey';
context.shadowBlur = 5 * canvas.ratio;
context.shadowOffsetX = 20 * canvas.ratio;
context.shadowOffsetY = 20 * canvas.ratio;
context.fillStyle = 'black';
context.fill();
context.restore();
// draw "stroke"
context.save();
context.beginPath();
context.moveTo(100, 50);
context.lineTo(200, 50);
context.lineTo(200, 100);
context.lineTo(100, 100);
context.closePath();
context.lineWidth = 10;
context.strokeStyle = 'black';
context.stroke();
context.restore();
context.save();
context.beginPath();
context.fillStyle = 'green';
context.rect(105, 55, 90, 40);
context.closePath();
context.fill();
context.restore();
// // don't test in PhantomJS as it use old chrome engine
// // it it has opacity + shadow bug
// if (!window.mochaPhantomJS) {
// compareLayerAndCanvas(layer, canvas, 260);
// }
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();save();shadowColor=rgba(128,128,128,1);shadowBlur=5;shadowOffsetX=20;shadowOffsetY=20;globalAlpha=0.5;drawImage([object HTMLCanvasElement],0,0,578,200);restore();restore();'
);
});
// ======================================================
test('text with fill and stroke with shadow', function() {
var stage = addStage();
var layer = new Konva.Layer();
var text = new Konva.Text({
x: 50,
y: 50,
text: 'Test TEXT',
fontSize: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 2,
shadowColor: 'grey',
shadowBlur: 2,
shadowOffset: {
x: 20,
y: 20
}
});
layer.add(text);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.save();
context.shadowColor = 'grey';
context.shadowBlur = 2 * canvas.ratio;
context.shadowOffsetX = 20 * canvas.ratio;
context.shadowOffsetY = 20 * canvas.ratio;
context.font = 'normal 50px Arial';
context.textBaseline = 'middle';
context.fillStyle = 'green';
context.fillText('Test TEXT', 50, 75);
context.lineWidth = 2;
context.strokeStyle = 'black';
context.strokeText('Test TEXT', 50, 75);
context.stroke();
context.fill();
context.restore();
// draw text again to remove shadow under stroke
context.font = 'normal 50px Arial';
context.textBaseline = 'middle';
context.fillText('Test TEXT', 50, 75);
context.fillStyle = 'green';
context.fillText('Test TEXT', 50, 75);
context.lineWidth = 2;
context.strokeStyle = 'black';
context.strokeText('Test TEXT', 50, 75);
compareLayerAndCanvas(layer, canvas, 254);
});
// ======================================================
test('shape intersect with shadow', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
fill: '#ff0000',
x: 50,
y: 50,
width: 200,
height: 200,
draggable: true,
shadowColor: '#000' // if all shadow properties removed, works fine
});
layer.add(rect);
stage.add(layer);
//error here
assert.equal(rect.intersects({ x: 52, y: 52 }), true);
assert.equal(rect.intersects({ x: 45, y: 45 }), false);
});
// ======================================================
test('overloaded getters and setters', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'red',
strokeWidth: 20,
draggable: true
});
layer.add(rect);
stage.add(layer);
rect.stroke('blue');
assert.equal(rect.stroke(), 'blue');
rect.lineJoin('bevel');
assert.equal(rect.lineJoin(), 'bevel');
rect.lineCap('square');
assert.equal(rect.lineCap(), 'square');
rect.strokeWidth(8);
assert.equal(rect.strokeWidth(), 8);
rect.sceneFunc('function');
assert.equal(rect.sceneFunc(), 'function');
rect.hitFunc('function');
assert.equal(rect.hitFunc(), 'function');
rect.dash([1]);
assert.equal(rect.dash()[0], 1);
// NOTE: skipping the rest because it would take hours to test all possible methods.
// This should hopefully be enough to test Factor overloaded methods
});
// ======================================================
test('create image hit region', function(done) {
var imageObj = new Image();
var stage = addStage();
var layer = new Konva.Layer();
imageObj.onload = function() {
var lion = new Konva.Image({
x: 200,
y: 40,
image: imageObj,
draggable: true,
shadowColor: 'black',
shadowBlur: 10,
shadowOffsetX: 20,
shadowOpacity: 0.2
});
// override color key with black
lion.colorKey = '#000000';
Konva.shapes['#000000'] = lion;
layer.add(lion);
stage.add(layer);
lion.cache();
//document.body.appendChild(lion._getCanvasCache().hit._canvas);
lion.drawHitFromCache();
layer.draw();
done();
};
imageObj.src = 'assets/lion.png';
showHit(layer);
layer.hitCanvas._canvas.style.border = '2px solid black';
});
test('test defaults', function() {
var shape = new Konva.Shape();
assert.equal(shape.strokeWidth(), 2);
assert.equal(shape.shadowOffsetX(), 0);
assert.equal(shape.shadowOffsetY(), 0);
assert.equal(shape.fillPatternX(), 0);
assert.equal(shape.fillPatternY(), 0);
assert.equal(shape.fillRadialGradientStartRadius(), 0);
assert.equal(shape.fillRadialGradientEndRadius(), 0);
assert.equal(shape.fillPatternRepeat(), 'repeat');
assert.equal(shape.fillEnabled(), true);
assert.equal(shape.strokeEnabled(), true);
assert.equal(shape.shadowEnabled(), true);
assert.equal(shape.dashEnabled(), true);
assert.equal(shape.dashOffset(), 0);
assert.equal(shape.strokeScaleEnabled(), true);
assert.equal(shape.fillPriority(), 'color');
assert.equal(shape.fillPatternOffsetX(), 0);
assert.equal(shape.fillPatternOffsetY(), 0);
assert.equal(shape.fillPatternScaleX(), 1);
assert.equal(shape.fillPatternScaleY(), 1);
assert.equal(shape.fillLinearGradientStartPointX(), 0);
assert.equal(shape.fillLinearGradientStartPointY(), 0);
assert.equal(shape.fillLinearGradientEndPointX(), 0);
assert.equal(shape.fillLinearGradientEndPointY(), 0);
assert.equal(shape.fillRadialGradientStartPointX(), 0);
assert.equal(shape.fillRadialGradientStartPointY(), 0);
assert.equal(shape.fillRadialGradientEndPointX(), 0);
assert.equal(shape.fillRadialGradientEndPointY(), 0);
assert.equal(shape.fillPatternRotation(), 0);
});
// ======================================================
test('hit graph when shape cached before adding to Layer', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 290,
y: 111,
width: 50,
height: 50,
fill: 'black'
});
rect.cache();
var click = false;
rect.on('click', function() {
click = true;
});
layer.add(rect);
stage.add(layer);
var top = stage.content.getBoundingClientRect().top;
showHit(layer);
stage.simulateMouseDown({
x: 300,
y: 120
});
stage.simulateMouseUp({
x: 300,
y: 120
});
assert.equal(
click,
true,
'click event should have been fired when mousing down and then up on rect'
);
});
test('class inherence', function() {
var rect = new Konva.Rect();
assert.equal(rect instanceof Konva.Rect, true);
assert.equal(rect instanceof Konva.Shape, true);
assert.equal(rect instanceof Konva.Node, true);
});
test('disable stroke for hit', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
stroke: 'red',
strokeWidth: 20,
draggable: true
});
// default value
assert.equal(rect.strokeHitEnabled(), true);
rect.strokeHitEnabled(false);
assert.equal(rect.strokeHitEnabled(), false);
layer.add(rect);
stage.add(layer);
assert.equal(rect.getY(), 50);
var trace = layer
.getHitCanvas()
.getContext()
.getTrace(true);
assert.equal(
trace,
'clearRect();save();transform();beginPath();rect();closePath();save();fillStyle;fill();restore();restore();'
);
});
test('hitStrokeWidth', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 10,
y: 10,
width: 100,
height: 100,
stroke: 'red',
strokeWidth: 2
});
// default value
layer.add(rect);
stage.add(layer);
// default value is auto
assert.equal(rect.hitStrokeWidth(), 'auto');
// try to hit test near edge
assert.equal(stage.getIntersection({ x: 5, y: 5 }), null);
rect.hitStrokeWidth(20);
layer.draw();
// no we should hit the rect
assert.equal(stage.getIntersection({ x: 5, y: 5 }), rect);
rect.strokeHitEnabled(false);
assert.equal(rect.hitStrokeWidth(), 0);
rect.strokeHitEnabled(true);
assert.equal(rect.hitStrokeWidth(), 'auto');
rect.hitStrokeWidth(0);
assert.equal(rect.strokeHitEnabled(), false);
// var trace = layer
// .getHitCanvas()
// .getContext()
// .getTrace(true);
// assert.equal(
// trace,
// 'clearRect();save();transform();beginPath();rect();closePath();save();fillStyle;fill();restore();restore();'
// );
});
test('enable hitStrokeWidth even if we have no stroke on scene', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 10,
y: 10,
width: 100,
height: 100
});
// default value
layer.add(rect);
stage.add(layer);
// try to hit test near edge
assert.equal(stage.getIntersection({ x: 5, y: 5 }), null);
rect.hitStrokeWidth(20);
layer.draw();
// no we should hit the rect
assert.equal(stage.getIntersection({ x: 5, y: 5 }), rect);
});
test('cache shadow color rgba', function() {
var circle = new Konva.Circle({
fill: 'green',
radius: 50
});
// no shadow on start
assert.equal(circle.hasShadow(), false);
assert.equal(circle.getShadowRGBA(), undefined);
// set shadow
circle.shadowColor('black');
assert.equal(circle.hasShadow(), true);
assert.equal(circle.getShadowRGBA(), 'rgba(0,0,0,1)');
// set another shadow property
circle.shadowOpacity(0.2);
assert.equal(circle.getShadowRGBA(), 'rgba(0,0,0,0.2)');
circle.shadowColor('rgba(10,10,10,0.5)');
assert.equal(circle.getShadowRGBA(), 'rgba(10,10,10,0.1)');
// reset shadow
circle.shadowColor(null);
assert.equal(circle.getShadowRGBA(), undefined);
});
test('scale should also effect shadow offset', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
scaleX: 0.5,
scaleY: 0.5,
fill: 'green',
shadowColor: 'black',
shadowBlur: 0,
shadowOffset: { x: 10, y: 10 }
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
// rect
context.beginPath();
context.rect(100, 100, 50, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'rgba(0,0,0,1)';
context.shadowBlur = 0;
context.shadowOffsetX = 5 * canvas.ratio;
context.shadowOffsetY = 5 * canvas.ratio;
context.fill();
compareLayerAndCanvas(layer, canvas, 10);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(0.5,0,0,0.5,100,100);save();shadowColor=rgba(0,0,0,1);shadowBlur=0;shadowOffsetX=5;shadowOffsetY=5;beginPath();rect(0,0,100,100);closePath();fillStyle=green;fill();restore();restore();'
);
});
test('scale should also effect shadow offset - negative scale', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 100,
width: 100,
height: 100,
scaleX: -0.5,
scaleY: 0.5,
fill: 'green',
shadowColor: 'black',
shadowBlur: 10,
shadowOffset: { x: 10, y: 10 }
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
// rect
context.beginPath();
context.rect(50, 100, 50, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'rgba(0,0,0,1)';
context.shadowBlur = 10;
context.shadowOffsetX = -5 * canvas.ratio;
context.shadowOffsetY = 5 * canvas.ratio;
context.fill();
compareLayerAndCanvas(layer, canvas, 150);
// var trace = layer.getContext().getTrace();
// assert.equal(
// trace,
// 'clearRect(0,0,578,200);save();transform(-0.5,0,0,0.5,100,100);save();shadowColor=rgba(0,0,0,1);shadowBlur=10;shadowOffsetX=-5;shadowOffsetY=5;beginPath();rect(0,0,100,100);closePath();fillStyle=green;fill();restore();restore();'
// );
});
test('scale of parent container should also effect shadow offset', function() {
var stage = addStage();
var layer = new Konva.Layer();
var group = new Konva.Group({
x: 100,
y: 100,
scaleX: 0.5,
scaleY: 0.5
});
var rect = new Konva.Rect({
width: 200,
height: 200,
scaleX: 0.5,
scaleY: 0.5,
fill: 'green',
shadowColor: 'black',
shadowBlur: 0,
shadowOffset: { x: 20, y: 20 }
});
group.add(rect);
layer.add(group);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
// rect
context.beginPath();
context.rect(100, 100, 50, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'rgba(0,0,0,1)';
context.shadowBlur = 0;
context.shadowOffsetX = 5 * canvas.ratio;
context.shadowOffsetY = 5 * canvas.ratio;
context.fill();
compareLayerAndCanvas(layer, canvas, 10);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(0.25,0,0,0.25,100,100);save();shadowColor=rgba(0,0,0,1);shadowBlur=0;shadowOffsetX=5;shadowOffsetY=5;beginPath();rect(0,0,200,200);closePath();fillStyle=green;fill();restore();restore();'
);
});
test('optional disable buffer canvas', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
opacity: 0.5,
perfectDrawEnabled: false
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.globalAlpha = 0.5;
// stroke
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.lineWidth = 10;
context.strokeStyle = 'black';
context.fillStyle = 'green';
context.fill();
context.stroke();
compareLayerAndCanvas(layer, canvas, 10);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);globalAlpha=0.5;beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();lineWidth=10;strokeStyle=black;stroke();restore();'
);
});
// ======================================================
test('optional disable shadow for stroke', function() {
var stage = addStage();
var layer = new Konva.Layer();
var rect = new Konva.Rect({
x: 100,
y: 50,
width: 100,
height: 50,
fill: 'green',
stroke: 'black',
strokeWidth: 10,
shadowColor: 'grey',
shadowBlur: 10,
shadowOffset: {
x: 20,
y: 20
},
shadowForStrokeEnabled: false
});
layer.add(rect);
stage.add(layer);
var canvas = createCanvas();
var context = canvas.getContext('2d');
context.beginPath();
context.rect(100, 50, 100, 50);
context.closePath();
context.fillStyle = 'green';
context.shadowColor = 'grey';
context.shadowBlur = 10 * canvas.ratio;
context.shadowOffsetX = 20 * canvas.ratio;
context.shadowOffsetY = 20 * canvas.ratio;
context.lineWidth = 10;
context.fill();
context.shadowColor = 'rgba(0,0,0,0)';
context.stroke();
compareLayerAndCanvas(layer, canvas, 10);
var trace = layer.getContext().getTrace();
assert.equal(
trace,
'clearRect(0,0,578,200);save();transform(1,0,0,1,100,50);save();shadowColor=rgba(128,128,128,1);shadowBlur=10;shadowOffsetX=20;shadowOffsetY=20;beginPath();rect(0,0,100,50);closePath();fillStyle=green;fill();lineWidth=10;shadowColor=rgba(0,0,0,0);strokeStyle=black;stroke();restore();restore();'
);
});
test('clone custom shape', function() {
var className = 'myCustomName';
var CustomShape = function() {
CustomShape.super.apply(this, arguments);
this.className = className;
};
CustomShape.prototype.foo = function() {};
Konva.Util.extend(CustomShape, Konva.Shape);
var myShape = new CustomShape({
fill: 'grey'
});
var clone = myShape.clone();
assert.equal(clone instanceof CustomShape, true);
assert.equal(clone instanceof Konva.Shape, true);
assert.equal(clone.className, className);
assert.equal(clone.fill(), 'grey');
assert.equal(clone.foo, CustomShape.prototype.foo);
});
test('getClientRect should skip disabled attributes', function() {
var stage = addStage();
var layer = new Konva.Layer();
var shape = new Konva.Rect({
x: 200,
y: 100,
width: 100,
height: 100,
fill: 'green',
stroke: 'black',
strokeWidth: 4,
strokeEnabled: false,
shadowOffsetX: 10,
shadowEnabled: false
});
layer.add(shape);
stage.add(layer);
var rect = shape.getClientRect();
assert.equal(rect.width, 100, 'should not effect width');
assert.equal(rect.height, 100, 'should not effect width');
});
test('getClientRect for shape in transformed parent', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var group = new Konva.Group({
x: 110,
y: 0,
rotation: 90
});
layer.add(group);
var shape = new Konva.Rect({
x: 0,
y: 0,
width: 100,
height: 100,
fill: 'green'
});
group.add(shape);
var relativeRect = shape.getClientRect({ relativeTo: group });
assert.equal(relativeRect.x, 0);
assert.equal(relativeRect.y, 0);
assert.equal(relativeRect.width, 100);
assert.equal(relativeRect.height, 100);
var absRect = shape.getClientRect();
assert.equal(absRect.x, 10);
assert.equal(absRect.y, 0);
assert.equal(absRect.width, 100);
assert.equal(absRect.height, 100);
});
test('shadow should respect pixel ratio', function() {
var stage = addStage();
var layer = new Konva.Layer();
layer.getCanvas().setPixelRatio(2);
var shape = new Konva.Rect({
width: 100,
height: 100,
fill: 'black',
shadowColor: 'green',
shadowOffsetX: 20,
shadowOffsetY: 20,
shadowBlur: 0
});
layer.add(shape);
stage.add(layer);
var data = layer.getContext().getImageData(15 * 2, (100 + 5) * 2, 1, 1);
assert.equal(data.data[3], 0, 'pixel should be empty, no shadow here');
});
test('text shadow blur should take scale into account', function() {
var stage = addStage();
var layer1 = new Konva.Layer();
stage.add(layer1);
var rect1 = new Konva.Rect({
x: 10,
y: 10,
scaleX: 0.5,
scaleY: 0.5,
width: 80,
height: 80,
fill: 'black',
shadowColor: 'black',
shadowOffsetX: 0,
shadowOffsetY: 50,
shadowBlur: 10
});
layer1.add(rect1);
stage.add(layer1);
var layer2 = new Konva.Layer();
stage.add(layer2);
var rect2 = new Konva.Rect({
x: 10,
y: 10,
fill: 'black',
width: 40,
height: 40,
shadowColor: 'black',
shadowOffsetX: 0,
shadowOffsetY: 25,
shadowBlur: 5
});
layer2.add(rect2);
stage.add(layer2);
compareLayers(layer1, layer2, 30);
});
// ======================================================
test('sceneFunc and hitFunc should have shape as second argument', function() {
var stage = addStage();
var layer = new Konva.Layer();
var shape = new Konva.Shape({
sceneFunc: function(context, shape) {
assert.equal(this, shape);
context.beginPath();
context.moveTo(0, 0);
context.lineTo(100, 0);
context.lineTo(100, 100);
context.closePath();
context.fillStrokeShape(shape);
},
x: 200,
y: 100,
fill: 'green',
stroke: 'blue',
strokeWidth: 5
});
layer.add(shape);
var rect = new Konva.Rect({
hitFunc: function(ctx, shape) {
assert.equal(this, shape);
}
});
layer.add(rect);
stage.add(layer);
});
// ======================================================
test('cache fill pattern', function(done) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillPatternImage: imageObj,
fillPatternX: -20,
fillPatternY: -30,
fillPatternScale: { x: 0.5, y: 0.5 },
fillPatternOffset: { x: 219, y: 150 },
fillPatternRotation: 90,
fillPatternRepeat: 'no-repeat',
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var ctx = layer.getContext();
var oldCreate = ctx.createPattern;
var callCount = 0;
ctx.createPattern = function() {
callCount += 1;
return oldCreate.apply(this, arguments);
};
layer.draw();
layer.draw();
assert.equal(callCount, 0);
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
test('recache fill pattern on changes', function(done) {
var imageObj = new Image();
imageObj.onload = function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillPatternImage: imageObj,
fillPatternX: -20,
fillPatternY: -30,
fillPatternScale: { x: 0.5, y: 0.5 },
fillPatternOffset: { x: 219, y: 150 },
fillPatternRotation: 90,
fillPatternRepeat: 'no-repeat',
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var pattern1 = star._getFillPattern();
star.fillPatternImage(document.createElement('canvas'));
var pattern2 = star._getFillPattern();
assert.notEqual(pattern1, pattern2);
star.fillPatternRepeat('repeat');
var pattern3 = star._getFillPattern();
assert.notEqual(pattern2, pattern3);
done();
};
imageObj.src = 'assets/darth-vader.jpg';
});
// ======================================================
test('cache linear gradient', function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillLinearGradientStartPoint: { x: -50, y: -50 },
fillLinearGradientEndPoint: { x: 50, y: 50 },
fillLinearGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var ctx = layer.getContext();
var oldCreate = ctx.createLinearGradient;
var callCount = 0;
ctx.createLinearGradient = function() {
callCount += 1;
return oldCreate.apply(this, arguments);
};
layer.draw();
layer.draw();
assert.equal(callCount, 0);
});
test('recache linear gradient on changes', function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillLinearGradientStartPoint: { x: -50, y: -50 },
fillLinearGradientEndPoint: { x: 50, y: 50 },
fillLinearGradientColorStops: [0, 'red', 1, 'yellow'],
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var gradient1 = star._getLinearGradient();
star.fillLinearGradientStartPointX(-10);
var gradient2 = star._getLinearGradient();
assert.notEqual(gradient1, gradient2);
star.fillLinearGradientStartPointY(-10);
var gradient3 = star._getLinearGradient();
assert.notEqual(gradient2, gradient3);
star.fillLinearGradientEndPointX(100);
var gradient4 = star._getLinearGradient();
assert.notEqual(gradient3, gradient4);
star.fillLinearGradientEndPointY(100);
var gradient5 = star._getLinearGradient();
assert.notEqual(gradient4, gradient5);
star.fillLinearGradientColorStops([0, 'red', 1, 'green']);
var gradient6 = star._getLinearGradient();
assert.notEqual(gradient5, gradient6);
layer.draw();
});
// ======================================================
test('cache radial gradient', function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillRadialGradientStartPoint: { x: 0, y: 0 },
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: { x: 0, y: 0 },
fillRadialGradientEndRadius: 70,
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'blue'],
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var ctx = layer.getContext();
var oldCreate = ctx.createRadialGradient;
var callCount = 0;
ctx.createRadialGradient = function() {
callCount += 1;
return oldCreate.apply(this, arguments);
};
layer.draw();
layer.draw();
assert.equal(callCount, 0);
});
test('recache linear gradient on changes', function() {
var stage = addStage();
var layer = new Konva.Layer();
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
fillRadialGradientStartPoint: { x: 0, y: 0 },
fillRadialGradientStartRadius: 0,
fillRadialGradientEndPoint: { x: 0, y: 0 },
fillRadialGradientEndRadius: 70,
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'blue'],
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
layer.add(star);
stage.add(layer);
var gradient1 = star._getRadialGradient();
star.fillRadialGradientStartPointX(-10);
var gradient2 = star._getRadialGradient();
assert.notEqual(gradient1, gradient2);
star.fillRadialGradientStartPointY(-10);
var gradient3 = star._getRadialGradient();
assert.notEqual(gradient2, gradient3);
star.fillRadialGradientEndPointX(100);
var gradient4 = star._getRadialGradient();
assert.notEqual(gradient3, gradient4);
star.fillRadialGradientEndPointY(100);
var gradient5 = star._getRadialGradient();
assert.notEqual(gradient4, gradient5);
star.fillRadialGradientColorStops([0, 'red', 1, 'green']);
var gradient6 = star._getRadialGradient();
assert.notEqual(gradient5, gradient6);
star.fillRadialGradientStartRadius(10);
var gradient7 = star._getRadialGradient();
assert.notEqual(gradient6, gradient7);
star.fillRadialGradientEndRadius(200);
var gradient8 = star._getRadialGradient();
assert.notEqual(gradient7, gradient8);
layer.draw();
});
test('try to add destroyed shape', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var star = new Konva.Star({
x: 200,
y: 100,
numPoints: 5,
innerRadius: 40,
outerRadius: 70,
stroke: 'blue',
strokeWidth: 5,
draggable: true
});
star.destroy();
var callCount = 0;
var oldWarn = Konva.Util.warn;
Konva.Util.warn = function() {
callCount += 1;
};
layer.add(star);
layer.draw();
assert.equal(callCount, 1);
Konva.Util.warn = oldWarn;
});
test('hasFill getter', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var shape = new Konva.Shape({
stroke: 'black',
strokeWidth: 4,
sceneFunc: function(context) {
context.beginPath();
context.moveTo(20, 50);
context.quadraticCurveTo(550, 0, 500, 500);
context.fillStrokeShape(shape);
},
fill: 'red',
fillEnabled: false
});
layer.add(shape);
assert.equal(shape.hasFill(), false);
});
test('test hit of non filled shape', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);
var line = new Konva.Shape({
sceneFunc: function(context) {
context.beginPath();
context.moveTo(20, 50);
context.quadraticCurveTo(550, 0, 500, 500);
context.fillStrokeShape(line);
}
});
layer.add(line);
layer.draw();
// we still should register shape here
// like for a non filled rectangle (with just stroke),
// we need fill it for full events
var shape = layer.getIntersection({ x: 50, y: 70 });
assert.equal(shape, line);
});
});