fix: shape resize/rotate by converting screen coords to canvas space
Resize and rotation handlers in folk-shape.ts passed raw event.clientX/Y (screen coordinates) to toLocalSpace/angleFromOrigin, but those methods expect canvas-parent coordinates. With any zoom/pan, the two coordinate systems diverge, making resize non-functional and rotation erratic. Added #screenToParent() to convert viewport coords to the parent's coordinate space using getBoundingClientRect + parent scale. Applied to: - Resize handle drag (pointermove → toLocalSpace) - Rotation start (pointerdown → angleFromOrigin) - Rotation drag (pointermove → angleFromOrigin) Also syncs ghost placeholder size with zoom changes so the dotted preview stays accurate if user zooms while in placement mode. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
7616fe0757
commit
aeb9247f96
|
|
@ -375,6 +375,18 @@ export class FolkShape extends FolkElement {
|
|||
return rect.width / w;
|
||||
}
|
||||
|
||||
/** Convert screen (viewport) coordinates to the parent's coordinate space. */
|
||||
#screenToParent(screenX: number, screenY: number): Point {
|
||||
const parent = this.parentElement;
|
||||
if (!parent) return { x: screenX, y: screenY };
|
||||
const parentRect = parent.getBoundingClientRect();
|
||||
const zoom = this.#getParentScale();
|
||||
return {
|
||||
x: (screenX - parentRect.left) / zoom,
|
||||
y: (screenY - parentRect.top) / zoom,
|
||||
};
|
||||
}
|
||||
|
||||
handleEvent(event: PointerEvent | KeyboardEvent | TouchEvent) {
|
||||
// Handle touch events for mobile drag support
|
||||
if (event instanceof TouchEvent) {
|
||||
|
|
@ -454,7 +466,7 @@ export class FolkShape extends FolkElement {
|
|||
x: this.#rect.width * this.#rect.rotateOrigin.x,
|
||||
y: this.#rect.height * this.#rect.rotateOrigin.y,
|
||||
});
|
||||
const mousePos = { x: event.clientX, y: event.clientY };
|
||||
const mousePos = this.#screenToParent(event.clientX, event.clientY);
|
||||
this.#startAngle = Vector.angleFromOrigin(mousePos, parentRotateOrigin) - this.#rect.rotation;
|
||||
}
|
||||
|
||||
|
|
@ -526,7 +538,7 @@ export class FolkShape extends FolkElement {
|
|||
const mousePos =
|
||||
event instanceof KeyboardEvent
|
||||
? { x: currentPos.x + moveDelta.x, y: currentPos.y + moveDelta.y }
|
||||
: { x: event.clientX, y: event.clientY };
|
||||
: this.#screenToParent(event.clientX, event.clientY);
|
||||
|
||||
this.#handleResize(
|
||||
handle as ResizeHandle,
|
||||
|
|
@ -544,7 +556,7 @@ export class FolkShape extends FolkElement {
|
|||
y: this.#rect.height * this.#rect.rotateOrigin.y,
|
||||
});
|
||||
const currentAngle = Vector.angleFromOrigin(
|
||||
{ x: event.clientX, y: event.clientY },
|
||||
this.#screenToParent(event.clientX, event.clientY),
|
||||
parentRotateOrigin,
|
||||
);
|
||||
this.rotation = currentAngle - this.#startAngle;
|
||||
|
|
|
|||
|
|
@ -2664,6 +2664,12 @@
|
|||
canvas.style.backgroundPosition = `${panX - 1}px ${panY - 1}px`;
|
||||
// Keep MI bridge in sync
|
||||
__miCanvasBridge.setViewport(panX, panY, scale);
|
||||
// Keep ghost placeholder size in sync with zoom
|
||||
if (ghostEl && pendingTool) {
|
||||
const defaults = SHAPE_DEFAULTS[pendingTool.tagName] || { width: 300, height: 200 };
|
||||
ghostEl.style.width = (defaults.width * scale) + "px";
|
||||
ghostEl.style.height = (defaults.height * scale) + "px";
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("zoom-in").addEventListener("click", () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue