mirror of
https://github.com/konvajs/konva.git
synced 2025-04-05 20:48:28 +08:00
1474 lines
31 KiB
JavaScript
1474 lines
31 KiB
JavaScript
suite('Caching', function () {
|
|
// this.timeout(5000);
|
|
// CACHING SHAPE
|
|
|
|
test('cache simple rectangle', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
draggable: true,
|
|
});
|
|
rect.cache();
|
|
|
|
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();
|
|
|
|
compareLayerAndCanvas(layer, canvas, 10);
|
|
cloneAndCompareLayer(layer);
|
|
showHit(layer);
|
|
});
|
|
|
|
test('cache simple rectangle with transform', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 50,
|
|
rotation: 45,
|
|
scaleY: 2,
|
|
fill: 'green',
|
|
});
|
|
rect.cache();
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.translate(100, 50);
|
|
context.rotate(Math.PI / 4);
|
|
context.beginPath();
|
|
context.rect(0, 0, 100, 100);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
|
|
compareLayerAndCanvas(layer, canvas, 200);
|
|
cloneAndCompareLayer(layer, 150);
|
|
});
|
|
|
|
test('cache rectangle with fill and 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: 20,
|
|
});
|
|
rect.cache();
|
|
|
|
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();
|
|
context.lineWidth = 20;
|
|
context.stroke();
|
|
compareLayerAndCanvas(layer, canvas, 50);
|
|
cloneAndCompareLayer(layer, 50);
|
|
});
|
|
|
|
test('cache rectangle with fill 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,
|
|
});
|
|
rect.cache();
|
|
rect.opacity(0.3);
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.globalAlpha = 0.3;
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 50);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 5);
|
|
});
|
|
|
|
test('cache rectangle with fill, stroke 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,
|
|
stroke: 'black',
|
|
strokeWidth: 10,
|
|
});
|
|
rect.cache();
|
|
rect.opacity(0.3);
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
cloneAndCompareLayer(layer, 100);
|
|
});
|
|
|
|
// skip, because opacity rendering of cached shape is different
|
|
// nothing we can do here
|
|
test('cache rectangle with fill, shadow and opacity', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 10,
|
|
y: 10,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
opacity: 0.5,
|
|
shadowBlur: 10,
|
|
shadowColor: 'black',
|
|
draggable: true,
|
|
});
|
|
// rect.cache();
|
|
// rect.opacity(0.3);
|
|
|
|
layer.add(rect.clone({ y: 50, x: 50, shadowEnabled: false }));
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
cloneAndCompareLayer(layer, 10);
|
|
});
|
|
|
|
test('cache rectangle with fill and simple shadow', 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,
|
|
fill: 'green',
|
|
shadowColor: 'black',
|
|
shadowBlur: 10,
|
|
draggable: true,
|
|
});
|
|
rect.cache();
|
|
|
|
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 = 'black';
|
|
context.shadowBlur = 10;
|
|
context.fill();
|
|
|
|
showCanvas(rect._getCanvasCache().scene._canvas);
|
|
showCanvas(rect._getCanvasCache().hit._canvas);
|
|
showHit(layer);
|
|
compareLayerAndCanvas(layer, canvas, 10);
|
|
Konva.pixelRatio = undefined;
|
|
});
|
|
|
|
test('cache rectangle with fill and shadow with offset', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 50,
|
|
height: 25,
|
|
fill: 'green',
|
|
shadowOffsetX: 10,
|
|
shadowOffsetY: 10,
|
|
shadowColor: 'black',
|
|
shadowBlur: 10,
|
|
});
|
|
rect.cache();
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
|
|
context.translate(100, 50);
|
|
context.beginPath();
|
|
context.rect(0, 0, 50, 25);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.shadowColor = 'black';
|
|
context.shadowBlur = 10 * canvas.ratio;
|
|
context.shadowOffsetX = 10 * canvas.ratio;
|
|
context.shadowOffsetY = 10 * canvas.ratio;
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 50);
|
|
});
|
|
|
|
test('cache rectangle with fill and shadow with negative offset', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 50,
|
|
height: 25,
|
|
fill: 'green',
|
|
shadowOffsetX: -10,
|
|
shadowOffsetY: -10,
|
|
shadowColor: 'black',
|
|
shadowBlur: 10,
|
|
});
|
|
rect.cache();
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
|
|
context.translate(100, 50);
|
|
context.beginPath();
|
|
context.rect(0, 0, 50, 25);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.shadowColor = 'black';
|
|
context.shadowBlur = 10 * canvas.ratio;
|
|
context.shadowOffsetX = -10 * canvas.ratio;
|
|
context.shadowOffsetY = -10 * canvas.ratio;
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 50);
|
|
});
|
|
|
|
test('cache rectangle with fill and shadow with negative offset and scale', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 50,
|
|
height: 25,
|
|
fill: 'green',
|
|
shadowOffsetX: -10,
|
|
shadowOffsetY: -10,
|
|
shadowColor: 'black',
|
|
shadowBlur: 10,
|
|
scaleX: 2,
|
|
scaleY: 2,
|
|
});
|
|
rect.cache();
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
cloneAndCompareLayer(layer, 200);
|
|
});
|
|
|
|
test('cache rectangle with fill and shadow and some transform', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 50,
|
|
height: 25,
|
|
fill: 'green',
|
|
shadowOffsetX: -10,
|
|
shadowOffsetY: -10,
|
|
shadowColor: 'black',
|
|
shadowBlur: 10,
|
|
offsetX: 50,
|
|
offsetY: 25,
|
|
});
|
|
rect.cache();
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
|
|
context.translate(50, 25);
|
|
context.beginPath();
|
|
context.rect(0, 0, 50, 25);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.shadowColor = 'black';
|
|
context.shadowBlur = 10 * canvas.ratio;
|
|
context.shadowOffsetX = -10 * canvas.ratio;
|
|
context.shadowOffsetY = -10 * canvas.ratio;
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 50);
|
|
});
|
|
|
|
// CACHING CONTAINERS
|
|
test('cache group with simple rectangle', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var group = new Konva.Group({
|
|
x: 100,
|
|
y: 50,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
});
|
|
group.add(rect);
|
|
group.cache();
|
|
|
|
layer.add(group);
|
|
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();
|
|
compareLayerAndCanvas(layer, canvas, 10);
|
|
cloneAndCompareLayer(layer);
|
|
});
|
|
|
|
test('cache group with simple rectangle with transform', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var group = new Konva.Group({
|
|
x: 50,
|
|
y: 25,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 50,
|
|
y: 25,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
rotation: 45,
|
|
});
|
|
group.add(rect);
|
|
group.cache();
|
|
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
cloneAndCompareLayer(layer, 200);
|
|
});
|
|
|
|
test('cache group with several shape with transform', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var group = new Konva.Group({
|
|
x: 50,
|
|
y: 25,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 50,
|
|
y: 25,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
shadowOffsetX: 10,
|
|
shadowOffsetY: 10,
|
|
shadowBlur: 10,
|
|
});
|
|
group.add(rect);
|
|
|
|
var circle = new Konva.Circle({
|
|
x: 250,
|
|
y: 50,
|
|
radius: 25,
|
|
fill: 'red',
|
|
// rotation on circle should not have any effects
|
|
stroke: 'black',
|
|
rotation: 45,
|
|
scaleX: 2,
|
|
scaleY: 2,
|
|
});
|
|
group.add(circle);
|
|
|
|
group.cache();
|
|
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
|
|
// draw rect
|
|
context.save();
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 50);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.shadowColor = 'black';
|
|
context.shadowBlur = 10 * canvas.ratio;
|
|
context.shadowOffsetX = 10 * canvas.ratio;
|
|
context.shadowOffsetY = 10 * canvas.ratio;
|
|
context.fill();
|
|
context.restore();
|
|
|
|
// circle
|
|
context.save();
|
|
context.beginPath();
|
|
context.arc(300, 75, 50, 0, Math.PI * 2);
|
|
context.closePath();
|
|
context.fillStyle = 'red';
|
|
context.lineWidth = 4;
|
|
context.fill();
|
|
context.stroke();
|
|
context.restore();
|
|
|
|
compareLayerAndCanvas(layer, canvas, 150);
|
|
|
|
// recache
|
|
group.cache();
|
|
layer.draw();
|
|
compareLayerAndCanvas(layer, canvas, 150);
|
|
});
|
|
|
|
test('cache group with rectangle and text', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var button = new Konva.Group({
|
|
width: 100,
|
|
height: 50,
|
|
draggable: true,
|
|
});
|
|
|
|
var face = new Konva.Rect({
|
|
fill: 'red',
|
|
x: 0,
|
|
y: 0,
|
|
width: 100,
|
|
height: 50,
|
|
});
|
|
|
|
var text = new Konva.Text({
|
|
text: 'Wrong button',
|
|
x: 15,
|
|
y: 20,
|
|
});
|
|
|
|
button.add(face);
|
|
button.add(text);
|
|
|
|
button.cache();
|
|
|
|
layer.add(button);
|
|
stage.add(layer);
|
|
|
|
cloneAndCompareLayer(layer, 100);
|
|
});
|
|
|
|
test('cache layer with several shape with transform', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({
|
|
draggable: true,
|
|
});
|
|
|
|
var group = new Konva.Group({
|
|
x: 50,
|
|
y: 25,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 50,
|
|
y: 25,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
shadowOffsetX: 10,
|
|
shadowOffsetY: 10,
|
|
shadowBlur: 10,
|
|
});
|
|
group.add(rect);
|
|
|
|
var circle = new Konva.Circle({
|
|
x: 250,
|
|
y: 50,
|
|
radius: 25,
|
|
fill: 'red',
|
|
// rotation on circle should not have any effects
|
|
rotation: 45,
|
|
stroke: 'black',
|
|
scaleX: 2,
|
|
scaleY: 2,
|
|
});
|
|
group.add(circle);
|
|
|
|
group.cache();
|
|
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
|
|
// draw rect
|
|
context.save();
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 50);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.shadowColor = 'black';
|
|
context.shadowBlur = 10 * canvas.ratio;
|
|
context.shadowOffsetX = 10 * canvas.ratio;
|
|
context.shadowOffsetY = 10 * canvas.ratio;
|
|
context.fill();
|
|
context.restore();
|
|
|
|
// circle
|
|
context.save();
|
|
context.beginPath();
|
|
context.arc(300, 75, 50, 0, Math.PI * 2);
|
|
context.closePath();
|
|
context.fillStyle = 'red';
|
|
context.lineWidth = 4;
|
|
context.fill();
|
|
context.stroke();
|
|
context.restore();
|
|
|
|
compareLayerAndCanvas(layer, canvas, 150);
|
|
|
|
// recache
|
|
group.cache();
|
|
layer.draw();
|
|
compareLayerAndCanvas(layer, canvas, 150);
|
|
});
|
|
|
|
test('cache shape that is larger than stage', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
var group = new Konva.Group();
|
|
var circle = new Konva.Circle({
|
|
x: 74,
|
|
y: 74,
|
|
radius: 300,
|
|
fill: 'red',
|
|
stroke: 'black',
|
|
strokeWidth: 4,
|
|
scaleX: 1 / 2,
|
|
scaleY: 1 / 2,
|
|
});
|
|
|
|
group.add(circle);
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
|
|
assert.equal(circle._getCanvasCache(), undefined);
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
// circle
|
|
context.save();
|
|
context.beginPath();
|
|
context.arc(74, 74, 150, 0, Math.PI * 2);
|
|
context.closePath();
|
|
context.fillStyle = 'red';
|
|
context.lineWidth = 2;
|
|
context.fill();
|
|
context.stroke();
|
|
context.restore();
|
|
|
|
compareLayerAndCanvas(layer, canvas, 150);
|
|
});
|
|
|
|
test('cache shape that is larger than stage but need buffer canvas', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
var group = new Konva.Group();
|
|
var circle = new Konva.Circle({
|
|
x: stage.width() / 2,
|
|
y: stage.height() / 2,
|
|
radius: 400,
|
|
fill: 'red',
|
|
stroke: 'black',
|
|
strokeWidth: 50,
|
|
opacity: 0.5,
|
|
scaleX: 1 / 5,
|
|
scaleY: 1 / 5,
|
|
});
|
|
|
|
group.add(circle);
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
circle.cache();
|
|
layer.draw();
|
|
|
|
cloneAndCompareLayer(layer, 200);
|
|
});
|
|
|
|
test('cache nested groups', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
|
|
var groupOuter = new Konva.Group({
|
|
x: 50,
|
|
y: 10,
|
|
});
|
|
|
|
var groupInner = new Konva.Group({
|
|
x: 10,
|
|
y: 10,
|
|
draggable: true,
|
|
});
|
|
var rect = new Konva.Rect({
|
|
width: 50,
|
|
height: 50,
|
|
stroke: 'grey',
|
|
strokeWidth: 3,
|
|
fill: 'yellow',
|
|
});
|
|
|
|
var text = new Konva.Text({
|
|
x: 18,
|
|
y: 15,
|
|
text: 'A',
|
|
fill: 'black',
|
|
fontSize: 24,
|
|
});
|
|
|
|
groupInner.add(rect);
|
|
groupInner.add(text);
|
|
|
|
groupOuter.add(groupInner);
|
|
|
|
layer.add(groupOuter);
|
|
stage.add(layer);
|
|
|
|
groupInner.cache();
|
|
|
|
layer.draw();
|
|
cloneAndCompareLayer(layer, 150);
|
|
|
|
groupInner.clearCache();
|
|
groupOuter.cache();
|
|
layer.draw();
|
|
cloneAndCompareLayer(layer, 150);
|
|
|
|
groupOuter.clearCache();
|
|
groupInner.clearCache();
|
|
rect.cache();
|
|
layer.draw();
|
|
cloneAndCompareLayer(layer, 150);
|
|
});
|
|
|
|
test('test group with circle + buffer canvas usage', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group({
|
|
x: 100,
|
|
y: 100,
|
|
draggable: true,
|
|
});
|
|
layer.add(group);
|
|
|
|
var circle = new Konva.Circle({
|
|
radius: 10,
|
|
// fill: 'white',
|
|
fillRadialGradientStartRadius: 0,
|
|
fillRadialGradientEndRadius: 10,
|
|
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'black'],
|
|
opacity: 0.4,
|
|
strokeHitEnabled: false,
|
|
stroke: 'rgba(0,0,0,0)',
|
|
});
|
|
group.add(circle);
|
|
group.cache();
|
|
stage.draw();
|
|
|
|
cloneAndCompareLayer(layer, 200);
|
|
});
|
|
|
|
test('test group with opacity', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group({
|
|
x: 100,
|
|
y: 100,
|
|
draggable: true,
|
|
});
|
|
layer.add(group);
|
|
|
|
var circle = new Konva.Circle({
|
|
radius: 10,
|
|
fillRadialGradientStartRadius: 0,
|
|
fillRadialGradientEndRadius: 10,
|
|
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'black'],
|
|
opacity: 0.4,
|
|
strokeHitEnabled: false,
|
|
stroke: 'rgba(0,0,0,0)',
|
|
});
|
|
group.add(circle);
|
|
group.cache();
|
|
stage.draw();
|
|
|
|
cloneAndCompareLayer(layer, 210);
|
|
});
|
|
|
|
test('test group with opacity', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group({
|
|
x: 100,
|
|
y: 100,
|
|
draggable: true,
|
|
});
|
|
layer.add(group);
|
|
|
|
var circle = new Konva.Circle({
|
|
radius: 10,
|
|
fillRadialGradientStartRadius: 0,
|
|
fillRadialGradientEndRadius: 10,
|
|
fillRadialGradientColorStops: [0, 'red', 0.5, 'yellow', 1, 'black'],
|
|
opacity: 0.4,
|
|
strokeHitEnabled: false,
|
|
stroke: 'rgba(0,0,0,0)',
|
|
});
|
|
group.add(circle);
|
|
group.cache();
|
|
stage.draw();
|
|
|
|
cloneAndCompareLayer(layer, 100);
|
|
});
|
|
|
|
test('test rect with float dimensions', function () {
|
|
var stage = addStage();
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group({
|
|
x: 10,
|
|
y: 10,
|
|
draggable: true,
|
|
});
|
|
layer.add(group);
|
|
|
|
var circle = new Konva.Circle({
|
|
radius: 52.2,
|
|
fill: 'red',
|
|
});
|
|
group.add(circle);
|
|
group.cache();
|
|
|
|
const canvas = group._cache.get('canvas').scene;
|
|
assert.equal(canvas.width, 105 * canvas.pixelRatio);
|
|
});
|
|
|
|
test('cache group with rectangle with fill and opacity', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
|
|
var group = new Konva.Group({
|
|
opacity: 0.5,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 50,
|
|
fill: 'green',
|
|
});
|
|
|
|
group.add(rect);
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
|
|
group.cache();
|
|
layer.draw();
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.globalAlpha = 0.5;
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 50);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 5);
|
|
});
|
|
|
|
test('even if parent is not visible cache should be created', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({
|
|
visible: false,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 100,
|
|
fill: 'green',
|
|
});
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
rect.cache();
|
|
layer.visible(true);
|
|
layer.draw();
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 100);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
showHit(layer);
|
|
compareLayerAndCanvas(layer, canvas, 5);
|
|
assert.equal(stage.getIntersection({ x: 150, y: 100 }), rect);
|
|
});
|
|
|
|
test('even if parent is not listening cache and hit should be created', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({
|
|
listening: false,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 100,
|
|
fill: 'green',
|
|
});
|
|
|
|
layer.add(rect);
|
|
stage.add(layer);
|
|
|
|
rect.cache();
|
|
layer.listening(true);
|
|
layer.draw();
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 100);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
showHit(layer);
|
|
compareLayerAndCanvas(layer, canvas, 5);
|
|
assert.equal(stage.getIntersection({ x: 150, y: 100 }), rect);
|
|
});
|
|
|
|
// hard to fix
|
|
test.skip('even if parent is not visible cache should be created - test for group', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({
|
|
visible: false,
|
|
});
|
|
|
|
var group = new Konva.Group({
|
|
opacity: 0.5,
|
|
});
|
|
|
|
var rect = new Konva.Rect({
|
|
x: 100,
|
|
y: 50,
|
|
width: 100,
|
|
height: 100,
|
|
fill: 'green',
|
|
});
|
|
|
|
group.add(rect);
|
|
layer.add(group);
|
|
stage.add(layer);
|
|
|
|
group.cache();
|
|
layer.visible(true);
|
|
layer.draw();
|
|
|
|
var canvas = createCanvas();
|
|
var context = canvas.getContext('2d');
|
|
context.globalAlpha = 0.5;
|
|
context.beginPath();
|
|
context.rect(100, 50, 100, 100);
|
|
context.closePath();
|
|
context.fillStyle = 'green';
|
|
context.fill();
|
|
compareLayerAndCanvas(layer, canvas, 5);
|
|
assert.equal(stage.getIntersection({ x: 150, y: 100 }), rect);
|
|
});
|
|
|
|
it('listening false on a shape should not create hit area', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'green',
|
|
});
|
|
|
|
layer.add(bigCircle);
|
|
|
|
var smallCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 50,
|
|
fill: 'red',
|
|
listening: false,
|
|
});
|
|
|
|
layer.add(smallCircle);
|
|
smallCircle.cache();
|
|
layer.draw();
|
|
|
|
var shape = stage.getIntersection({ x: 100, y: 100 });
|
|
assert.equal(shape, bigCircle);
|
|
});
|
|
|
|
it('listening false on a shape inside group should not create hit area', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group();
|
|
layer.add(group);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'green',
|
|
});
|
|
|
|
group.add(bigCircle);
|
|
|
|
var smallCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 50,
|
|
fill: 'red',
|
|
listening: false,
|
|
});
|
|
|
|
group.add(smallCircle);
|
|
group.cache();
|
|
|
|
layer.draw();
|
|
var shape = stage.getIntersection({ x: 100, y: 100 });
|
|
assert.equal(shape, bigCircle);
|
|
});
|
|
it('listening false on a group inside a group should not create hit area', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group();
|
|
layer.add(group);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'green',
|
|
});
|
|
group.add(bigCircle);
|
|
|
|
var innerGroup = new Konva.Group({
|
|
listening: false,
|
|
});
|
|
group.add(innerGroup);
|
|
|
|
var smallCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 50,
|
|
fill: 'red',
|
|
});
|
|
|
|
innerGroup.add(smallCircle);
|
|
group.cache();
|
|
|
|
layer.draw();
|
|
var shape = stage.getIntersection({ x: 100, y: 100 });
|
|
assert.equal(shape, bigCircle);
|
|
});
|
|
|
|
// for performance reasons
|
|
it('do no call client rect calculation, if we do not need it', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var group = new Konva.Group();
|
|
layer.add(group);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'green',
|
|
});
|
|
group.add(bigCircle);
|
|
|
|
layer.draw();
|
|
|
|
var called = false;
|
|
group.getClientRect = function () {
|
|
called = true;
|
|
};
|
|
group.cache({
|
|
x: 0,
|
|
y: 0,
|
|
width: 100,
|
|
height: 100,
|
|
});
|
|
|
|
assert.equal(called, false);
|
|
});
|
|
|
|
// for performance reasons
|
|
it('caching should skip clearing internal caching for perf boos', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'green',
|
|
});
|
|
layer.add(bigCircle);
|
|
|
|
layer.cache();
|
|
|
|
var callCount = 0;
|
|
bigCircle._clearSelfAndDescendantCache = function () {
|
|
callCount += 1;
|
|
};
|
|
|
|
layer.x(10);
|
|
assert.equal(callCount, 0);
|
|
layer.clearCache();
|
|
// make sure all cleared for children
|
|
assert.equal(callCount, 1);
|
|
});
|
|
|
|
it('caching group with clip', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var width = 100;
|
|
var height = 100;
|
|
var verts = [
|
|
{ x: width * 0.2, y: 0 },
|
|
{ x: width, y: 0 },
|
|
{ x: width * 0.8, y: height },
|
|
{ x: 0, y: height },
|
|
];
|
|
|
|
var clipFunc = (ctx) => {
|
|
for (let i = 0; i < verts.length; i++) {
|
|
const vertex = verts[i];
|
|
if (i === 0) {
|
|
ctx.moveTo(vertex.x, vertex.y);
|
|
} else {
|
|
ctx.lineTo(vertex.x, vertex.y);
|
|
}
|
|
}
|
|
ctx.closePath();
|
|
};
|
|
|
|
var group1 = new Konva.Group({
|
|
clipFunc: clipFunc,
|
|
x: 50,
|
|
y: 50,
|
|
listening: false,
|
|
});
|
|
layer.add(group1);
|
|
var rect1 = new Konva.Rect({
|
|
fill: 'green',
|
|
width: 100,
|
|
height: 100,
|
|
});
|
|
group1.add(rect1);
|
|
|
|
layer.draw();
|
|
group1.cache();
|
|
|
|
layer.draw();
|
|
|
|
// var group2 = group1.clone({
|
|
// x: height - 20,
|
|
// y: 50,
|
|
// });
|
|
// group2.findOne('Rect').fill('red');
|
|
// layer.add(group2);
|
|
// group2.cache();
|
|
|
|
// var group3 = group1.clone({
|
|
// x: width + 20,
|
|
// });
|
|
// layer.add(group3);
|
|
// group3.findOne('Rect').x(150);
|
|
// group2.cache();
|
|
|
|
layer.draw();
|
|
|
|
cloneAndCompareLayer(layer, 10);
|
|
|
|
// throw 1;
|
|
});
|
|
|
|
it('check caching with global composite operation', function () {
|
|
var stage = addStage();
|
|
|
|
const layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
function getColor(pos) {
|
|
var ratio = layer.canvas.pixelRatio;
|
|
var p = layer.canvas.context.getImageData(
|
|
Math.round(pos.x * ratio),
|
|
Math.round(pos.y * ratio),
|
|
1,
|
|
1
|
|
).data;
|
|
return Konva.Util._rgbToHex(p[0], p[1], p[2]);
|
|
}
|
|
|
|
const bg = new Konva.Rect({
|
|
x: 0,
|
|
y: 0,
|
|
width: stage.width(),
|
|
height: stage.height(),
|
|
fill: 'lightgray',
|
|
});
|
|
layer.add(bg);
|
|
|
|
const group = new Konva.Group();
|
|
layer.add(group);
|
|
|
|
const rect = new Konva.Rect({
|
|
x: 10,
|
|
y: 0,
|
|
width: 200,
|
|
height: 100,
|
|
fill: 'blue',
|
|
draggable: true,
|
|
});
|
|
group.add(rect);
|
|
|
|
const maskgroup = new Konva.Group({});
|
|
group.add(maskgroup);
|
|
|
|
const mask = new Konva.Rect({
|
|
x: 50,
|
|
y: 0,
|
|
width: 100,
|
|
height: 100,
|
|
fill: 'black',
|
|
});
|
|
maskgroup.add(mask);
|
|
|
|
maskgroup.cache();
|
|
var canvasBefore = maskgroup._cache.get('canvas').scene._canvas;
|
|
|
|
maskgroup.globalCompositeOperation('destination-in');
|
|
maskgroup.cache();
|
|
var canvasAfter = maskgroup._cache.get('canvas').scene._canvas;
|
|
|
|
compareCanvases(canvasBefore, canvasAfter);
|
|
|
|
maskgroup.clearCache();
|
|
|
|
layer.draw();
|
|
// no caches - mask group clipped all drawing
|
|
assert.equal(getColor({ x: 5, y: 20 }), '000000');
|
|
assert.equal(getColor({ x: 55, y: 20 }), '0000ff');
|
|
|
|
// cache inner mask group - same result
|
|
maskgroup.cache();
|
|
layer.draw();
|
|
|
|
assert.equal(getColor({ x: 5, y: 20 }), '000000');
|
|
assert.equal(getColor({ x: 55, y: 20 }), '0000ff');
|
|
|
|
// cache group
|
|
// background will be visible now, because globalCompositeOperation
|
|
// will work inside cached parent only
|
|
group.cache();
|
|
layer.draw();
|
|
|
|
assert.equal(getColor({ x: 5, y: 20 }), 'd3d3d3');
|
|
assert.equal(getColor({ x: 55, y: 20 }), '0000ff');
|
|
});
|
|
|
|
it('recache should update internal caching', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'red',
|
|
draggable: true,
|
|
});
|
|
layer.add(bigCircle);
|
|
|
|
bigCircle.cache();
|
|
|
|
layer.draw();
|
|
|
|
var d = layer.getContext().getImageData(100, 100, 1, 1).data;
|
|
assert.equal(d[0], 255, 'see red');
|
|
|
|
bigCircle.fill('blue');
|
|
bigCircle.cache();
|
|
|
|
layer.draw();
|
|
d = layer.getContext().getImageData(100, 100, 1, 1).data;
|
|
assert.equal(d[0], 0, 'no red');
|
|
assert.equal(d[2], 255, 'see blue');
|
|
});
|
|
|
|
it('recache with filters', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer();
|
|
stage.add(layer);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 100,
|
|
fill: 'red',
|
|
draggable: true,
|
|
});
|
|
layer.add(bigCircle);
|
|
|
|
bigCircle.filters([Konva.Filters.Blur]);
|
|
bigCircle.blurRadius(10);
|
|
bigCircle.cache();
|
|
|
|
layer.draw();
|
|
bigCircle.cache();
|
|
|
|
layer.draw();
|
|
|
|
var d = layer.getContext().getImageData(100, 100, 1, 1).data;
|
|
assert.equal(d[0], 255, 'see red');
|
|
});
|
|
|
|
test('check image smooth', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({
|
|
imageSmoothingEnabled: false,
|
|
});
|
|
stage.add(layer);
|
|
|
|
var bigCircle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 10,
|
|
fill: 'red',
|
|
draggable: true,
|
|
scaleX: 10,
|
|
scaleY: 10,
|
|
});
|
|
layer.add(bigCircle);
|
|
|
|
bigCircle.cache({
|
|
imageSmoothingEnabled: false,
|
|
});
|
|
|
|
layer.draw();
|
|
assert.equal(
|
|
bigCircle._cache.get('canvas').scene.getContext()._context
|
|
.imageSmoothingEnabled,
|
|
false
|
|
);
|
|
});
|
|
|
|
test('getAbsolutePosition for cached container', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({});
|
|
stage.add(layer);
|
|
|
|
var circle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 10,
|
|
fill: 'red',
|
|
draggable: true,
|
|
scaleX: 10,
|
|
scaleY: 10,
|
|
});
|
|
layer.add(circle);
|
|
// initial calculations
|
|
circle.getAbsolutePosition();
|
|
//
|
|
|
|
layer.cache();
|
|
layer.draw();
|
|
layer.position({
|
|
x: 10,
|
|
y: 10,
|
|
});
|
|
assert.equal(circle.getAbsolutePosition().x, 110);
|
|
assert.equal(circle.getAbsolutePosition().y, 110);
|
|
});
|
|
|
|
test('cached node should not have filter canvas until we have a filter', function () {
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({});
|
|
stage.add(layer);
|
|
|
|
var circle = new Konva.Circle({
|
|
x: 100,
|
|
y: 100,
|
|
radius: 10,
|
|
fill: 'red',
|
|
draggable: true,
|
|
scaleX: 10,
|
|
scaleY: 10,
|
|
});
|
|
layer.add(circle);
|
|
circle.cache();
|
|
|
|
assert.equal(circle._cache.get('canvas').filter.width, 0);
|
|
circle.filters([Konva.Filters.Blur]);
|
|
layer.draw();
|
|
assert.equal(
|
|
circle._cache.get('canvas').filter.width,
|
|
20 * circle._cache.get('canvas').filter.pixelRatio
|
|
);
|
|
circle.filters([]);
|
|
// TODO: should we clear cache canvas?
|
|
// assert.equal(circle._cache.get('canvas').filter.width, 0);
|
|
});
|
|
|
|
test('hit from cache + global composite', function (done) {
|
|
// blend mode should NOT effect hit detection.
|
|
var stage = addStage();
|
|
|
|
var layer = new Konva.Layer({});
|
|
stage.add(layer);
|
|
|
|
Konva.Image.fromURL('./assets/lion.png', function (lion) {
|
|
lion.name('lion');
|
|
lion.cache();
|
|
lion.drawHitFromCache();
|
|
layer.add(lion);
|
|
|
|
Konva.Image.fromURL('./assets/lion.png', function (lion2) {
|
|
lion2.position({
|
|
x: 50,
|
|
y: 50,
|
|
});
|
|
lion2.name('lion2');
|
|
lion2.globalCompositeOperation('overlay');
|
|
lion2.cache();
|
|
lion2.drawHitFromCache();
|
|
layer.add(lion2);
|
|
layer.draw();
|
|
layer.toggleHitCanvas();
|
|
|
|
var shape = layer.getIntersection({ x: 106, y: 78 });
|
|
assert.equal(shape, lion2);
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|