Fix Konva.Transformer behavior on mirrored nodes. close #732

This commit is contained in:
Anton Lavrenov
2019-09-06 14:15:07 -05:00
parent be3f7e8059
commit 456bd9ec91
6 changed files with 185 additions and 92 deletions

View File

@@ -5,6 +5,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## Not released:
* Fix `Konva.Transformer` behavior on mirrored nodes
* Fix `stage.getPointerPosition()` logic.
## 4.0.8 - 2019-09-05

101
konva.js
View File

@@ -13546,7 +13546,7 @@
this.add(back);
};
Transformer.prototype._handleMouseDown = function (e) {
this.movingResizer = e.target.name().split(' ')[0];
this._movingAnchorName = e.target.name().split(' ')[0];
// var node = this.getNode();
var attrs = this._getNodeRect();
var width = attrs.width;
@@ -13564,8 +13564,8 @@
};
Transformer.prototype._handleMouseMove = function (e) {
var x, y, newHypotenuse;
var resizerNode = this.findOne('.' + this.movingResizer);
var stage = resizerNode.getStage();
var anchorNode = this.findOne('.' + this._movingAnchorName);
var stage = anchorNode.getStage();
var box = stage.getContent().getBoundingClientRect();
var zeroPoint = {
x: box.left,
@@ -13579,84 +13579,96 @@
x: pointerPos.left - zeroPoint.x,
y: pointerPos.top - zeroPoint.y
};
resizerNode.setAbsolutePosition(newAbsPos);
anchorNode.setAbsolutePosition(newAbsPos);
var keepProportion = this.keepRatio() || e.shiftKey;
// console.log(keepProportion);
if (this.movingResizer === 'top-left') {
if (this._movingAnchorName === 'top-left') {
if (keepProportion) {
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-right').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.bottom-right').y() - resizerNode.y(), 2));
var reverse = this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-right').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.bottom-right').y() - anchorNode.y(), 2));
var reverseX = this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY = this.findOne('.top-left').y() > this.findOne('.bottom-right').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-left').x(this.findOne('.bottom-right').x() - x);
this.findOne('.top-left').y(this.findOne('.bottom-right').y() - y);
}
}
else if (this.movingResizer === 'top-center') {
this.findOne('.top-left').y(resizerNode.y());
else if (this._movingAnchorName === 'top-center') {
this.findOne('.top-left').y(anchorNode.y());
}
else if (this.movingResizer === 'top-right') {
else if (this._movingAnchorName === 'top-right') {
if (keepProportion) {
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-left').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.bottom-left').y() - resizerNode.y(), 2));
var reverse = this.findOne('.top-right').x() < this.findOne('.top-left').x()
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-left').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.bottom-left').y() - anchorNode.y(), 2));
var reverseX = this.findOne('.top-right').x() < this.findOne('.top-left').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY = this.findOne('.top-right').y() > this.findOne('.bottom-left').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-right').x(x);
this.findOne('.top-right').y(this.findOne('.bottom-left').y() - y);
}
var pos = resizerNode.position();
var pos = anchorNode.position();
this.findOne('.top-left').y(pos.y);
this.findOne('.bottom-right').x(pos.x);
}
else if (this.movingResizer === 'middle-left') {
this.findOne('.top-left').x(resizerNode.x());
else if (this._movingAnchorName === 'middle-left') {
this.findOne('.top-left').x(anchorNode.x());
}
else if (this.movingResizer === 'middle-right') {
this.findOne('.bottom-right').x(resizerNode.x());
else if (this._movingAnchorName === 'middle-right') {
this.findOne('.bottom-right').x(anchorNode.x());
}
else if (this.movingResizer === 'bottom-left') {
else if (this._movingAnchorName === 'bottom-left') {
if (keepProportion) {
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.top-right').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.top-right').y() - resizerNode.y(), 2));
var reverse = this.findOne('.top-right').x() < this.findOne('.bottom-left').x()
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.top-right').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.top-right').y() - anchorNode.y(), 2));
var reverseX = this.findOne('.top-right').x() < this.findOne('.bottom-left').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY = this.findOne('.bottom-right').y() < this.findOne('.top-left').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.bottom-left').x(this.findOne('.top-right').x() - x);
this.findOne('.bottom-left').y(y);
}
pos = resizerNode.position();
pos = anchorNode.position();
this.findOne('.top-left').x(pos.x);
this.findOne('.bottom-right').y(pos.y);
}
else if (this.movingResizer === 'bottom-center') {
this.findOne('.bottom-right').y(resizerNode.y());
else if (this._movingAnchorName === 'bottom-center') {
this.findOne('.bottom-right').y(anchorNode.y());
}
else if (this.movingResizer === 'bottom-right') {
else if (this._movingAnchorName === 'bottom-right') {
if (keepProportion) {
newHypotenuse = Math.sqrt(Math.pow(this.findOne('.bottom-right').x(), 2) +
Math.pow(this.findOne('.bottom-right').y(), 2));
var reverse = this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
var reverseX = this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY = this.findOne('.top-left').y() > this.findOne('.bottom-right').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.bottom-right').x(x);
this.findOne('.bottom-right').y(y);
}
}
else if (this.movingResizer === 'rotater') {
else if (this._movingAnchorName === 'rotater') {
var padding = this.padding();
var attrs = this._getNodeRect();
x = resizerNode.x() - attrs.width / 2;
y = -resizerNode.y() + attrs.height / 2;
x = anchorNode.x() - attrs.width / 2;
y = -anchorNode.y() + attrs.height / 2;
var dAlpha = Math.atan2(-y, x) + Math.PI / 2;
if (attrs.height < 0) {
dAlpha -= Math.PI;
@@ -13696,9 +13708,10 @@
}, e);
}
else {
console.error(new Error('Wrong position argument of selection resizer: ' + this.movingResizer));
console.error(new Error('Wrong position argument of selection resizer: ' +
this._movingAnchorName));
}
if (this.movingResizer === 'rotater') {
if (this._movingAnchorName === 'rotater') {
return;
}
var absPos = this.findOne('.top-left').getAbsolutePosition(this.getParent());
@@ -13906,9 +13919,9 @@
Transformer.prototype.stopTransform = function () {
if (this._transforming) {
this._removeEvents();
var resizerNode = this.findOne('.' + this.movingResizer);
if (resizerNode) {
resizerNode.stopDrag();
var anchorNode = this.findOne('.' + this._movingAnchorName);
if (anchorNode) {
anchorNode.stopDrag();
}
}
};

4
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@@ -180,7 +180,7 @@ var MAX_SAFE_INTEGER = 100000000;
export class Transformer extends Group {
_node: Node;
movingResizer: string;
_movingAnchorName: string;
_transforming = false;
sin: number;
cos: number;
@@ -405,7 +405,7 @@ export class Transformer extends Group {
this.add(back);
}
_handleMouseDown(e) {
this.movingResizer = e.target.name().split(' ')[0];
this._movingAnchorName = e.target.name().split(' ')[0];
// var node = this.getNode();
var attrs = this._getNodeRect();
@@ -427,8 +427,8 @@ export class Transformer extends Group {
}
_handleMouseMove(e) {
var x, y, newHypotenuse;
var resizerNode = this.findOne('.' + this.movingResizer);
var stage = resizerNode.getStage();
var anchorNode = this.findOne('.' + this._movingAnchorName);
var stage = anchorNode.getStage();
var box = stage.getContent().getBoundingClientRect();
var zeroPoint = {
@@ -444,106 +444,126 @@ export class Transformer extends Group {
y: pointerPos.top - zeroPoint.y
};
resizerNode.setAbsolutePosition(newAbsPos);
anchorNode.setAbsolutePosition(newAbsPos);
var keepProportion = this.keepRatio() || e.shiftKey;
// console.log(keepProportion);
if (this.movingResizer === 'top-left') {
if (this._movingAnchorName === 'top-left') {
if (keepProportion) {
newHypotenuse = Math.sqrt(
Math.pow(this.findOne('.bottom-right').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.bottom-right').y() - resizerNode.y(), 2)
Math.pow(this.findOne('.bottom-right').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.bottom-right').y() - anchorNode.y(), 2)
);
var reverse =
var reverseX =
this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY =
this.findOne('.top-left').y() > this.findOne('.bottom-right').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-left').x(this.findOne('.bottom-right').x() - x);
this.findOne('.top-left').y(this.findOne('.bottom-right').y() - y);
}
} else if (this.movingResizer === 'top-center') {
this.findOne('.top-left').y(resizerNode.y());
} else if (this.movingResizer === 'top-right') {
} else if (this._movingAnchorName === 'top-center') {
this.findOne('.top-left').y(anchorNode.y());
} else if (this._movingAnchorName === 'top-right') {
if (keepProportion) {
newHypotenuse = Math.sqrt(
Math.pow(this.findOne('.bottom-left').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.bottom-left').y() - resizerNode.y(), 2)
Math.pow(this.findOne('.bottom-left').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.bottom-left').y() - anchorNode.y(), 2)
);
var reverse =
var reverseX =
this.findOne('.top-right').x() < this.findOne('.top-left').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY =
this.findOne('.top-right').y() > this.findOne('.bottom-left').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.top-right').x(x);
this.findOne('.top-right').y(this.findOne('.bottom-left').y() - y);
}
var pos = resizerNode.position();
var pos = anchorNode.position();
this.findOne('.top-left').y(pos.y);
this.findOne('.bottom-right').x(pos.x);
} else if (this.movingResizer === 'middle-left') {
this.findOne('.top-left').x(resizerNode.x());
} else if (this.movingResizer === 'middle-right') {
this.findOne('.bottom-right').x(resizerNode.x());
} else if (this.movingResizer === 'bottom-left') {
} else if (this._movingAnchorName === 'middle-left') {
this.findOne('.top-left').x(anchorNode.x());
} else if (this._movingAnchorName === 'middle-right') {
this.findOne('.bottom-right').x(anchorNode.x());
} else if (this._movingAnchorName === 'bottom-left') {
if (keepProportion) {
newHypotenuse = Math.sqrt(
Math.pow(this.findOne('.top-right').x() - resizerNode.x(), 2) +
Math.pow(this.findOne('.top-right').y() - resizerNode.y(), 2)
Math.pow(this.findOne('.top-right').x() - anchorNode.x(), 2) +
Math.pow(this.findOne('.top-right').y() - anchorNode.y(), 2)
);
var reverse =
var reverseX =
this.findOne('.top-right').x() < this.findOne('.bottom-left').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY =
this.findOne('.bottom-right').y() < this.findOne('.top-left').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.bottom-left').x(this.findOne('.top-right').x() - x);
this.findOne('.bottom-left').y(y);
}
pos = resizerNode.position();
pos = anchorNode.position();
this.findOne('.top-left').x(pos.x);
this.findOne('.bottom-right').y(pos.y);
} else if (this.movingResizer === 'bottom-center') {
this.findOne('.bottom-right').y(resizerNode.y());
} else if (this.movingResizer === 'bottom-right') {
} else if (this._movingAnchorName === 'bottom-center') {
this.findOne('.bottom-right').y(anchorNode.y());
} else if (this._movingAnchorName === 'bottom-right') {
if (keepProportion) {
newHypotenuse = Math.sqrt(
Math.pow(this.findOne('.bottom-right').x(), 2) +
Math.pow(this.findOne('.bottom-right').y(), 2)
);
var reverse =
var reverseX =
this.findOne('.top-left').x() > this.findOne('.bottom-right').x()
? -1
: 1;
x = newHypotenuse * this.cos * reverse;
y = newHypotenuse * this.sin * reverse;
var reverseY =
this.findOne('.top-left').y() > this.findOne('.bottom-right').y()
? -1
: 1;
x = newHypotenuse * this.cos * reverseX;
y = newHypotenuse * this.sin * reverseY;
this.findOne('.bottom-right').x(x);
this.findOne('.bottom-right').y(y);
}
} else if (this.movingResizer === 'rotater') {
} else if (this._movingAnchorName === 'rotater') {
var padding = this.padding();
var attrs = this._getNodeRect();
x = resizerNode.x() - attrs.width / 2;
y = -resizerNode.y() + attrs.height / 2;
x = anchorNode.x() - attrs.width / 2;
y = -anchorNode.y() + attrs.height / 2;
var dAlpha = Math.atan2(-y, x) + Math.PI / 2;
@@ -599,12 +619,13 @@ export class Transformer extends Group {
} else {
console.error(
new Error(
'Wrong position argument of selection resizer: ' + this.movingResizer
'Wrong position argument of selection resizer: ' +
this._movingAnchorName
)
);
}
if (this.movingResizer === 'rotater') {
if (this._movingAnchorName === 'rotater') {
return;
}
@@ -839,9 +860,9 @@ export class Transformer extends Group {
stopTransform() {
if (this._transforming) {
this._removeEvents();
var resizerNode = this.findOne('.' + this.movingResizer);
if (resizerNode) {
resizerNode.stopDrag();
var anchorNode = this.findOne('.' + this._movingAnchorName);
if (anchorNode) {
anchorNode.stopDrag();
}
}
}

View File

@@ -624,7 +624,7 @@ suite('TouchEvents', function() {
assert.equal(dbltap, 0, 'no dbltap triggered');
});
test.only('tap should give pointer position', function() {
test('tap should give pointer position', function() {
var stage = addStage();
var layer = new Konva.Layer();
stage.add(layer);

View File

@@ -1814,6 +1814,64 @@ suite('Transformer', function() {
});
});
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,
scaleY: -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 < 0.1, true, ' width check');
assert.equal(
rect.height() * rect.scaleY() - 50 < 0.1,
true,
' height check'
);
});
test('transformer should ignore shadow', function() {
var stage = addStage();
var layer = new Konva.Layer();