more Transformer fixes

This commit is contained in:
Anton Lavrenov 2018-03-21 15:21:55 +07:00
parent 1930ffc9d7
commit 248f57cd3f
6 changed files with 259 additions and 133 deletions

143
konva.js
View File

@ -743,6 +743,16 @@
firstChar === firstChar.toUpperCase()
);
},
_sign: function(number) {
if (number === 0) {
return 0;
}
if (number > 0) {
return 1;
} else {
return -1;
}
},
createCanvasElement: function() {
var canvas = Konva.isBrowser
? Konva.document.createElement('canvas')
@ -18544,20 +18554,7 @@
return 'crosshair';
}
var angle;
if (anchorName === 'top-left' || anchorName === 'bottom-right') {
angle = -45;
} else if (anchorName === 'top-right' || anchorName === 'bottom-left') {
angle = 45;
} else if (anchorName === 'top-center' || anchorName === 'bottom-center') {
angle = 0;
} else if (anchorName === 'middle-left' || anchorName === 'middle-right') {
angle = 90;
} else {
angle = 0;
}
angle = (angle + Konva.Util._radToDeg(rad) + 360) % 360;
var angle = (Konva.Util._radToDeg(rad) % 360 + 360) % 360;
if (
Konva.Util._inRange(angle, 315 + 22.5, 360) ||
@ -18589,6 +18586,9 @@
} else {
// how can we can there?
// TODO: throw error
Konva.Util.error(
'Transformer has unknown angle for cursor detection: ' + angle
);
return 'pointer';
}
}
@ -18670,8 +18670,8 @@
this._createElements();
// bindings
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this._handleMouseMove = this._handleMouseMove.bind(this);
this._handleMouseUp = this._handleMouseUp.bind(this);
this.update = this.update.bind(this);
// update transformer data for certain attr changes
@ -18808,16 +18808,36 @@
});
var self = this;
anchor.on('mousedown touchstart', function(e) {
self.handleResizerMouseDown(e);
self._handleMouseDown(e);
});
// add hover styling
anchor.on('mouseenter', function() {
var layer = this.getLayer();
var rad = Konva.getAngle(this.getParent().rotation());
var cursor = getCursor(name, rad);
anchor.getStage().getContainer().style.cursor = cursor;
this.fill('lightgrey');
var tr = this.getParent();
// TODO: I guess there are some ways to simplify that calculations
// the basic idea is to find "angle" of handler
var rad = Konva.getAngle(tr.rotation());
var cdx = tr.getWidth() / 2;
var cdy = tr.getHeight() / 2;
var parentPos = tr.getAbsolutePosition(tr.getParent());
var center = {
x: parentPos.x + (cdx * Math.cos(rad) + cdy * Math.sin(-rad)),
y: parentPos.y + (cdy * Math.cos(rad) + cdx * Math.sin(rad))
};
var pos = this.getAbsolutePosition(tr.getParent());
var dx = -pos.x + center.x;
var dy = -pos.y + center.y;
var angle = -Math.atan2(-dy, dx) - Math.PI / 2;
var cursor = getCursor(name, angle);
anchor.getStage().content.style.cursor = cursor;
layer.batchDraw();
});
anchor.on('mouseout', function() {
@ -18825,8 +18845,7 @@
if (!layer) {
return;
}
anchor.getStage().getContainer().style.cursor = '';
this.fill('white');
anchor.getStage().content.style.cursor = '';
layer.batchDraw();
});
this.add(anchor);
@ -18851,7 +18870,10 @@
);
ctx.moveTo(this.width() / 2, -padding);
if (tr.rotateEnabled()) {
ctx.lineTo(this.width() / 2, -tr.rotateHandlerOffset());
ctx.lineTo(
this.width() / 2,
-tr.rotateHandlerOffset() * Konva.Util._sign(this.height())
);
}
ctx.fillStrokeShape(this);
@ -18860,7 +18882,7 @@
this.add(back);
},
handleResizerMouseDown: function(e) {
_handleMouseDown: function(e) {
this.movingResizer = e.target.name();
// var node = this.getNode();
@ -18871,10 +18893,10 @@
this.sin = height / hypotenuse;
this.cos = width / hypotenuse;
window.addEventListener('mousemove', this.handleMouseMove);
window.addEventListener('touchmove', this.handleMouseMove);
window.addEventListener('mouseup', this.handleMouseUp);
window.addEventListener('touchend', this.handleMouseUp);
window.addEventListener('mousemove', this._handleMouseMove);
window.addEventListener('touchmove', this._handleMouseMove);
window.addEventListener('mouseup', this._handleMouseUp);
window.addEventListener('touchend', this._handleMouseUp);
this._transforming = true;
@ -18882,7 +18904,7 @@
this.getNode().fire('transformstart');
},
handleMouseMove: function(e) {
_handleMouseMove: function(e) {
var x, y, newHypotenuse;
var resizerNode = this.findOne('.' + this.movingResizer);
var stage = resizerNode.getStage();
@ -18981,7 +19003,10 @@
y = -resizerNode.y() + attrs.height / 2;
var dAlpha = Math.atan2(-y, x) + Math.PI / 2;
// var attrs = this._getAttrs();
if (attrs.height < 0) {
dAlpha -= Math.PI;
}
var rot = Konva.getAngle(this.rotation());
@ -19008,29 +19033,27 @@
var dx = padding;
var dy = padding;
this._fitNodeInto(
Object.assign(attrs, {
rotation: Konva.angleDeg
? newRotation
: Konva.Util._degToRad(newRotation),
x:
attrs.x +
(attrs.width / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.height / 2 + padding) *
(Math.sin(-alpha) - Math.sin(-newAlpha)) -
(dx * Math.cos(rot) + dy * Math.sin(-rot)),
y:
attrs.y +
(attrs.height / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.width / 2 + padding) *
(Math.sin(alpha) - Math.sin(newAlpha)) -
(dy * Math.cos(rot) + dx * Math.sin(rot)),
width: attrs.width + padding * 2,
height: attrs.height + padding * 2
})
);
this._fitNodeInto({
rotation: Konva.angleDeg
? newRotation
: Konva.Util._degToRad(newRotation),
x:
attrs.x +
(attrs.width / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.height / 2 + padding) *
(Math.sin(-alpha) - Math.sin(-newAlpha)) -
(dx * Math.cos(rot) + dy * Math.sin(-rot)),
y:
attrs.y +
(attrs.height / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.width / 2 + padding) *
(Math.sin(alpha) - Math.sin(newAlpha)) -
(dy * Math.cos(rot) + dx * Math.sin(rot)),
width: attrs.width + padding * 2,
height: attrs.height + padding * 2
});
} else {
console.error(
new Error(
@ -19064,17 +19087,17 @@
});
},
handleMouseUp: function() {
_handleMouseUp: function() {
this._removeEvents();
},
_removeEvents: function() {
if (this._transforming) {
this._transforming = false;
window.removeEventListener('mousemove', this.handleMouseMove);
window.removeEventListener('touchmove', this.handleMouseMove);
window.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('touchend', this.handleMouseUp);
window.removeEventListener('mousemove', this._handleMouseMove);
window.removeEventListener('touchmove', this._handleMouseMove);
window.removeEventListener('mouseup', this._handleMouseUp);
window.removeEventListener('touchend', this._handleMouseUp);
this.fire('transformend');
this.getNode().fire('transformend');
}
@ -19187,7 +19210,7 @@
this.findOne('.rotater').setAttrs({
x: width / 2,
y: -this.rotateHandlerOffset(),
y: -this.rotateHandlerOffset() * Konva.Util._sign(height),
visible: this.rotateEnabled()
});

4
konva.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -498,6 +498,16 @@
firstChar === firstChar.toUpperCase()
);
},
_sign: function(number) {
if (number === 0) {
return 0;
}
if (number > 0) {
return 1;
} else {
return -1;
}
},
createCanvasElement: function() {
var canvas = Konva.isBrowser
? Konva.document.createElement('canvas')

View File

@ -28,20 +28,7 @@
return 'crosshair';
}
var angle;
if (anchorName === 'top-left' || anchorName === 'bottom-right') {
angle = -45;
} else if (anchorName === 'top-right' || anchorName === 'bottom-left') {
angle = 45;
} else if (anchorName === 'top-center' || anchorName === 'bottom-center') {
angle = 0;
} else if (anchorName === 'middle-left' || anchorName === 'middle-right') {
angle = 90;
} else {
angle = 0;
}
angle = (angle + Konva.Util._radToDeg(rad) + 360) % 360;
var angle = (Konva.Util._radToDeg(rad) % 360 + 360) % 360;
if (
Konva.Util._inRange(angle, 315 + 22.5, 360) ||
@ -73,6 +60,9 @@
} else {
// how can we can there?
// TODO: throw error
Konva.Util.error(
'Transformer has unknown angle for cursor detection: ' + angle
);
return 'pointer';
}
}
@ -129,8 +119,8 @@
this._createElements();
// bindings
this.handleMouseMove = this.handleMouseMove.bind(this);
this.handleMouseUp = this.handleMouseUp.bind(this);
this._handleMouseMove = this._handleMouseMove.bind(this);
this._handleMouseUp = this._handleMouseUp.bind(this);
this.update = this.update.bind(this);
// update transformer data for certain attr changes
@ -267,16 +257,36 @@
});
var self = this;
anchor.on('mousedown touchstart', function(e) {
self.handleResizerMouseDown(e);
self._handleMouseDown(e);
});
// add hover styling
anchor.on('mouseenter', function() {
var layer = this.getLayer();
var rad = Konva.getAngle(this.getParent().rotation());
var cursor = getCursor(name, rad);
anchor.getStage().getContainer().style.cursor = cursor;
this.fill('lightgrey');
var tr = this.getParent();
// TODO: I guess there are some ways to simplify that calculations
// the basic idea is to find "angle" of handler
var rad = Konva.getAngle(tr.rotation());
var cdx = tr.getWidth() / 2;
var cdy = tr.getHeight() / 2;
var parentPos = tr.getAbsolutePosition(tr.getParent());
var center = {
x: parentPos.x + (cdx * Math.cos(rad) + cdy * Math.sin(-rad)),
y: parentPos.y + (cdy * Math.cos(rad) + cdx * Math.sin(rad))
};
var pos = this.getAbsolutePosition(tr.getParent());
var dx = -pos.x + center.x;
var dy = -pos.y + center.y;
var angle = -Math.atan2(-dy, dx) - Math.PI / 2;
var cursor = getCursor(name, angle);
anchor.getStage().content.style.cursor = cursor;
layer.batchDraw();
});
anchor.on('mouseout', function() {
@ -284,8 +294,7 @@
if (!layer) {
return;
}
anchor.getStage().getContainer().style.cursor = '';
this.fill('white');
anchor.getStage().content.style.cursor = '';
layer.batchDraw();
});
this.add(anchor);
@ -310,7 +319,10 @@
);
ctx.moveTo(this.width() / 2, -padding);
if (tr.rotateEnabled()) {
ctx.lineTo(this.width() / 2, -tr.rotateHandlerOffset());
ctx.lineTo(
this.width() / 2,
-tr.rotateHandlerOffset() * Konva.Util._sign(this.height())
);
}
ctx.fillStrokeShape(this);
@ -319,7 +331,7 @@
this.add(back);
},
handleResizerMouseDown: function(e) {
_handleMouseDown: function(e) {
this.movingResizer = e.target.name();
// var node = this.getNode();
@ -330,10 +342,10 @@
this.sin = height / hypotenuse;
this.cos = width / hypotenuse;
window.addEventListener('mousemove', this.handleMouseMove);
window.addEventListener('touchmove', this.handleMouseMove);
window.addEventListener('mouseup', this.handleMouseUp);
window.addEventListener('touchend', this.handleMouseUp);
window.addEventListener('mousemove', this._handleMouseMove);
window.addEventListener('touchmove', this._handleMouseMove);
window.addEventListener('mouseup', this._handleMouseUp);
window.addEventListener('touchend', this._handleMouseUp);
this._transforming = true;
@ -341,7 +353,7 @@
this.getNode().fire('transformstart');
},
handleMouseMove: function(e) {
_handleMouseMove: function(e) {
var x, y, newHypotenuse;
var resizerNode = this.findOne('.' + this.movingResizer);
var stage = resizerNode.getStage();
@ -440,7 +452,10 @@
y = -resizerNode.y() + attrs.height / 2;
var dAlpha = Math.atan2(-y, x) + Math.PI / 2;
// var attrs = this._getAttrs();
if (attrs.height < 0) {
dAlpha -= Math.PI;
}
var rot = Konva.getAngle(this.rotation());
@ -467,29 +482,27 @@
var dx = padding;
var dy = padding;
this._fitNodeInto(
Object.assign(attrs, {
rotation: Konva.angleDeg
? newRotation
: Konva.Util._degToRad(newRotation),
x:
attrs.x +
(attrs.width / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.height / 2 + padding) *
(Math.sin(-alpha) - Math.sin(-newAlpha)) -
(dx * Math.cos(rot) + dy * Math.sin(-rot)),
y:
attrs.y +
(attrs.height / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.width / 2 + padding) *
(Math.sin(alpha) - Math.sin(newAlpha)) -
(dy * Math.cos(rot) + dx * Math.sin(rot)),
width: attrs.width + padding * 2,
height: attrs.height + padding * 2
})
);
this._fitNodeInto({
rotation: Konva.angleDeg
? newRotation
: Konva.Util._degToRad(newRotation),
x:
attrs.x +
(attrs.width / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.height / 2 + padding) *
(Math.sin(-alpha) - Math.sin(-newAlpha)) -
(dx * Math.cos(rot) + dy * Math.sin(-rot)),
y:
attrs.y +
(attrs.height / 2 + padding) *
(Math.cos(alpha) - Math.cos(newAlpha)) +
(attrs.width / 2 + padding) *
(Math.sin(alpha) - Math.sin(newAlpha)) -
(dy * Math.cos(rot) + dx * Math.sin(rot)),
width: attrs.width + padding * 2,
height: attrs.height + padding * 2
});
} else {
console.error(
new Error(
@ -523,17 +536,17 @@
});
},
handleMouseUp: function() {
_handleMouseUp: function() {
this._removeEvents();
},
_removeEvents: function() {
if (this._transforming) {
this._transforming = false;
window.removeEventListener('mousemove', this.handleMouseMove);
window.removeEventListener('touchmove', this.handleMouseMove);
window.removeEventListener('mouseup', this.handleMouseUp);
window.removeEventListener('touchend', this.handleMouseUp);
window.removeEventListener('mousemove', this._handleMouseMove);
window.removeEventListener('touchmove', this._handleMouseMove);
window.removeEventListener('mouseup', this._handleMouseUp);
window.removeEventListener('touchend', this._handleMouseUp);
this.fire('transformend');
this.getNode().fire('transformend');
}
@ -646,7 +659,7 @@
this.findOne('.rotater').setAttrs({
x: width / 2,
y: -this.rotateHandlerOffset(),
y: -this.rotateHandlerOffset() * Konva.Util._sign(height),
visible: this.rotateEnabled()
});

View File

@ -2140,7 +2140,6 @@ suite('Container', function() {
y: 10
});
group.add(new Konva.Group());
console.log(group.getClientRect());
assert.deepEqual(group.getClientRect(), {
x: 10,
y: 10,

View File

@ -884,22 +884,19 @@ suite('Transformer', function() {
});
});
test('with strokes', function() {
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: 20,
y: 60,
x: 50,
y: 160,
draggable: true,
width: 10,
height: 10,
width: 100,
height: 100,
fill: 'yellow',
strokeWidth: 2,
stroke: 'black',
scaleX: 10,
scaleY: 10
scaleY: -1
});
layer.add(rect);
@ -907,7 +904,91 @@ suite('Transformer', function() {
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');
});
});