fix: rotate/scale press-drag-release + object-center pivot

This commit is contained in:
A0 Orchestrator
2026-07-02 07:51:13 +02:00
parent 137f5f3a27
commit 72e3d1da24
+26 -18
View File
@@ -368,10 +368,10 @@ export class InteractionEngine {
return; return;
} }
// Move/Copy: confirm on mouseUp (drag-release) // Move/Copy/Rotate/Scale: confirm on mouseUp (press-drag-release)
if (this.state.phase === 'modifying' && this.state.points.length >= 1) { if (this.state.phase === 'modifying' && this.state.points.length >= 1) {
const tool = this.state.activeTool; const tool = this.state.activeTool;
if (tool === 'move' || tool === 'copy') { if (tool === 'move' || tool === 'copy' || tool === 'rotate' || tool === 'scale') {
const raw = this.getWorldCoords(e); const raw = this.getWorldCoords(e);
const snapped = this.applySnap(raw.x, raw.y); const snapped = this.applySnap(raw.x, raw.y);
const final = this.applyOrtho(snapped.x, snapped.y); const final = this.applyOrtho(snapped.x, snapped.y);
@@ -777,10 +777,10 @@ export class InteractionEngine {
return; return;
} }
// Move/Copy: press-drag-release (kein click-click) // Move/Copy/Rotate/Scale: press-drag-release (kein click-click)
if (tool === 'move' || tool === 'copy') { if (tool === 'move' || tool === 'copy' || tool === 'rotate' || tool === 'scale') {
if (this.state.phase === 'modifying' && this.state.points.length >= 1) { if (this.state.phase === 'modifying' && this.state.points.length >= 1) {
// Zweiter Klick bei move/copy — sollte nicht passieren, aber falls doch: bestätigen // Zweiter Klick — sollte nicht passieren bei drag-release, aber falls doch: bestätigen
this.confirmModify(pt); this.confirmModify(pt);
return; return;
} }
@@ -796,7 +796,7 @@ export class InteractionEngine {
return; return;
} }
// Rotate/Scale/Mirror: click-click (Pivot + Target) // Mirror: click-click (zwei Punkte für die Spiegelungsachse)
if (this.state.phase === 'modifying' && this.state.points.length >= 1) { if (this.state.phase === 'modifying' && this.state.points.length >= 1) {
this.confirmModify(pt); this.confirmModify(pt);
return; return;
@@ -825,13 +825,17 @@ export class InteractionEngine {
// Show preview of first selected element moved // Show preview of first selected element moved
this.state.previewElement = moveElement(this.modifySelected[0], dx, dy); this.state.previewElement = moveElement(this.modifySelected[0], dx, dy);
} else if (tool === 'rotate') { } else if (tool === 'rotate') {
const angle = angleBetween(base, pt); const objCenter = { x: this.modifySelected[0].x, y: this.modifySelected[0].y };
this.state.previewElement = rotateElement(this.modifySelected[0], base.x, base.y, angle); const startAngle = angleBetween(objCenter, base);
const currentAngle = angleBetween(objCenter, pt);
const rotationDelta = currentAngle - startAngle;
this.state.previewElement = rotateElement(this.modifySelected[0], objCenter.x, objCenter.y, rotationDelta);
} else if (tool === 'scale') { } else if (tool === 'scale') {
const dist = distance(base, pt); const objCenter = { x: this.modifySelected[0].x, y: this.modifySelected[0].y };
const refDist = distance(base, { x: this.modifySelected[0].x, y: this.modifySelected[0].y }); const startDist = distance(objCenter, base);
const factor = refDist > 0 ? dist / refDist : 1; const currentDist = distance(objCenter, pt);
this.state.previewElement = scaleElement(this.modifySelected[0], base.x, base.y, factor, factor); const factor = startDist > 0 ? currentDist / startDist : 1;
this.state.previewElement = scaleElement(this.modifySelected[0], objCenter.x, objCenter.y, factor, factor);
} else if (tool === 'mirror') { } else if (tool === 'mirror') {
// Mirror preview: axis from base point to current mouse position // Mirror preview: axis from base point to current mouse position
this.state.previewElement = mirrorElement(this.modifySelected[0], base.x, base.y, pt.x, pt.y); this.state.previewElement = mirrorElement(this.modifySelected[0], base.x, base.y, pt.x, pt.y);
@@ -871,14 +875,18 @@ export class InteractionEngine {
this.onElementCreated?.({ ...copy, id: this.generateId() }); this.onElementCreated?.({ ...copy, id: this.generateId() });
} }
} else if (tool === 'rotate') { } else if (tool === 'rotate') {
const angle = angleBetween(base, pt); const objCenter = { x: this.modifySelected[0].x, y: this.modifySelected[0].y };
const modified = this.modifySelected.map(el => rotateElement(el, base.x, base.y, angle)); const startAngle = angleBetween(objCenter, base);
const endAngle = angleBetween(objCenter, pt);
const rotationDelta = endAngle - startAngle;
const modified = this.modifySelected.map(el => rotateElement(el, objCenter.x, objCenter.y, rotationDelta));
this.onElementsModified?.(modified); this.onElementsModified?.(modified);
} else if (tool === 'scale') { } else if (tool === 'scale') {
const dist = distance(base, pt); const objCenter = { x: this.modifySelected[0].x, y: this.modifySelected[0].y };
const refDist = distance(base, { x: this.modifySelected[0].x, y: this.modifySelected[0].y }); const startDist = distance(objCenter, base);
const factor = refDist > 0 ? dist / refDist : 1; const endDist = distance(objCenter, pt);
const modified = this.modifySelected.map(el => scaleElement(el, base.x, base.y, factor, factor)); const factor = startDist > 0 ? endDist / startDist : 1;
const modified = this.modifySelected.map(el => scaleElement(el, objCenter.x, objCenter.y, factor, factor));
this.onElementsModified?.(modified); this.onElementsModified?.(modified);
} else if (tool === 'mirror') { } else if (tool === 'mirror') {
// Mirror axis: base point (first click) to current point (second click) // Mirror axis: base point (first click) to current point (second click)