1
0
mirror of https://github.com/konvajs/konva.git synced 2025-04-24 19:03:56 +08:00

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

View File

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

View File

@ -2140,7 +2140,6 @@ suite('Container', function() {
y: 10 y: 10
}); });
group.add(new Konva.Group()); group.add(new Konva.Group());
console.log(group.getClientRect());
assert.deepEqual(group.getClientRect(), { assert.deepEqual(group.getClientRect(), {
x: 10, x: 10,
y: 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 stage = addStage();
var layer = new Konva.Layer(); var layer = new Konva.Layer();
stage.add(layer); stage.add(layer);
var rect = new Konva.Rect({ var rect = new Konva.Rect({
x: 20, x: 50,
y: 60, y: 160,
draggable: true, draggable: true,
width: 10, width: 100,
height: 10, height: 100,
fill: 'yellow', fill: 'yellow',
strokeWidth: 2, scaleY: -1
stroke: 'black',
scaleX: 10,
scaleY: 10
}); });
layer.add(rect); layer.add(rect);
@ -907,7 +904,91 @@ suite('Transformer', function() {
node: rect node: rect
}); });
layer.add(tr); layer.add(tr);
layer.draw(); 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');
}); });
}); });