suite('Transformer', function() { // ====================================================== test('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({ node: 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()); }); test('try it on a parent of parent', function() { var callCount = 0; var oldWarn = Konva.Util.warn; Konva.Util.warn = function() { callCount += 1; }; var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var group = new Konva.Group({ x: 50, y: 50 }); layer.add(group); var rect = new Konva.Rect({ x: 50, y: 50, draggable: true, width: 100, height: 100, fill: 'yellow' }); group.add(rect); var tr = new Konva.Transformer({ node: rect }); layer.add(tr); rect.width(120); layer.draw(); assert.equal(callCount, 1); Konva.Util.warn = oldWarn; // assert.equal(tr.x(), rect.x() + group.x()); // assert.equal(tr.y(), rect.y() + group.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()); }); test('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.Rect({ x: 10, y: 60, radius: 100, fill: 'yellow' }); layer.add(circle); var tr = new Konva.Transformer({ node: rect }); layer.add(tr); layer.draw(); assert.equal(tr.node(), rect); tr.attachTo(circle); assert.equal(tr.node(), circle); }); test('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.attachTo(rect); layer.draw(); tr._fitNodeInto({ x: 120, y: 60, width: 50, height: 50, rotation: 45 }); assert.equal(tr.x(), rect.x()); assert.equal(tr.y(), rect.y()); assert.equal(tr.width(), 50); assert.equal(tr.height(), 50); assert.equal(tr.rotation(), rect.rotation()); }); test('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.attachTo(rect); layer.draw(); tr._fitNodeInto({ x: 20, y: 20, width: 200, height: 200 }); assert.equal(rect.x(), 20); assert.equal(rect.y(), 20); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); assert.equal(rect.scaleX(), 2); }); test('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.attachTo(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()); }); test('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.attachTo(rect); 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() * rect.scaleX()); assert.equal(tr.height(), rect.height() * rect.scaleY()); assert.equal(tr.rotation(), rect.rotation()); }); test('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.attachTo(rect); layer.draw(); tr._fitNodeInto({ 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()); }); test('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.attachTo(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()); }); test('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.attachTo(rect); tr._fitNodeInto({ x: 0, y: 0, width: 200, height: 100 }); layer.draw(); assert.equal(rect.x(), 100); assert.equal(rect.y(), 50); assert.equal(rect.width() * rect.scaleX(), 200); assert.equal(rect.height() * rect.scaleY(), 100); assert.equal(rect.rotation(), rect.rotation()); assert.equal(tr.x(), 0); assert.equal(tr.y(), 0); assert.equal(tr.width(), 200); assert.equal(tr.height(), 100); assert.equal(rect.rotation(), rect.rotation()); }); test('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.attachTo(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()); }); test('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.attachTo(circle); tr._fitNodeInto({ x: 40, y: 40, width: 160, height: 80 }); 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); }); test('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.attachTo(circle); tr._fitNodeInto({ x: 80, y: 0, width: 80, height: 80, rotation: 90 }); layer.draw(); assert.equal(circle.x(), 40); assert.equal(circle.y(), 40); assert.equal(circle.width() * circle.scaleX(), 80); assert.equal(circle.height() * circle.scaleY(), 80); assert.equal(circle.rotation(), 90); assert.equal(tr.x(), 80); assert.equal(tr.y(), 0); assert.equal(tr.width(), 80); assert.equal(tr.height(), 80); }); test('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.attachTo(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); }); test('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.attachTo(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()); }); test('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.attachTo(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); }); test('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.attachTo(group); tr._fitNodeInto({ x: 100, y: 0, width: 100, height: 100, rotation: 90 }); layer.draw(); var rect = group.getClientRect(); assert.equal(group.x(), 50); assert.equal(group.y(), 50); assert.equal(rect.width, 100); assert.equal(rect.height, 100); assert.equal(group.rotation(), 90); assert.equal(tr.x(), 100); assert.equal(tr.y(), 0); assert.equal(tr.width(), 100); assert.equal(tr.height(), 100); }); test('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.attachTo(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); }); test('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.attachTo(group); tr._fitNodeInto({ x: 0, y: 0, width: 200, height: 100 }); layer.draw(); var rect = group.getClientRect(); assert.equal(group.x(), 100); assert.equal(group.y(), 50); assert.equal(rect.width, 200); assert.equal(rect.height, 100); assert.equal(tr.x(), 0); assert.equal(tr.y(), 0); assert.equal(tr.width(), 200); assert.equal(tr.height(), 100); }); test('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.attachTo(rect); layer.draw(); var json = tr.toJSON(); var object = JSON.parse(json); assert.equal(object.attrs.node, undefined); assert.equal(object.children, undefined); }); test('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(); }); test('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.attachTo(rect); assert.equal(tr.getWidth(), 100); }); test('can destroy without attached node', function() { var tr = new Konva.Transformer(); tr.destroy(); }); test('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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 100, y: 60 }); assert.equal(tr.isTransforming(), true); tr.destroy(); assert.equal(tr.isTransforming(), false); assert.equal(tr.getNode(), undefined); stage.simulateMouseUp({ x: 100, y: 60 }); }); test('can add padding', 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({ node: rect, padding: 10 }); layer.add(tr); tr._fitNodeInto({ x: 0, y: 0, width: 120, height: 120 }); layer.draw(); assert.equal(rect.x(), 10); assert.equal(rect.y(), 10); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); }); test.skip('test padding + keep ratio', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); const rect = new Konva.Rect({ x: 50, y: 50, width: 180, height: 50, fill: 'red', draggable: true }); layer.add(rect); var tr = new Konva.Transformer({ node: rect, padding: 40, keepRatio: true }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 250, y: 150 }); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: tr.findOne('.bottom-right'), clientX: 200, clientY: 150 + top }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: 200, clientY: 150 + top }); stage.simulateMouseUp({ x: 200, y: 150 }); layer.draw(); assert.equal(rect.x(), 50); assert.equal(rect.y(), 50); assert.equal(rect.width(), 100); assert.equal(rect.height(), 50); assert.equal(rect.scaleX(), 1); assert.equal(rect.scaleY(), 1); }); test('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({ node: rect }); layer.add(tr); layer.draw(); var anchor = tr.findOne('.top-right'); var pos = anchor.getAbsolutePosition(); stage.simulateMouseDown({ x: pos.x, y: pos.y }); var box = stage.content.getBoundingClientRect(); // debugger; tr._handleMouseMove({ target: anchor, clientX: box.left + pos.x - 100, clientY: box.top + pos.y + 100 }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: box.left + pos.x - 100, clientY: box.top + pos.y + 100 }); stage.simulateMouseUp({ x: pos.x - 100, y: pos.y + 100 }); assert.equal(rect.scaleX(), -1); assert.equal(rect.scaleY(), -1); }); test('can add padding with rotation', 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({ node: rect, padding: 10 }); layer.add(tr); tr._fitNodeInto({ x: 120, y: 0, width: 120, height: 120, rotation: 90 }); layer.draw(); assert.equal(rect.x(), 110); assert.equal(rect.y(), 10); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); assert.equal(rect.rotation(), 90); }); test('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({ node: 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(); }); test('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({ node: 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'); }); test('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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 20, y: 20 }); stage.simulateMouseMove({ x: 30, y: 30 }); assert.equal(rect.x(), 10); assert.equal(rect.y(), 10); assert.equal(tr.x(), 10); assert.equal(tr.y(), 10); stage.simulateMouseUp({ x: 30, y: 30 }); }); test('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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 20, y: 20 }); stage.simulateMouseMove({ x: 30, y: 30 }); 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); stage.simulateMouseUp({ x: 30, y: 30 }); }); test('on negative scaleY should move rotater', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var rect = new Konva.Rect({ x: 50, y: 160, draggable: true, width: 100, height: 100, fill: 'yellow', scaleY: -1 }); layer.add(rect); var tr = new Konva.Transformer({ node: rect }); layer.add(tr); layer.draw(); var rotater = tr.findOne('.rotater'); var pos = rotater.getAbsolutePosition(); assert.equal(pos.x, 100); assert.equal(pos.y, 210); }); test('try rotated scaled rect', function() { 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({ node: rect }); layer.add(tr); layer.draw(); var rotater = tr.findOne('.rotater'); var pos = rotater.getAbsolutePosition(); stage.simulateMouseDown({ x: pos.x, y: pos.y }); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: rotater, clientX: pos.x + 100, clientY: pos.y - 100 + top }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: pos.x + 100, clientY: pos.y - 50 + top }); stage.simulateMouseUp({ x: 100, y: 100 }); assert.equal(rect.rotation(), -90); }); test('check correct cursor on scaled shape', function() { 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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseMove({ x: 50, y: 1 }); assert.equal(stage.content.style.cursor, 'nwse-resize'); }); test('check correct cursor off on Transformer destroy', 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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseMove({ x: 100, y: 100 }); stage.simulateMouseDown({ x: 100, y: 100 }); assert.equal(stage.content.style.cursor, 'nwse-resize'); var target = stage.getIntersection({ x: 100, y: 100 }); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: target, clientX: 120, clientY: 100 + top }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: 120, clientY: 100 + top }); stage.simulateMouseUp({ x: 120, y: 100 }); tr.destroy(); stage.simulateMouseMove({ x: 140, y: 100 }); assert.equal(stage.content.style.cursor, ''); }); test('check correct cursor on scaled parent', function() { 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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseMove({ x: 50, y: 1 }); assert.equal(stage.content.style.cursor, 'nwse-resize'); }); test('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({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 50, y: 50 }); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: tr.findOne('.top-left'), clientX: 60, clientY: 60 + top }); 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 stage.simulateMouseUp({ x: 100, y: 100 }); }); test('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.attachTo(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._fitNodeInto({ // 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()); }); test('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.attachTo(rect); layer.draw(); var shape = layer.getIntersection({ x: 20, y: 20 }); assert.equal(shape.name(), 'top-left _anchor'); }); test('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({ node: 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 } ]; test('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({ node: rect }); layer.add(tr); tests.forEach(test => { rect.setAttrs({ x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1 }); tr.update(); layer.draw(); stage.simulateMouseDown(test.startPos); var target = stage.getIntersection(test.startPos); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: target, clientX: test.endPos.x, clientY: test.endPos.y + top, altKey: true }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: test.endPos.x, clientY: test.endPos.y + top }); stage.simulateMouseUp({ x: test.endPos.x, y: test.endPos.y }); layer.draw(); assert.equal( rect.width() * rect.scaleX(), test.expectedWidth, test.name + ' width check' ); assert.equal( rect.height() * rect.scaleY(), test.expectedHeight, test.name + ' height check' ); }); }); test('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({ node: rect, centeredScaling: true }); layer.add(tr); tests.forEach(test => { rect.setAttrs({ x: 0, y: 0, width: 100, height: 100, scaleX: 1, scaleY: 1 }); tr.update(); layer.draw(); stage.simulateMouseDown(test.startPos); var target = stage.getIntersection(test.startPos); var top = stage.content.getBoundingClientRect().top; tr._handleMouseMove({ target: target, clientX: test.endPos.x, clientY: test.endPos.y + top }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: test.endPos.x, clientY: test.endPos.y + top }); stage.simulateMouseUp({ x: test.endPos.x, y: test.endPos.y }); layer.draw(); assert.equal( rect.width() * rect.scaleX(), test.expectedWidth, test.name + ' width check' ); assert.equal( rect.height() * rect.scaleY(), test.expectedHeight, test.name + ' height check' ); }); }); test('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, fill: 'yellow', x: 150, y: 50, width: 100, height: 100, scaleX: -1 }); layer.add(rect); var tr = new Konva.Transformer({ node: rect }); layer.add(tr); layer.draw(); stage.simulateMouseDown({ x: 150, y: 150 }); var target = stage.getIntersection({ x: 150, y: 150 }); var top = Math.round(stage.content.getBoundingClientRect().top); tr._handleMouseMove({ target: target, clientX: 100, clientY: 100 + top }); // here is duplicate, because transformer is listening window events tr._handleMouseUp({ clientX: 100, clientY: 100 + top }); stage.simulateMouseUp({ 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'); }); test('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({ node: 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._fitNodeInto({ x: 50, y: 50, width: 100, height: 100 }); assert.equal(rect.x(), 50); assert.equal(rect.y(), 50); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); }); test.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({ node: 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._fitNodeInto({ x: 50, y: 50, width: 100, height: 100 }); assert.equal(rect.x(), 50); assert.equal(rect.y(), 50); assert.equal(rect.width(), 100); assert.equal(rect.height(), 100); }); test('attrs change - arc', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Arc({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, innerRadius: 40, outerRadius: 70, angle: 60, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.outerRadius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.innerRadius(200); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); test('attrs change - line', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Arrow({ x: stage.getWidth() / 4, y: stage.getHeight() / 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({ node: shape }); layer.add(tr); layer.draw(); shape.points([10, 10, 100, 10]); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; layer.draw(); assert.deepEqual(shape.getClientRect(), rect); shape.strokeWidth(10); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; layer.draw(); assert.deepEqual(shape.getClientRect(), rect); }); test('attrs change - circle', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Circle({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, radius: 40, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); test('attrs change - ellipse', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Ellipse({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, radius: { x: 100, y: 50 }, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.radiusX(120); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.radiusY(100); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); test('attrs change - rect', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Rect({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, width: 100, height: 100, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.width(120); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.height(110); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); test('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({ node: shape }); layer.add(tr); shape.data('M200,100h100v50z'); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); test('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({ node: shape }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); test('attrs change - ring', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Ring({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, innerRadius: 40, outerRadius: 70, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.outerRadius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.innerRadius(200); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); test('attrs change - star', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Star({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, numPoints: 6, innerRadius: 40, outerRadius: 70, fill: 'yellow', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.outerRadius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); shape.innerRadius(200); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); layer.draw(); }); test('attrs change - wedge', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Wedge({ x: stage.getWidth() / 2, y: stage.getHeight() / 2, radius: 70, angle: 60, fill: 'red', stroke: 'black', strokeWidth: 4 }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.radius(100); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect); }); test('attrs change - text', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); var shape = new Konva.Text({ x: stage.getWidth() / 2, y: 15, text: 'Simple Text', fontSize: 60, fontFamily: 'Calibri', fill: 'green' }); layer.add(shape); var tr = new Konva.Transformer({ node: shape }); layer.add(tr); shape.text('Simple'); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change text'); shape.fontSize(30); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change font size'); shape.padding(10); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change padding'); shape.lineHeight(2); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change line height'); shape.width(30); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect), 'change width'; shape.height(30); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change height'); }); test('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({ node: shape }); layer.add(tr); shape.text('Simple'); layer.draw(); var rect = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect, 'change text'); shape.fontSize(30); layer.draw(); var rect = Object.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 = Object.assign({}, tr._getNodeRect()); delete rect.rotation; assert.deepEqual(shape.getClientRect(), rect), 'change data'; }); test('make sure transformer events are not cloned', function() { var stage = addStage(); var layer = new Konva.Layer(); stage.add(layer); const rect1 = new Konva.Rect({ x: stage.width() / 5, y: stage.height() / 5, width: 50, height: 50, fill: 'green', draggable: true }); layer.add(rect1); const tr1 = new Konva.Transformer({ node: rect1 }); layer.add(tr1); const rect2 = rect1.clone({ fill: 'red', x: stage.width() / 3, y: stage.height() / 3 }); layer.add(rect2); tr1.destroy(); let tr2 = new Konva.Transformer({ node: rect2 }); layer.add(tr2); // should not throw error rect2.width(100); stage.draw(); }); });