import { assert } from 'chai'; import { Transformer } from '../../src/shapes/Transformer'; import { addStage, isNode, Konva, simulateMouseDown as sd, simulateMouseMove as sm, simulateMouseUp as su, assertAlmostEqual, } from './test-utils'; function simulateMouseDown(tr, pos) { sd(tr.getStage(), pos); } function simulateMouseMove(tr, pos) { const stage = tr.getStage(); var top = (stage.content && stage.content.getBoundingClientRect().top) || 0; tr._handleMouseMove({ ...pos, clientX: pos.x, clientY: pos.y + top, }); sm(stage, pos); } function simulateMouseUp(tr: Transformer, pos = { x: 0, y: 0 }) { const stage = tr.getStage(); var top = (stage.content && stage.content.getBoundingClientRect().top) || 0; tr._handleMouseUp({ clientX: pos.x, clientY: pos.y + top, }); su(tr.getStage(), pos || { x: 1, y: 1 }); } describe('Transformer', function () { // ====================================================== it('init transformer on simple rectangle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); assert.equal(tr.x(), rect.x()); assert.equal(tr.y(), rect.y()); assert.equal(tr.width(), rect.width()); assert.equal(tr.height(), rect.height()); // manual check of correct position of node var handler = tr.findOne('.bottom-right'); var pos = handler.getAbsolutePosition(); assert.equal(pos.x, rect.x() + rect.width()); assert.equal(pos.y, rect.y() + rect.height()); }); it('can attach transformer into several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 10, y: 10, draggable: true, width: 100, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 110, y: 60, draggable: true, width: 100, height: 50, fill: 'red', }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); assert.equal(tr.x(), rect1.x()); assert.equal(tr.y(), rect1.y()); assert.equal(tr.width(), rect1.width() + rect2.width()); assert.equal(tr.height(), rect1.height() + rect2.height()); assert.equal(tr.rotation(), 0); }); it('try set/get node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var circle = new Konva.Circle({ x: 10, y: 60, radius: 100, fill: 'red', }); layer.add(circle); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.nodes()[0], rect); tr.nodes([circle]); assert.equal(tr.nodes()[0], circle); layer.draw(); }); it('try to fit simple rectangle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 120, y: 60, width: 50, height: 50, rotation: Konva.getAngle(45), }); assert.equal(tr.x(), rect.x()); assert.equal(Math.round(tr.y()), rect.y()); assert.equal(tr.width(), 50); assert.equal(tr.height(), 50); assert.equal(tr.rotation(), rect.rotation()); }); it('try to fit simple rotated rectangle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 150, fill: 'yellow', rotation: 45, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 50, y: 50, width: 100, height: 150, rotation: Konva.getAngle(45), }); assertAlmostEqual(rect.x(), 50); assertAlmostEqual(rect.y(), 50); assertAlmostEqual(tr.width(), 100); assertAlmostEqual(tr.height(), 150); assertAlmostEqual(tr.rotation(), rect.rotation()); }); it('transformer should follow rotation on single node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); rect.rotation(45); layer.draw(); assert.equal(tr.rotation(), 45); }); it('try to fit simple rotated rectangle in group', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var group = new Konva.Group({ rotation: 45, x: 50, y: 50, }); layer.add(group); var rect = new Konva.Rect({ draggable: true, width: 100, height: 150, fill: 'yellow', }); group.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 50, y: 50, width: 100, height: 150, rotation: 0, }); assertAlmostEqual(rect.x(), 0); assertAlmostEqual(rect.y(), 0); assertAlmostEqual(tr.width(), 100); assertAlmostEqual(tr.height(), 150); assertAlmostEqual(rect.rotation(), -45); }); it('transformer should follow rotation on single node inside group', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var group = new Konva.Group({ rotation: 45, }); layer.add(group); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); group.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); group.add(tr); layer.draw(); rect.rotation(45); layer.draw(); assertAlmostEqual(tr.rotation(), 90); }); it('try to fit simple rotated rectangle - 2', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 200, fill: 'yellow', rotation: 45, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 40, y: 40, width: 100, height: 100, rotation: 0, }); assertAlmostEqual(rect.x(), 40); assertAlmostEqual(rect.y(), 40); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.height(), 200); assertAlmostEqual(rect.scaleY(), 0.5); assertAlmostEqual(rect.rotation(), 0); }); it('rotate around center', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 200, fill: 'yellow', rotation: 45, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 40, y: 40, width: 100, height: 100, rotation: 0, }); assertAlmostEqual(rect.x(), 40); assertAlmostEqual(rect.y(), 40); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.height(), 200); assertAlmostEqual(rect.scaleY(), 0.5); assertAlmostEqual(rect.rotation(), 0); }); it('change transform of parent', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.x(), 50, 'first x'); stage.scaleX(2); stage.scaleY(2); // check attrs assert.equal(tr.x(), 100, 'second x'); assert.equal(tr.width(), 200); // check visual var pos = tr.findOne('.top-right').getAbsolutePosition(); assert.equal(pos.x, 300); stage.draw(); }); it('rotated inside scaled (in one direction) parent', function () { var stage = addStage(); stage.scaleX(2); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); tr._fitNodesInto({ x: 100, y: 0, width: 50, height: 50, rotation: Konva.getAngle(45), }); assert.equal(rect.x(), 50); assert.equal(rect.skewX(), 0.75); assert.equal(rect.skewY(), 0); }); it('try to fit rectangle with skew', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', skewX: 0.5, scaleX: 2, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 120, y: 60, width: 50, height: 50, rotation: Konva.getAngle(45), }); assert.equal(tr.x(), rect.x()); assert.equal(Math.round(tr.y()), rect.y()); assert.equal(tr.width(), 50); assert.equal(tr.height(), 50); assert.equal(tr.rotation(), rect.rotation()); assertAlmostEqual(rect.skewX(), 0.2); }); it('try to resize in draggable stage', function () { var stage = addStage(); stage.draggable(true); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var dragstart = 0; var dragmove = 0; var dragend = 0; stage.on('dragstart', function () { dragstart += 1; }); stage.on('dragmove', function () { dragmove += 1; }); stage.on('dragend', function () { dragend += 1; }); simulateMouseDown(tr, { x: 50, y: 50, }); simulateMouseMove(tr, { x: 60, y: 60, }); assert.equal(stage.isDragging(), false); assert.equal(dragstart, 0); simulateMouseUp(tr, { x: 60, y: 60 }); assert.equal(dragmove, 0); assert.equal(dragend, 0); simulateMouseDown(tr, { x: 40, y: 40, }); sm(stage, { x: 45, y: 45, }); sm(stage, { x: 50, y: 50, }); assert.equal(stage.isDragging(), true); assert.equal(stage.x(), 10); assert.equal(stage.y(), 10); su(stage, { x: 45, y: 45, }); }); it('try to fit simple rectangle into negative scale', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); var box = { x: 100, y: 0, width: -100, height: 100, rotation: 0, }; tr._fitNodesInto(box); assertAlmostEqual(rect.x(), 100); assertAlmostEqual(rect.y(), 0); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.scaleY(), -1); assertAlmostEqual(rect.rotation(), -180); layer.draw(); }); it('try to fit rectangle with ignoreStroke = false', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 20, y: 20, width: 100, height: 100, fill: 'green', stroke: 'rgba(0,0,0,0.5)', strokeWidth: 40, name: 'myCircle', draggable: true, strokeScaleEnabled: false, }); layer.add(rect); var tr = new Konva.Transformer({ ignoreStroke: true, }); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 20, y: 20, width: 200, height: 200, rotation: 0, }); assertAlmostEqual(rect.x(), 20); assertAlmostEqual(rect.y(), 20); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.scaleX(), 2); }); it('listen shape changes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); rect.setAttrs({ x: 50, y: 50, width: 100, height: 100, }); layer.draw(); assert.equal(tr.x(), rect.x()); assert.equal(tr.y(), rect.y()); assert.equal(tr.width(), rect.width()); assert.equal(tr.height(), rect.height()); assert.equal(tr.findOne('.back').width(), rect.width()); }); it('add transformer for transformed rect', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 150, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', rotation: 90, scaleY: 1.5, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); layer.draw(); assert.equal(tr.x(), rect.x()); assert.equal(tr.y(), rect.y()); assert.equal(tr.width(), rect.width() * rect.scaleX()); assert.equal(tr.height(), rect.height() * rect.scaleY()); assert.equal(tr.rotation(), rect.rotation()); }); it('try to fit a transformed rect', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 150, y: 60, draggable: true, width: 150, height: 100, fill: 'yellow', rotation: 90, scaleY: 1.5, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); tr._fitNodesInto({ x: 100, y: 70, width: 100, height: 100, rotation: 0, }); assertAlmostEqual(rect.x(), 100); assertAlmostEqual(rect.y(), 70); assertAlmostEqual(rect.width() * rect.scaleX(), 100); assertAlmostEqual(rect.height() * rect.scaleY(), 100); assertAlmostEqual(rect.rotation(), rect.rotation()); }); it('add transformer for transformed rect with offset', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 100, height: 100, scaleX: 2, scaleY: 2, fill: 'yellow', offsetX: 50, offsetY: 50, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); assert.equal(tr.x(), 0); assert.equal(tr.y(), 0); assert.equal(tr.width(), rect.width() * rect.scaleX()); assert.equal(tr.height(), rect.height() * rect.scaleY()); assert.equal(tr.rotation(), rect.rotation()); }); it('fit rect with offset', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', offsetX: 50, offsetY: 50, }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); tr._fitNodesInto({ x: 0, y: 0, width: 200, height: 100, rotation: 0, }); layer.draw(); assertAlmostEqual(rect.x(), 100); assertAlmostEqual(rect.y(), 50); assertAlmostEqual(rect.width() * rect.scaleX(), 200); assertAlmostEqual(rect.height() * rect.scaleY(), 100); assertAlmostEqual(rect.rotation(), rect.rotation()); assertAlmostEqual(tr.x(), 0); assertAlmostEqual(tr.y(), 0); assertAlmostEqual(tr.width(), 200); assertAlmostEqual(tr.height(), 100); assertAlmostEqual(rect.rotation(), rect.rotation()); }); it('add transformer for circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var circle = new Konva.Circle({ x: 40, y: 40, draggable: true, radius: 40, fill: 'yellow', }); layer.add(circle); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([circle]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); assert.equal(tr.x(), 0); assert.equal(tr.y(), 0); assert.equal(tr.width(), circle.width() * circle.scaleX()); assert.equal(tr.height(), circle.height() * circle.scaleY()); assert.equal(tr.rotation(), circle.rotation()); }); it('fit a circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var circle = new Konva.Circle({ x: 40, y: 40, draggable: true, radius: 40, fill: 'yellow', }); layer.add(circle); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([circle]); tr._fitNodesInto({ x: 40, y: 40, width: 160, height: 80, rotation: 0, }); layer.draw(); assert.equal(circle.x(), 120); assert.equal(circle.y(), 80); assert.equal(circle.width() * circle.scaleX(), 160); assert.equal(circle.height() * circle.scaleY(), 80); assert.equal(tr.x(), 40); assert.equal(tr.y(), 40); assert.equal(tr.width(), 160); assert.equal(tr.height(), 80); }); it('fit a rotated circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var circle = new Konva.Circle({ x: 40, y: 40, draggable: true, radius: 40, fill: 'yellow', }); layer.add(circle); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([circle]); tr._fitNodesInto({ x: 80, y: 0, width: 80, height: 80, rotation: Konva.getAngle(90), }); layer.draw(); assertAlmostEqual(circle.x(), 40); assertAlmostEqual(circle.y(), 40); assertAlmostEqual(circle.width() * circle.scaleX(), 80); assertAlmostEqual(circle.height() * circle.scaleY(), 80); assertAlmostEqual(circle.rotation(), 90); assertAlmostEqual(tr.x(), 80); assertAlmostEqual(tr.y(), 0); assertAlmostEqual(tr.width(), 80); assertAlmostEqual(tr.height(), 80); }); it('add transformer for transformed circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var circle = new Konva.Circle({ x: 100, y: 100, draggable: true, radius: 40, fill: 'yellow', scaleX: 1.5, }); layer.add(circle); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([circle]); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); assert.equal(tr.x(), 40); assert.equal(tr.y(), 60); assert.equal(tr.width(), 120); assert.equal(tr.height(), 80); assert.equal(tr.rotation(), 0); }); it('add transformer for rotated circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var circle = new Konva.Circle({ x: 100, y: 100, draggable: true, radius: 40, fill: 'yellow', scaleX: 1.5, rotation: 90, }); layer.add(circle); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([circle]); layer.draw(); assert.equal(tr.x(), 140); assert.equal(tr.y(), 40); assert.equal(tr.width(), 120); assert.equal(tr.height(), 80); assert.equal(tr.rotation(), circle.rotation()); }); it('add transformer to group', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var group = new Konva.Group({ x: 50, y: 50, draggable: true, }); layer.add(group); var shape1 = new Konva.Rect({ radius: 100, fill: 'red', x: 0, y: 0, width: 100, height: 100, }); group.add(shape1); var shape2 = new Konva.Rect({ radius: 100, fill: 'yellow', x: 50, y: 50, width: 100, height: 100, }); group.add(shape2); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([group]); layer.draw(); assert.equal(tr.x(), group.x()); assert.equal(tr.y(), group.y()); assert.equal(tr.width(), 150); assert.equal(tr.height(), 150); assert.equal(tr.rotation(), 0); }); it('rotated fit group', 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 shape1 = new Konva.Rect({ fill: 'red', x: -50, y: -50, width: 50, height: 50, }); group.add(shape1); var shape2 = new Konva.Rect({ fill: 'yellow', x: 0, y: 0, width: 50, height: 50, }); group.add(shape2); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([group]); tr._fitNodesInto({ x: 100, y: 0, width: 100, height: 100, rotation: Konva.getAngle(90), }); layer.draw(); var rect = group.getClientRect(); assertAlmostEqual(group.x(), 50); assertAlmostEqual(group.y(), 50); assertAlmostEqual(rect.width, 100); assertAlmostEqual(rect.height, 100); assertAlmostEqual(group.rotation(), 90); assertAlmostEqual(tr.x(), 100); assertAlmostEqual(tr.y(), 0); assertAlmostEqual(tr.width(), 100); assertAlmostEqual(tr.height(), 100); }); it('add transformer to another group', 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 shape1 = new Konva.Rect({ fill: 'red', x: -50, y: -50, width: 50, height: 50, }); group.add(shape1); var shape2 = new Konva.Rect({ fill: 'yellow', x: 0, y: 0, width: 50, height: 50, }); group.add(shape2); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([group]); layer.draw(); assert.equal(tr.x(), 50); assert.equal(tr.y(), 50); assert.equal(tr.width(), 100); assert.equal(tr.height(), 100); assert.equal(tr.rotation(), 0); }); it('fit group', 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 shape1 = new Konva.Rect({ fill: 'red', x: -50, y: -50, width: 50, height: 50, }); group.add(shape1); var shape2 = new Konva.Rect({ fill: 'yellow', x: 0, y: 0, width: 50, height: 50, }); group.add(shape2); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([group]); tr._fitNodesInto({ x: 0, y: 0, width: 200, height: 100, rotation: 0, }); layer.draw(); var rect = group.getClientRect(); assertAlmostEqual(group.x(), 100); assertAlmostEqual(group.y(), 50); assertAlmostEqual(rect.width, 200); assertAlmostEqual(rect.height, 100); assertAlmostEqual(tr.x(), 0); assertAlmostEqual(tr.y(), 0); assertAlmostEqual(tr.width(), 200); assertAlmostEqual(tr.height(), 100); }); it('toJSON should not save attached node and children', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([rect]); layer.draw(); var json = tr.toJSON(); var object = JSON.parse(json); assert.equal(object.attrs.node, undefined); assert.equal(object.children, undefined); }); it('make sure we can work without inner node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var tr = new Konva.Transformer(); layer.add(tr); layer.draw(); // just check not throw assert.equal(1, 1); }); it('reset attrs on node set', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); layer.draw(); assert.equal(tr.getWidth(), 0); tr.nodes([rect]); assert.equal(tr.getWidth(), 100); }); it('can destroy without attached node', function () { var tr = new Konva.Transformer(); tr.destroy(); // just check not throw assert.equal(1, 1); }); it('can destroy with attached node while resize', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 100, y: 60, }); assert.equal(tr.isTransforming(), true); tr.destroy(); assert.equal(tr.isTransforming(), false); assert.equal(tr.getNode(), undefined); su(stage, { x: 100, y: 60, }); }); it('can add padding', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 30, y: 30, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], padding: 20, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 10, y: 80, }); simulateMouseMove(tr, { x: 60, y: 80, }); simulateMouseUp(tr, { x: 200, y: 150, }); assertAlmostEqual(rect.x(), 80); assertAlmostEqual(rect.y(), 30); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.5); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.scaleY(), 1); }); it('keep ratio should allow negative scaling', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 150, y: 10, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var anchor = tr.findOne('.top-right'); var pos = anchor.getAbsolutePosition(); simulateMouseDown(tr, { x: pos.x, y: pos.y, }); simulateMouseMove(tr, { x: pos.x - 100, y: pos.y + 100, }); simulateMouseUp(tr, { x: pos.x - 100, y: pos.y + 100, }); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.scaleY(), 1); assertAlmostEqual(rect.rotation(), -180); }); it('slightly move for cache check (top-left anchor)', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 20, y: 20, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var anchor = tr.findOne('.top-left'); assertAlmostEqual(anchor.getAbsolutePosition().x, 20); simulateMouseDown(tr, { x: 20, y: 20, }); simulateMouseMove(tr, { x: 20, y: 20, }); simulateMouseUp(tr); layer.draw(); assertAlmostEqual(rect.x(), 20); assertAlmostEqual(rect.y(), 20); }); it('rotation snaps', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], rotationSnaps: [0, 90, 180, 270], rotationSnapTolerance: 45, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 100, y: 0, }); // move to almost 45 deg simulateMouseMove(tr, { x: 199, y: 0, }); assert.equal(rect.rotation(), 0); // move to more than 45 deg simulateMouseMove(tr, { x: 200, y: 2, }); assert.equal(rect.rotation(), 90); simulateMouseMove(tr, { x: 200, y: 199, }); assert.equal(rect.rotation(), 90); simulateMouseMove(tr, { x: 199, y: 200, }); assert.equal(rect.rotation(), 180); simulateMouseMove(tr, { x: 1, y: 200, }); assert.equal(rect.rotation(), 180); simulateMouseMove(tr, { x: 0, y: 199, }); assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 50, }); assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 45, }); assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 0, y: 1, }); assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 1, y: 0, }); assert.equal(rect.rotation(), 0); simulateMouseUp(tr); }); it('switch scaling with padding - x', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 10, y: 10, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], padding: 10, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 0, y: 60, }); simulateMouseMove(tr, { x: 125, y: 60, }); assertAlmostEqual(rect.x(), 115); assertAlmostEqual(rect.y(), 10); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.05); assertAlmostEqual(rect.scaleY(), -1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), -180); simulateMouseMove(tr, { x: 125, y: 60, }); assertAlmostEqual(rect.x(), 115); assertAlmostEqual(rect.y(), 10); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.scaleY(), -1); // switch again simulateMouseMove(tr, { x: 90, y: 60, }); assertAlmostEqual(rect.x(), 100); assertAlmostEqual(rect.y(), 10); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleY(), 1); assertAlmostEqual(rect.scaleX(), 0.1); assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); it('switch scaling with padding - y', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 10, y: 10, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], padding: 10, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 60, y: 0, }); simulateMouseMove(tr, { x: 60, y: 125, }); assertAlmostEqual(rect.x(), 10); assertAlmostEqual(rect.y(), 115); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleY(), -0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 0); simulateMouseMove(tr, { x: 60, y: 125, }); assertAlmostEqual(rect.x(), 10); assertAlmostEqual(rect.y(), 115); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleY(), -0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 0); // switch again simulateMouseMove(tr, { x: 60, y: 90, }); assertAlmostEqual(rect.x(), 10); assertAlmostEqual(rect.y(), 100); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.scaleY(), 0.1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 0); simulateMouseUp(tr); }); it('switch horizontal scaling with (top-left anchor)', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 0, y: 0, }); simulateMouseMove(tr, { x: 150, y: 50, }); layer.draw(); assertAlmostEqual(rect.x(), 150); assertAlmostEqual(rect.y(), 50); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.5); assertAlmostEqual(rect.scaleY(), -0.5); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), -180); simulateMouseMove(tr, { x: 98, y: 2.859375, }); simulateMouseMove(tr, { x: 98, y: 2.859375, }); simulateMouseMove(tr, { x: 98, y: 2.859375, }); simulateMouseMove(tr, { x: 100, y: 2.859375, }); layer.draw(); simulateMouseMove(tr, { x: 101, y: 2.859375, }); layer.draw(); simulateMouseMove(tr, { x: 101, y: 2.859375, }); layer.draw(); simulateMouseMove(tr, { x: 101, y: 2.859375, }); layer.draw(); simulateMouseMove(tr, { x: 102, y: 2.859375, }); layer.draw(); // switch again simulateMouseMove(tr, { x: 0, y: 0, }); assertAlmostEqual(rect.x(), 0); assertAlmostEqual(rect.y(), 0); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleY(), 1); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); it('switch vertical scaling with (top-left anchor)', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 0, y: 0, }); simulateMouseMove(tr, { x: 0, y: 200, }); layer.draw(); assertAlmostEqual(rect.x(), 0); assertAlmostEqual(rect.y(), 200); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 0); simulateMouseMove(tr, { x: 0, y: 0, }); layer.draw(); simulateMouseUp(tr); assertAlmostEqual(rect.x(), 0); assertAlmostEqual(rect.y(), 0); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 0); assertAlmostEqual(rect.scaleY(), 1); }); it('switch scaling with padding for rotated - x', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 110, y: 10, draggable: true, width: 100, height: 100, fill: 'yellow', rotation: 90, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], padding: 10, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 60, y: 0, }); simulateMouseMove(tr, { x: 60, y: 125, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y(), 115); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.05); assertAlmostEqual(rect.scaleY(), -1); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), -90); simulateMouseMove(tr, { x: 60, y: 125, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y(), 115); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.scaleY(), -1); layer.draw(); // switch again simulateMouseMove(tr, { x: 60, y: 90, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y(), 100); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 0.1); assertAlmostEqual(rect.scaleY(), 1); assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); it('switch scaling with padding for rotated - y', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 110, y: 10, draggable: true, width: 100, height: 100, fill: 'yellow', rotation: 90, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], padding: 10, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 0, y: 60, }); simulateMouseMove(tr, { x: 125, y: 60, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y(), 10); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.scaleY(), -0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 90); simulateMouseMove(tr, { x: 125, y: 60, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y(), 10); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.scaleY(), -0.05); assertAlmostEqual(rect.height(), 100); assertAlmostEqual(rect.rotation(), 90); // switch again simulateMouseMove(tr, { x: 90, y: 60, }); assertAlmostEqual(rect.x(), 110); assertAlmostEqual(rect.y() - 120 < 0.001, true); assertAlmostEqual(rect.width(), 100); assertAlmostEqual(rect.scaleX(), 1); assertAlmostEqual(rect.scaleY(), 0.1); assertAlmostEqual(rect.height(), 100); simulateMouseUp(tr); }); it('transformer should automatically track attr changes of a node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.x(), 100); assert.equal(tr.y(), 60); assert.equal(tr.width(), 100); assert.equal(rect.height(), 100); assert.equal(rect.rotation(), 0); rect.x(0); assert.equal(tr.x(), 0); rect.y(0); assert.equal(tr.y(), 0); rect.width(50); assert.equal(tr.width(), 50); rect.height(50); assert.equal(tr.height(), 50); rect.scaleX(2); assert.equal(tr.width(), 100); rect.scaleY(2); assert.equal(tr.height(), 100); // manual check position var back = tr.findOne('.back'); assert.equal(back.getAbsolutePosition().x, 0); layer.batchDraw(); }); it('on detach should remove all listeners', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); tr.detach(); rect.width(200); assert.equal(tr.width(), 0); layer.draw(); var called = false; // clear cache is called on each update // make sure we don't call it tr._clearCache = function () { called = true; }; rect.width(50); assert.equal(called, false, 'don not call clear cache'); }); it('check transformer with drag&drop', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, width: 100, height: 100, fill: 'green', draggable: true, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 20, y: 20, }); sm(stage, { x: 30, y: 30, }); su(stage, { x: 30, y: 30, }); assert.equal(rect.x(), 10); assert.equal(rect.y(), 10); assert.equal(tr.x(), 10); assert.equal(tr.y(), 10); }); it('check transformer with drag&drop and scaled shape', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, width: 100, height: 100, fill: 'green', draggable: true, scaleX: 2, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 20, y: 20, }); sm(stage, { x: 30, y: 30, }); layer.draw(); assert.equal(rect.x(), 10); assert.equal(rect.y(), 10); assert.equal(tr.x(), 10); assert.equal(tr.y(), 10); assert.equal(tr.width(), 200); su(stage, { x: 30, y: 30, }); }); it('try rotate scaled rect', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 150, draggable: true, width: 100, height: 100, fill: 'yellow', scaleY: -1, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var rotater = tr.findOne('.rotater'); var pos = rotater.getAbsolutePosition(); simulateMouseDown(tr, { x: pos.x, y: pos.y, }); simulateMouseMove(tr, { x: pos.x + 100, y: pos.y + 100, }); simulateMouseUp(tr, { x: pos.x + 100, y: pos.y + 100, }); assert.equal(rect.rotation(), 90); }); it('check correct cursor on scaled shape', function () { if (isNode) { return; } var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 100, draggable: true, width: 100, height: 100, fill: 'yellow', scaleY: -1, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); sm(stage, { x: 50, y: 1, }); assert.equal(stage.content.style.cursor, 'nwse-resize'); }); it('check correct cursor off on Transformer destroy', function () { if (isNode) { return; } var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); sm(stage, { x: 100, y: 100, }); simulateMouseDown(tr, { x: 100, y: 100, }); assert.equal(stage.content.style.cursor, 'nwse-resize'); var target = stage.getIntersection({ x: 100, y: 100, }); simulateMouseMove(tr, { x: 120, y: 100, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: 120, y: 100, }); su(stage, { x: 120, y: 100, }); tr.destroy(); sm(stage, { x: 140, y: 100, }); assert.equal(stage.content.style.cursor, ''); }); it('check correct cursor on scaled parent', function () { if (isNode) { return; } var stage = addStage(); var layer = new Konva.Layer({ y: 100, scaleY: -1, }); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); sm(stage, { x: 50, y: 1, }); assert.equal(stage.content.style.cursor, 'nwse-resize'); }); it('changing parent transform should recalculate transformer attrs', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); layer.scaleX(2); layer.draw(); assert.equal(tr.width(), 200); }); it('check fit and correct cursor on rotated parent', function () { if (isNode) { return; } var stage = addStage(); var layer = new Konva.Layer({ x: 100, y: -50, rotation: 90, }); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var box = { x: 100, y: 0, width: 100, height: 100, rotation: Konva.getAngle(90), }; tr._fitNodesInto(box); assert.equal(Math.round(tr.x()), Math.round(box.x)); assert.equal(Math.round(tr.y()), Math.round(box.y)); assert.equal(Math.round(tr.width()), Math.round(box.width)); assert.equal(Math.round(tr.height()), Math.round(box.height)); sm(stage, { x: 50, y: 1, }); assert.equal(stage.content.style.cursor, 'ns-resize'); }); it('check drag with transformer', function () { var stage = addStage(); stage.draggable(true); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 50, y: 50, }); sm(stage, { x: 55, y: 50, }); sm(stage, { x: 60, y: 50, }); su(stage, { x: 60, y: 50, }); assert.equal(rect.x(), 10); assert.equal(rect.y(), 0); }); it('stopTransform method', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 50, y: 50, }); simulateMouseMove(tr, { x: 60, y: 60, }); assert.equal(tr.isTransforming(), true); assert.equal(rect.x(), 60); var transformend = 0; rect.on('transformend', function () { transformend += 1; }); tr.stopTransform(); assert.equal(transformend, 1); assert.equal(tr.isTransforming(), false); assert.equal(rect.x(), 60); // here is duplicate, because transformer is listening window events su(stage, { x: 100, y: 100, }); }); it('transform events check', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var callCount = 0; rect.on('transformstart', function (e) { callCount += 1; assert.equal(e.target, rect); assert.equal(tr.getActiveAnchor(), 'top-left'); }); rect.on('transform', function (e) { callCount += 1; assert.equal(e.target, rect); assert.equal(tr.getActiveAnchor(), 'top-left'); }); rect.on('transformend', function (e) { callCount += 1; assert.equal(e.target, rect); assert.equal(tr.getActiveAnchor(), 'top-left'); }); tr.on('transformstart', function (e) { callCount += 1; assert.equal(e.target, rect); }); tr.on('transform', function (e) { callCount += 1; assert.equal(e.target, rect); }); tr.on('transformend', function (e) { callCount += 1; assert.equal(e.target, rect); }); simulateMouseDown(tr, { x: 50, y: 50, }); simulateMouseMove(tr, { x: 60, y: 60, }); simulateMouseUp(tr, { x: 60, y: 60, }); assert.equal(callCount, 6); assert.equal(tr.getActiveAnchor(), null); }); it('on force update should clear transform', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var group = new Konva.Group({ x: 50, y: 50, }); layer.add(group); var tr = new Konva.Transformer(); layer.add(tr); tr.nodes([group]); layer.draw(); assert.equal(tr._cache.get('transform').m[4], 50); var rect = new Konva.Rect({ x: 50, y: 50, width: 100, height: 100, fill: 'yellow', }); group.add(rect); tr.forceUpdate(); layer.draw(); assert.equal(tr._cache.get('transform').m[4], 100); // tr._fitNodesInto({ // x: 100, // y: 70, // width: 100, // height: 100 // }); // assert.equal(rect.x(), 100); // assert.equal(rect.y(), 70); // assert.equal(rect.width() * rect.scaleX(), 100); // assert.equal(rect.height() * rect.scaleY(), 100); // assert.equal(rect.rotation(), rect.rotation()); }); it('test cache reset on attach', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 20, y: 20, draggable: true, width: 150, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer(); layer.add(tr); // make draw to set all caches layer.draw(); // then attach tr.nodes([rect]); layer.draw(); var shape = layer.getIntersection({ x: 20, y: 20, }); assert.equal(shape.name(), 'top-left _anchor'); }); it('check rotator size on scaled transformer', function () { var stage = addStage(); var layer = new Konva.Layer({ scaleX: 10, scaleY: 10, }); stage.add(layer); var rect = new Konva.Rect({ x: 5, y: 16, draggable: true, width: 10, height: 10, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); var rotater = tr.findOne('.rotater'); var pos = rotater.getAbsolutePosition(); // pos.x === (x * scaleX - (height)) assert.equal(pos.x, 100); // pos.y === (y * scaleY - (height * scaleY / 2)) assert.equal(pos.y, 110); }); var tests = [ { name: 'top-left', startPos: { x: 0, y: 0, }, endPos: { x: 25, y: 25, }, expectedWidth: 50, expectedHeight: 50, }, { name: 'top-center', startPos: { x: 50, y: 0, }, endPos: { x: 50, y: 25, }, expectedWidth: 100, expectedHeight: 50, }, { name: 'top-right', startPos: { x: 100, y: 0, }, endPos: { x: 75, y: 25, }, expectedWidth: 50, expectedHeight: 50, }, { name: 'middle-left', startPos: { x: 0, y: 50, }, endPos: { x: 25, y: 50, }, expectedWidth: 50, expectedHeight: 100, }, { name: 'middle-right', startPos: { x: 100, y: 50, }, endPos: { x: 75, y: 50, }, expectedWidth: 50, expectedHeight: 100, }, { name: 'bottom-left', startPos: { x: 0, y: 100, }, endPos: { x: 25, y: 75, }, expectedWidth: 50, expectedHeight: 50, }, { name: 'bottom-center', startPos: { x: 50, y: 100, }, endPos: { x: 50, y: 75, }, expectedWidth: 100, expectedHeight: 50, }, { name: 'bottom-right', startPos: { x: 100, y: 100, }, endPos: { x: 75, y: 75, }, expectedWidth: 50, expectedHeight: 50, }, // { // name: 'top-left-reverse', // startPos: { // x: 0, // y: 0 // }, // endPos: { // x: 100, // y: 100 // }, // expectedWidth: 100, // expectedHeight: 100 // } ]; it('if alt is pressed should transform around center', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); tests.forEach(function (test) { rect.setAttrs({ x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1, }); tr.update(); layer.draw(); simulateMouseDown(tr, test.startPos); var target = stage.getIntersection(test.startPos); simulateMouseMove(tr, { target: target, x: test.endPos.x, y: test.endPos.y, altKey: true, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: test.endPos.x, y: test.endPos.y, }); su(stage, { x: test.endPos.x, y: test.endPos.y, }); layer.draw(); assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); it('centered scaling - no keep ratio', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], centeredScaling: true, keepRatio: false, }); layer.add(tr); tests.forEach(function (test) { rect.setAttrs({ x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1, }); tr.update(); layer.draw(); simulateMouseDown(tr, test.startPos); var target = stage.getIntersection(test.startPos); simulateMouseMove(tr, { target: target, x: test.endPos.x, y: test.endPos.y, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: test.endPos.x, y: test.endPos.y, }); su(stage, { x: test.endPos.x, y: test.endPos.y, }); layer.draw(); assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); it('centered scaling', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], centeredScaling: true, }); layer.add(tr); tests.forEach(function (test) { rect.setAttrs({ x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1, }); tr.update(); layer.draw(); simulateMouseDown(tr, test.startPos); var target = stage.getIntersection(test.startPos); simulateMouseMove(tr, { target: target, x: test.endPos.x, y: test.endPos.y, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: test.endPos.x, y: test.endPos.y, }); su(stage, { x: test.endPos.x, y: test.endPos.y, }); layer.draw(); assertAlmostEqual(rect.width() * rect.scaleX(), test.expectedWidth); assertAlmostEqual(rect.height() * rect.scaleY(), test.expectedHeight); }); }); it('centered scaling on flip + keep ratio', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], centeredScaling: true, keepRatio: true, }); layer.add(tr); // try to move mouse from edge corners into different directions var tl = { x: 0, y: 0 }; var trr = { x: 200, y: 0 }; var bl = { x: 0, y: 100 }; var br = { x: 200, y: 100 }; var tests = [ [tl, trr], [tl, bl], [tl, br], [trr, tl], [trr, bl], [trr, br], [bl, tl], [bl, trr], [bl, br], [br, tl], [br, trr], [br, bl], ]; tests.forEach((test) => { var start = test[0]; var end = test[1]; rect.setAttrs({ x: 0, y: 0, width: 200, height: 100, scaleX: 1, scaleY: 1, rotation: 0, }); layer.draw(); // move from start to end simulateMouseDown(tr, start); simulateMouseMove(tr, end); var box = rect.getClientRect(); assertAlmostEqual(box.x, 0); assertAlmostEqual(box.y, 0); assertAlmostEqual(box.width, 200); assertAlmostEqual(box.height, 100); // make extra move on end simulateMouseMove(tr, end); var box = rect.getClientRect(); assertAlmostEqual(box.x, 0); assertAlmostEqual(box.y, 0); assertAlmostEqual(box.width, 200); assertAlmostEqual(box.height, 100); // move back simulateMouseMove(tr, start); simulateMouseUp(tr); assertAlmostEqual(box.x, 0); assertAlmostEqual(box.y, 0); assertAlmostEqual(box.width, 200); assertAlmostEqual(box.height, 100); }); }); it('transform scaled (in one direction) node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ draggable: true, x: 150, y: 50, width: 100, height: 100, scaleX: -1, fillLinearGradientStartPoint: { x: 0, y: 0 }, fillLinearGradientEndPoint: { x: 100, y: 100 }, fillLinearGradientColorStops: [0, 'red', 0.8, 'yellow'], }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 150, y: 150, }); var target = stage.getIntersection({ x: 150, y: 150, }); simulateMouseMove(tr, { x: 100, y: 100, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: 100, y: 100, }); su(stage, { x: 100, y: 100, }); layer.draw(); assert.equal(rect.width() * rect.scaleX() - 50 < 1, true, ' width check'); assert.equal(rect.height() * rect.scaleY() + 50 < 1, true, ' height check'); }); it('transformer should ignore shadow', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow', shadowBlur: 10, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.x(), 50); assert.equal(tr.y(), 50); assert.equal(tr.width(), 100); assert.equal(tr.height(), 100); tr._fitNodesInto({ x: 50, y: 50, width: 100, height: 100, rotation: 0, }); assert.equal(rect.x(), 50); assert.equal(rect.y(), 50); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); }); it.skip('transformer should skip scale on stroke if strokeScaleEnabled = false', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 10, height: 10, scaleX: 10, scaleY: 10, fill: 'yellow', strokeWidth: 10, stroke: 'red', strokeScaleEnabled: false, }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], ignoreStroke: true, }); layer.add(tr); layer.draw(); assert.equal(tr.x(), 50); assert.equal(tr.y(), 50); assert.equal(tr.width(), 100); assert.equal(tr.height(), 100); tr._fitNodesInto({ x: 50, y: 50, width: 100, height: 100, rotation: 0, }); assert.equal(rect.x(), 50); assert.equal(rect.y(), 50); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); }); it.skip('check calculations when the size = 0', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, // can we fit from empty width? width: 0, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], }); layer.add(tr); layer.draw(); tr._fitNodesInto({ x: 50, y: 50, width: 100, height: 100, rotation: 0, }); layer.draw(); assert.equal(rect.scaleX(), 1); }); it('attrs change - arc', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Arc({ x: stage.width() / 2, y: stage.height() / 2, innerRadius: 40, outerRadius: 70, angle: 60, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); layer.draw(); shape.outerRadius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); it('attrs change - line', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Arrow({ x: stage.width() / 4, y: stage.height() / 4, points: [0, 0, stage.width() / 2, stage.height() / 2], pointerLength: 20, pointerWidth: 20, fill: 'black', stroke: 'black', strokeWidth: 4, draggable: true, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); layer.draw(); shape.points([10, 10, 100, 10]); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; layer.draw(); assert.deepEqual(shape.getClientRect(), rect); shape.strokeWidth(10); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; layer.draw(); assert.deepEqual(shape.getClientRect(), rect); }); it('attrs change - circle', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Circle({ x: stage.width() / 2, y: stage.height() / 2, radius: 40, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); it('attrs change - ellipse', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Ellipse({ x: stage.width() / 2, y: stage.height() / 2, radiusX: 100, radiusY: 50, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.radiusX(120); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.radiusY(100); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); it('attrs change - rect', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Rect({ x: stage.width() / 2, y: stage.height() / 2, width: 100, height: 100, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.width(120); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.height(110); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); it('attrs change - path', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Path({ x: 50, y: 40, data: 'M12.582,9.551C3.251,16.237,0.921,29.021,7.08,38.564l-2.36,1.689l4.893,2.262l4.893,2.262l-0.568-5.36l-0.567-5.359l-2.365,1.694c-4.657-7.375-2.83-17.185,4.352-22.33c7.451-5.338,17.817-3.625,23.156,3.824c5.337,7.449,3.625,17.813-3.821,23.152l2.857,3.988c9.617-6.893,11.827-20.277,4.935-29.896C35.591,4.87,22.204,2.658,12.582,9.551z', fill: 'green', }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.data('M200,100h100v50z'); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); it('attrs change - regular polygon', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.RegularPolygon({ x: 100, y: 150, sides: 6, radius: 70, fill: 'red', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); it('attrs change - ring', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Ring({ x: stage.width() / 2, y: stage.height() / 2, innerRadius: 40, outerRadius: 70, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.outerRadius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.innerRadius(200); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); it('attrs change - star', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Star({ x: stage.width() / 2, y: stage.height() / 2, numPoints: 6, innerRadius: 40, outerRadius: 70, fill: 'yellow', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.outerRadius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.innerRadius(200); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); it('attrs change - wedge', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Wedge({ x: stage.width() / 2, y: stage.height() / 2, radius: 70, angle: 60, fill: 'red', stroke: 'black', strokeWidth: 4, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); it('attrs change - text', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Text({ x: stage.width() / 2, y: 15, text: 'Simple Text', fontSize: 60, fontFamily: 'Arial', fill: 'green', }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.text('Simple'); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change text'); shape.fontSize(30); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change font size'); shape.padding(10); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change padding'); shape.lineHeight(2); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change line height'); shape.width(30); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect), 'change width'; shape.height(30); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change height'); }); it('attrs change - text path', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.TextPath({ x: 0, y: 50, fill: '#333', fontSize: 16, fontFamily: 'Arial', text: "All the world's a stage, and all the men and women merely players.", data: 'M10,10 C0,0 10,150 100,100 S300,150 400,50', }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], }); layer.add(tr); shape.text('Simple'); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change text'); shape.fontSize(30); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change font size'); shape.data('M10,10 C0,0 10,150 100,100 S300,150 400,50'); layer.draw(); var rect = Konva.Util._assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect), 'change data'; }); it('make sure transformer events are not cloned', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: stage.width() / 5, y: stage.height() / 5, width: 50, height: 50, fill: 'green', draggable: true, }); layer.add(rect1); var tr1 = new Konva.Transformer({ nodes: [rect1], }); layer.add(tr1); var rect2 = rect1.clone({ fill: 'red', x: stage.width() / 3, y: stage.height() / 3, }); layer.add(rect2); tr1.destroy(); var tr2 = new Konva.Transformer({ nodes: [rect2], }); layer.add(tr2); // should not throw error rect2.width(100); assertAlmostEqual(tr2.width(), 100); stage.draw(); }); it('try to move anchor on scaled with css stage', function () { if (isNode) { return; } var stage = addStage(); stage.container().style.transform = 'scale(0.5)'; stage.container().style.transformOrigin = 'top left'; var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr = new Konva.Transformer({ nodes: [rect], keepRatio: false, }); layer.add(tr); layer.draw(); sm(stage, { x: 50, y: 50, }); simulateMouseDown(tr, { x: 50, y: 50, }); var target = stage.getIntersection({ x: 50, y: 50, }); simulateMouseMove(tr, { x: 100, y: 50, }); // here is duplicate, because transformer is listening window events simulateMouseUp(tr, { x: 100, y: 50, }); su(stage, { x: 100, y: 50, }); assertAlmostEqual(rect.width() * rect.scaleX(), 200); }); it('rotate several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); tr._fitNodesInto({ x: 100, y: 0, width: 100, height: 100, rotation: Konva.getAngle(90), }); layer.draw(); assertAlmostEqual(rect1.x(), 100); assertAlmostEqual(rect1.y(), 0); assertAlmostEqual(rect1.width() + rect2.width(), 100); assertAlmostEqual(rect1.height() + rect2.width(), 100); assertAlmostEqual(rect1.rotation(), 90); assertAlmostEqual(rect2.x(), 50); assertAlmostEqual(rect2.y(), 50); assertAlmostEqual(rect2.width() + rect2.width(), 100); assertAlmostEqual(rect2.height() + rect2.width(), 100); assertAlmostEqual(tr.rotation(), 90); tr._fitNodesInto({ x: 100, y: 100, width: 100, height: 100, rotation: Konva.getAngle(180), }); assertAlmostEqual(tr.x(), rect1.x()); assertAlmostEqual(tr.y(), rect1.y()); assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); assertAlmostEqual(tr.rotation(), 180); }); it('events on several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect2); var transformstart = 0; var transform = 0; var transformend = 0; rect1.on('transformstart', function () { transformstart += 1; }); rect1.on('transform', function () { transform += 1; }); rect1.on('transformend', function () { transformend += 1; }); rect2.on('transformstart', function () { transformstart += 1; }); rect2.on('transform', function () { transform += 1; }); rect2.on('transformend', function () { transformend += 1; }); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 100, y: 60, }); simulateMouseMove(tr, { x: 105, y: 60, }); simulateMouseUp(tr, { x: 105, y: 60, }); assert.equal(transformstart, 2); assert.equal(transform, 2); assert.equal(transformend, 2); }); it('transform several rotated nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'blue', rotation: 45, }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', rotation: 120, }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); tr._fitNodesInto({ x: 100, y: 0, width: 100, height: 100, rotation: Konva.getAngle(90), }); layer.draw(); assertAlmostEqual(rect1.x(), 100); assertAlmostEqual(rect1.y(), 41.421356237309496); assertAlmostEqual(rect1.width() + rect2.width(), 100); assertAlmostEqual(rect1.height() + rect2.width(), 100); assertAlmostEqual(rect1.rotation(), 132.45339125826706); assertAlmostEqual(rect2.x(), 46.41016151377549); assertAlmostEqual(rect2.y(), 100); assertAlmostEqual(rect2.width() + rect2.width(), 100); assertAlmostEqual(rect2.height() + rect2.width(), 100); assertAlmostEqual(tr.rotation(), 90); tr._fitNodesInto({ x: 100, y: 100, width: 100, height: 100, rotation: Konva.getAngle(180), }); assertAlmostEqual(tr.x(), 100); assertAlmostEqual(tr.y(), 100); }); it('drag several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var dragstart = 0; var dragmove = 0; var dragend = 0; rect2.on('dragstart', () => { dragstart += 1; }); rect2.on('dragmove', () => { dragmove += 1; }); rect2.on('dragend', () => { dragend += 1; }); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); // make sure drag also triggers on the transformer. tr.on('dragstart', (e) => { assert.equal(!!e.evt, true); dragstart += 1; }); tr.on('dragmove', () => { dragmove += 1; }); tr.on('dragend', () => { dragend += 1; }); // also drag should bubble to stage // two times for two rects stage.on('dragstart', (e) => { assert.equal(!!e.evt, true); dragstart += 1; }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 75, y: 75, }); sm(stage, { x: 80, y: 80, }); sm(stage, { x: 85, y: 85, }); su(stage, { x: 80, y: 80, }); // proxy drag to other nodes assert.equal(rect2.x(), 110); assert.equal(rect2.y(), 110); assert.equal(dragstart, 4, 'dragstart'); assert.equal(dragmove, 3, 'dragmove'); assert.equal(dragend, 2, 'dragend'); }); it('reattach from several and drag one', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); tr.nodes([rect1]); // now drag just the first simulateMouseDown(tr, { x: 125, y: 125, }); sm(stage, { x: 130, y: 130, }); su(stage, { x: 130, y: 130, }); // no changes on the second assert.equal(rect1.x(), 50); assert.equal(rect1.y(), 50); }); it('transformer should not hide shapes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var click = 0; rect1.on('click', () => { click += 1; }); var tr = new Konva.Transformer({ nodes: [rect1], }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 75, y: 75, }); sm(stage, { x: 75, y: 75, }); su(stage, { x: 75, y: 75, }); // proxy drag to other nodes assert.equal(click, 1); }); it('drag several nodes by transformer back', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var dragstart = 0; var dragmove = 0; var dragend = 0; rect1.on('dragstart', () => { dragstart += 1; }); rect1.on('dragmove', () => { dragmove += 1; }); rect1.on('dragend', () => { dragend += 1; }); rect2.on('dragstart', () => { dragstart += 1; }); rect2.on('dragmove', () => { dragmove += 1; }); rect2.on('dragend', () => { dragend += 1; }); var tr = new Konva.Transformer({ nodes: [rect1, rect2], shouldOverdrawWholeArea: true, }); tr.on('dragstart', () => { dragstart += 1; }); tr.on('dragmove', () => { dragmove += 1; }); tr.on('dragend', () => { dragend += 1; }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: 110, y: 90, }); // move mouse twice // because first move will jus trigger start dragging sm(stage, { x: 120, y: 90, }); sm(stage, { x: 120, y: 90, }); su(stage, { x: 120, y: 90, }); // proxy drag to other nodes assert.equal(rect1.x(), 60); assert.equal(rect1.y(), 50); assert.equal(rect2.x(), 110); assert.equal(rect2.y(), 100); assert.equal(dragstart, 3, 'dragstart'); assert.equal(dragmove, 3, 'dragmove'); assert.equal(dragend, 3, 'dragend'); }); it('reattach to several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 100, y: 100, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); tr._fitNodesInto({ x: 100, y: 0, width: 100, height: 100, rotation: Konva.getAngle(90), }); assertAlmostEqual(tr.x(), rect1.x()); assertAlmostEqual(tr.y(), rect1.y()); assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); assertAlmostEqual(tr.rotation(), 90); layer.draw(); tr.nodes([rect1, rect2]); assertAlmostEqual(tr.x(), 0); assertAlmostEqual(tr.y(), 0); assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); assertAlmostEqual(tr.height(), rect1.height() + rect2.width()); assertAlmostEqual(tr.rotation(), 0); }); it('rotate several nodes inside different parents', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var group = new Konva.Group({ x: 50, scaleX: 2, }); layer.add(group); var rect2 = new Konva.Rect({ x: 0, y: 50, draggable: true, width: 25, height: 50, fill: 'red', }); group.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); layer.draw(); assert.equal(tr.x(), 0); assert.equal(tr.y(), 0); assert.equal(tr.width(), 100); assert.equal(tr.height(), 100); assert.equal(tr.rotation(), 0); // fit into the same area const box = { x: 0, y: 0, width: 100, height: 100, rotation: 0, }; tr._fitNodesInto(box); var newBox = tr._getNodeRect(); assertAlmostEqual(box.x, newBox.x); assertAlmostEqual(box.y, newBox.y); assertAlmostEqual(box.width, newBox.width); assertAlmostEqual(box.height, newBox.height); assertAlmostEqual(box.rotation, newBox.rotation); assertAlmostEqual(rect1.x(), 0); assertAlmostEqual(rect1.y(), 0); assertAlmostEqual(rect1.width(), 50); assertAlmostEqual(rect1.height(), 50); assertAlmostEqual(rect1.rotation(), 0); assertAlmostEqual(rect2.x(), 0); assertAlmostEqual(rect2.y(), 50); assertAlmostEqual(rect2.width(), 25); assertAlmostEqual(rect2.height(), 50); assertAlmostEqual(rect2.rotation(), 0); }); it('can attach transformer into several nodes and fit into negative scale', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect1 = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var tr = new Konva.Transformer({ nodes: [rect1, rect2], }); layer.add(tr); tr._fitNodesInto({ x: 100, y: 0, width: 0, height: 100, rotation: 0, }); tr._fitNodesInto({ x: 100, y: 0, width: -100, height: 100, rotation: 0, }); layer.draw(); assertAlmostEqual(Math.round(tr.x()), 0); assertAlmostEqual(Math.round(tr.y()), 0); assertAlmostEqual(tr.width(), rect1.width() + rect2.width()); assertAlmostEqual(tr.height(), rect1.height() + rect2.height()); assertAlmostEqual(tr.rotation(), 0); }); it('boundBoxFox should work in absolute coordinates', function () { var stage = addStage(); var layer = new Konva.Layer({ x: 10, y: 10, scaleX: 2, scaleY: 2, }); stage.add(layer); var rect1 = new Konva.Rect({ x: 0, y: 0, draggable: true, width: 50, height: 50, fill: 'yellow', }); layer.add(rect1); var rect2 = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 50, height: 50, fill: 'red', }); layer.add(rect2); var callCount = 0; var tr = new Konva.Transformer({ nodes: [rect1, rect2], boundBoxFunc: function (oldBox, newBox) { callCount += 1; assert.deepEqual(oldBox, { x: 10, y: 10, width: 200, height: 200, rotation: 0, }); assert.deepEqual(newBox, { x: 10, y: 10, width: 300, height: 200, rotation: 0, }); return newBox; }, }); layer.add(tr); tr._fitNodesInto({ x: 10, y: 10, width: 300, height: 200, rotation: 0, }); assert.equal(callCount, 1); }); // TODO: move to manual tests it.skip('performance check - drag several nodes', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); for (var i = 0; i < 500; i++) { var shape = new Konva.Circle({ x: 100, y: 100, radius: 50, fill: 'red', draggable: true, }); layer.add(shape); } var shapes = layer.find('Circle'); var tr = new Konva.Transformer({ nodes: shapes, }); layer.add(tr); layer.draw(); throw 1; }); // we don't support height = 0 it.skip('try to transform zero size shape', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Line({ x: stage.width() / 4, y: stage.height() / 4, points: [0, 0, 200, 0], fill: 'black', stroke: 'black', strokeWidth: 4, draggable: true, }); layer.add(shape); var tr = new Konva.Transformer({ nodes: [shape], enabledAnchors: ['middle-left', 'middle-right'], ignoreStroke: true, }); layer.add(tr); layer.draw(); simulateMouseDown(tr, { x: stage.width() / 2, y: stage.height() / 2, }); simulateMouseDown(tr, { x: stage.width() / 2 + 100, y: stage.height() / 2, }); simulateMouseUp(tr); assert.equal(shape.scaleX(), 0.5); }); it('check transform cache', function () { var stage = addStage({ scaleX: 0.5, scaleY: 0.5 }); var layer = new Konva.Layer(); stage.add(layer); var textNode = new Konva.Text({ text: 'Some text here', x: 300, y: 100, fontSize: 20, draggable: true, width: 200, }); var tr = new Konva.Transformer({ nodes: [textNode], enabledAnchors: [ 'top-left', 'top-right', 'bottom-left', 'bottom-right', 'middle-left', 'middle-right', ], boundBoxFunc: function (oldBox, newBox) { if (newBox.width < 5 || newBox.height < 5 || newBox.width > 1000) { return oldBox; } return newBox; }, }); layer.add(tr); layer.add(textNode); assert.equal(textNode.getClientRect().width, 100); }); // ====================================================== it('init transformer on simple rectangle', function () { var stage = addStage(); stage.rotation(45); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', rotation: 45, }); layer.add(rect); var tr = new Konva.Transformer({ useSingleNodeRotation: false, nodes: [rect], }); layer.add(tr); layer.draw(); assert.equal(tr.getClassName(), 'Transformer'); assert.equal(tr.rotation(), 0); }); it('use several transformers on a single node', function () { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 100, y: 60, draggable: true, width: 100, height: 100, fill: 'yellow', }); layer.add(rect); var tr1 = new Konva.Transformer({ nodes: [rect], }); layer.add(tr1); var tr2 = new Konva.Transformer({ nodes: [rect], }); layer.add(tr2); // detach tr1 tr1.nodes([]); // update rect rect.setAttrs({ x: 0, y: 0, width: 50, height: 50 }); // it should update second transformer assert.equal(tr2.x(), rect.x()); assert.equal(tr2.y(), rect.y()); assert.equal(tr2.width(), rect.width()); assert.equal(tr2.height(), rect.height()); }); });