Merge branch 'dev'
This commit is contained in:
commit
a0188195d7
|
|
@ -72,7 +72,7 @@ const styles = css`
|
||||||
div {
|
div {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
overflow: scroll;
|
overflow: hidden;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,6 +249,8 @@ export class FolkShape extends FolkElement {
|
||||||
this.requestUpdate("rotation");
|
this.requestUpdate("rotation");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GAP = 8; // minimum gap between shapes
|
||||||
|
|
||||||
#highlighted = false;
|
#highlighted = false;
|
||||||
get highlighted() {
|
get highlighted() {
|
||||||
return this.#highlighted;
|
return this.#highlighted;
|
||||||
|
|
@ -348,6 +350,7 @@ export class FolkShape extends FolkElement {
|
||||||
// Apply movement
|
// Apply movement
|
||||||
this.#rect.x += moveDelta.x;
|
this.#rect.x += moveDelta.x;
|
||||||
this.#rect.y += moveDelta.y;
|
this.#rect.y += moveDelta.y;
|
||||||
|
this.#resolveOverlaps(moveDelta.x, moveDelta.y);
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
this.#dispatchTransformEvent();
|
this.#dispatchTransformEvent();
|
||||||
}
|
}
|
||||||
|
|
@ -442,6 +445,7 @@ export class FolkShape extends FolkElement {
|
||||||
} else {
|
} else {
|
||||||
this.x += moveDelta.x;
|
this.x += moveDelta.x;
|
||||||
this.y += moveDelta.y;
|
this.y += moveDelta.y;
|
||||||
|
this.#resolveOverlaps(moveDelta.x, moveDelta.y);
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
return;
|
return;
|
||||||
|
|
@ -603,6 +607,52 @@ export class FolkShape extends FolkElement {
|
||||||
this.requestUpdate();
|
this.requestUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* After moving, push this shape away from any overlapping siblings.
|
||||||
|
* Uses the direction of the move to decide which side to slide to.
|
||||||
|
*/
|
||||||
|
#resolveOverlaps(dx: number, dy: number) {
|
||||||
|
const parent = this.parentElement;
|
||||||
|
if (!parent) return;
|
||||||
|
|
||||||
|
const gap = FolkShape.GAP;
|
||||||
|
const me = { x: this.x, y: this.y, w: this.width, h: this.height };
|
||||||
|
|
||||||
|
for (const sibling of parent.children) {
|
||||||
|
if (sibling === this || !(sibling instanceof FolkShape)) continue;
|
||||||
|
if (sibling.tagName.toLowerCase() === "folk-arrow") continue;
|
||||||
|
|
||||||
|
const other = { x: sibling.x, y: sibling.y, w: sibling.width, h: sibling.height };
|
||||||
|
|
||||||
|
// Check overlap (axis-aligned)
|
||||||
|
const overlapX = me.x < other.x + other.w + gap && me.x + me.w + gap > other.x;
|
||||||
|
const overlapY = me.y < other.y + other.h + gap && me.y + me.h + gap > other.y;
|
||||||
|
|
||||||
|
if (!overlapX || !overlapY) continue;
|
||||||
|
|
||||||
|
// Compute penetration depths from each side
|
||||||
|
const pushRight = (other.x + other.w + gap) - me.x;
|
||||||
|
const pushLeft = me.x + me.w + gap - other.x;
|
||||||
|
const pushDown = (other.y + other.h + gap) - me.y;
|
||||||
|
const pushUp = me.y + me.h + gap - other.y;
|
||||||
|
|
||||||
|
// Pick the axis with the smallest penetration, biased by move direction
|
||||||
|
const minX = pushRight < pushLeft ? -pushRight : pushLeft;
|
||||||
|
const minY = pushDown < pushUp ? -pushDown : pushUp;
|
||||||
|
|
||||||
|
if (Math.abs(minX) < Math.abs(minY)) {
|
||||||
|
// Slide horizontally
|
||||||
|
this.#rect.x += dx <= 0 ? -pushLeft : pushRight;
|
||||||
|
} else {
|
||||||
|
// Slide vertically
|
||||||
|
this.#rect.y += dy <= 0 ? -pushUp : pushDown;
|
||||||
|
}
|
||||||
|
|
||||||
|
me.x = this.#rect.x;
|
||||||
|
me.y = this.#rect.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Serialize shape to JSON for Automerge sync
|
* Serialize shape to JSON for Automerge sync
|
||||||
* Subclasses should override and call super.toJSON()
|
* Subclasses should override and call super.toJSON()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue