fix: ensure card detaches from leader and clears followers when starting a drag, and centralize stack property recalculations.
This commit is contained in:
@@ -4,8 +4,11 @@ export const handleDragStart = (store: LayoutStore, selection: string[], leading
|
||||
const leadingCard = store.items.get(leadingId);
|
||||
if (!leadingCard) return;
|
||||
|
||||
// 1. Snap all followers to leader's center
|
||||
// 2. Attach them as followers to the leader's physics
|
||||
// 1. Begin drag on the leader (clears old followers)
|
||||
leadingCard.physics.beginDrag(offset, pointerId);
|
||||
|
||||
// 2. Snap all followers to leader's center
|
||||
// 3. Attach them as followers to the leader's physics
|
||||
selection.forEach(id => {
|
||||
if (id === leadingId) return;
|
||||
const card = store.items.get(id);
|
||||
@@ -28,9 +31,6 @@ export const handleDragStart = (store: LayoutStore, selection: string[], leading
|
||||
leadingCard.physics.addFollower(card);
|
||||
}
|
||||
});
|
||||
|
||||
// 3. Begin drag ONLY on the leader
|
||||
leadingCard.physics.beginDrag(offset, pointerId);
|
||||
};
|
||||
|
||||
export const attachToDragGroup = (store: LayoutStore, selection: string[], leadingId: string, pointerId: number) => {
|
||||
|
||||
@@ -46,6 +46,14 @@ export class CardPhysics {
|
||||
}
|
||||
|
||||
beginDrag(offset: { x: number, y: number }, pointerId: number) {
|
||||
// If I am a follower of someone else, detach first!
|
||||
if (this.leader) {
|
||||
this.leader.removeFollower(this.card);
|
||||
}
|
||||
|
||||
// Ensure I don't have stale followers from a previous session
|
||||
this.stopPhysicsLoop();
|
||||
|
||||
this._isDragging = true;
|
||||
this.dragPointerId = pointerId;
|
||||
|
||||
@@ -113,6 +121,7 @@ export class CardPhysics {
|
||||
private maxLimit: number = 5;
|
||||
|
||||
private followers: { card: LayoutCard, offsetRotation: number }[] = [];
|
||||
public leader: CardPhysics | null = null;
|
||||
|
||||
addFollower(card: LayoutCard) {
|
||||
// Calculate relative rotation
|
||||
@@ -120,25 +129,53 @@ export class CardPhysics {
|
||||
const offset = this.normalizeAngle(card.rotation - this.card.rotation);
|
||||
this.followers.push({ card, offsetRotation: offset });
|
||||
|
||||
// Set back-reference
|
||||
card.physics.leader = this;
|
||||
|
||||
// Add follower mass to leader
|
||||
this.mass += card.physics.mass;
|
||||
this.updateMassScale();
|
||||
|
||||
// Constrain leader limits to ensure follower stays within [-5, 5]
|
||||
// -5 <= leader + offset <= 5
|
||||
// -5 - offset <= leader <= 5 - offset
|
||||
this.minLimit = Math.max(this.minLimit, -this.ROTATION_LIMIT - offset);
|
||||
this.maxLimit = Math.min(this.maxLimit, this.ROTATION_LIMIT - offset);
|
||||
}
|
||||
|
||||
removeFollower(card: LayoutCard) {
|
||||
const index = this.followers.findIndex(f => f.card === card);
|
||||
if (index !== -1) {
|
||||
const follower = this.followers[index];
|
||||
follower.card.physics.leader = null;
|
||||
this.followers.splice(index, 1);
|
||||
|
||||
// Recalculate mass and limits
|
||||
this.recalculateStackProperties();
|
||||
}
|
||||
}
|
||||
|
||||
clearFollowers() {
|
||||
// Clear back-references
|
||||
this.followers.forEach(f => {
|
||||
f.card.physics.leader = null;
|
||||
});
|
||||
this.followers = [];
|
||||
// Reset mass to base mass
|
||||
this.recalculateStackProperties();
|
||||
}
|
||||
|
||||
private recalculateStackProperties() {
|
||||
this.mass = this.baseMass;
|
||||
this.updateMassScale();
|
||||
// Reset limits
|
||||
this.minLimit = -this.ROTATION_LIMIT;
|
||||
this.maxLimit = this.ROTATION_LIMIT;
|
||||
|
||||
for (const f of this.followers) {
|
||||
this.mass += f.card.physics.mass;
|
||||
|
||||
// Re-apply limits
|
||||
const offset = f.offsetRotation;
|
||||
this.minLimit = Math.max(this.minLimit, -this.ROTATION_LIMIT - offset);
|
||||
this.maxLimit = Math.min(this.maxLimit, this.ROTATION_LIMIT - offset);
|
||||
}
|
||||
this.updateMassScale();
|
||||
}
|
||||
|
||||
private updatePhysics(dt: number) {
|
||||
|
||||
Reference in New Issue
Block a user