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);
|
const leadingCard = store.items.get(leadingId);
|
||||||
if (!leadingCard) return;
|
if (!leadingCard) return;
|
||||||
|
|
||||||
// 1. Snap all followers to leader's center
|
// 1. Begin drag on the leader (clears old followers)
|
||||||
// 2. Attach them as followers to the leader's physics
|
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 => {
|
selection.forEach(id => {
|
||||||
if (id === leadingId) return;
|
if (id === leadingId) return;
|
||||||
const card = store.items.get(id);
|
const card = store.items.get(id);
|
||||||
@@ -28,9 +31,6 @@ export const handleDragStart = (store: LayoutStore, selection: string[], leading
|
|||||||
leadingCard.physics.addFollower(card);
|
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) => {
|
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) {
|
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._isDragging = true;
|
||||||
this.dragPointerId = pointerId;
|
this.dragPointerId = pointerId;
|
||||||
|
|
||||||
@@ -113,6 +121,7 @@ export class CardPhysics {
|
|||||||
private maxLimit: number = 5;
|
private maxLimit: number = 5;
|
||||||
|
|
||||||
private followers: { card: LayoutCard, offsetRotation: number }[] = [];
|
private followers: { card: LayoutCard, offsetRotation: number }[] = [];
|
||||||
|
public leader: CardPhysics | null = null;
|
||||||
|
|
||||||
addFollower(card: LayoutCard) {
|
addFollower(card: LayoutCard) {
|
||||||
// Calculate relative rotation
|
// Calculate relative rotation
|
||||||
@@ -120,25 +129,53 @@ export class CardPhysics {
|
|||||||
const offset = this.normalizeAngle(card.rotation - this.card.rotation);
|
const offset = this.normalizeAngle(card.rotation - this.card.rotation);
|
||||||
this.followers.push({ card, offsetRotation: offset });
|
this.followers.push({ card, offsetRotation: offset });
|
||||||
|
|
||||||
|
// Set back-reference
|
||||||
|
card.physics.leader = this;
|
||||||
|
|
||||||
// Add follower mass to leader
|
// Add follower mass to leader
|
||||||
this.mass += card.physics.mass;
|
this.mass += card.physics.mass;
|
||||||
this.updateMassScale();
|
this.updateMassScale();
|
||||||
|
|
||||||
// Constrain leader limits to ensure follower stays within [-5, 5]
|
// 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.minLimit = Math.max(this.minLimit, -this.ROTATION_LIMIT - offset);
|
||||||
this.maxLimit = Math.min(this.maxLimit, 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() {
|
clearFollowers() {
|
||||||
|
// Clear back-references
|
||||||
|
this.followers.forEach(f => {
|
||||||
|
f.card.physics.leader = null;
|
||||||
|
});
|
||||||
this.followers = [];
|
this.followers = [];
|
||||||
// Reset mass to base mass
|
this.recalculateStackProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private recalculateStackProperties() {
|
||||||
this.mass = this.baseMass;
|
this.mass = this.baseMass;
|
||||||
this.updateMassScale();
|
|
||||||
// Reset limits
|
|
||||||
this.minLimit = -this.ROTATION_LIMIT;
|
this.minLimit = -this.ROTATION_LIMIT;
|
||||||
this.maxLimit = 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) {
|
private updatePhysics(dt: number) {
|
||||||
|
|||||||
Reference in New Issue
Block a user