Improve churn

This commit is contained in:
Benjamin Lu
2025-09-10 19:02:48 -07:00
parent 0ba660f8ff
commit ed7a4e9c24
2 changed files with 34 additions and 43 deletions

View File

@@ -39,6 +39,7 @@ import {
type Size,
type SlotLayout
} from '@/renderer/core/layout/types'
import { sameBounds, samePoint } from '@/renderer/core/layout/utils/geometry'
import { SpatialIndexManager } from '@/renderer/core/spatial/SpatialIndex'
type YEventChange = {
@@ -413,12 +414,8 @@ class LayoutStoreImpl implements LayoutStore {
// Short-circuit if bounds and centerPos unchanged
if (
existing &&
existing.bounds.x === layout.bounds.x &&
existing.bounds.y === layout.bounds.y &&
existing.bounds.width === layout.bounds.width &&
existing.bounds.height === layout.bounds.height &&
existing.centerPos.x === layout.centerPos.x &&
existing.centerPos.y === layout.centerPos.y
sameBounds(existing.bounds, layout.bounds) &&
samePoint(existing.centerPos, layout.centerPos)
) {
// Only update path if provided (for hit detection)
if (layout.path) {
@@ -457,6 +454,13 @@ class LayoutStoreImpl implements LayoutStore {
const existing = this.slotLayouts.get(key)
if (existing) {
// Short-circuit if geometry is unchanged
if (
samePoint(existing.position, layout.position) &&
sameBounds(existing.bounds, layout.bounds)
) {
return
}
// Update spatial index
this.slotSpatialIndex.update(key, layout.bounds)
} else {
@@ -475,9 +479,18 @@ class LayoutStoreImpl implements LayoutStore {
): void {
if (!updates.length) return
// Update spatial index and map entries
// Update spatial index and map entries (skip unchanged)
for (const { key, layout } of updates) {
if (this.slotLayouts.has(key)) {
const existing = this.slotLayouts.get(key)
if (existing) {
// Short-circuit if geometry is unchanged
if (
samePoint(existing.position, layout.position) &&
sameBounds(existing.bounds, layout.bounds)
) {
continue
}
this.slotSpatialIndex.update(key, layout.bounds)
} else {
this.slotSpatialIndex.insert(key, layout.bounds)
@@ -604,12 +617,8 @@ class LayoutStoreImpl implements LayoutStore {
// Short-circuit if bounds and centerPos unchanged (prevents spatial index churn)
if (
existing &&
existing.bounds.x === layout.bounds.x &&
existing.bounds.y === layout.bounds.y &&
existing.bounds.width === layout.bounds.width &&
existing.bounds.height === layout.bounds.height &&
existing.centerPos.x === layout.centerPos.x &&
existing.centerPos.y === layout.centerPos.y
sameBounds(existing.bounds, layout.bounds) &&
samePoint(existing.centerPos, layout.centerPos)
) {
// Only update path if provided (for hit detection)
if (layout.path) {
@@ -1018,9 +1027,6 @@ class LayoutStoreImpl implements LayoutStore {
// Hit detection queries can run before CRDT updates complete
this.spatialIndex.update(operation.nodeId, newBounds)
// Update associated slot positions synchronously
this.updateNodeSlotPositions(operation.nodeId, operation.position)
// Then update CRDT
ynode.set('position', operation.position)
this.updateNodeBounds(ynode, operation.position, size)
@@ -1047,9 +1053,6 @@ class LayoutStoreImpl implements LayoutStore {
// Hit detection queries can run before CRDT updates complete
this.spatialIndex.update(operation.nodeId, newBounds)
// Update associated slot positions synchronously (size changes may affect slot positions)
this.updateNodeSlotPositions(operation.nodeId, position)
// Then update CRDT
ynode.set('size', operation.size)
this.updateNodeBounds(ynode, position, operation.size)
@@ -1330,29 +1333,6 @@ class LayoutStoreImpl implements LayoutStore {
}
}
/**
* Update slot positions when a node moves
* TODO: This should be handled by the layout sync system (useSlotLayoutSync)
* rather than manually here. For now, we'll mark affected slots as needing recalculation.
*/
private updateNodeSlotPositions(nodeId: NodeId, _nodePosition: Point): void {
// Mark all slots for this node as potentially stale
// The layout sync system will recalculate positions on the next frame
const slotsToRemove: string[] = []
for (const [key, slotLayout] of this.slotLayouts) {
if (slotLayout.nodeId === nodeId) {
slotsToRemove.push(key)
}
}
// Remove from spatial index so they'll be recalculated
for (const key of slotsToRemove) {
this.slotSpatialIndex.remove(key)
this.slotLayouts.delete(key)
}
}
// Helper methods
private layoutToYNode(layout: NodeLayout): Y.Map<unknown> {
const ynode = new Y.Map<unknown>()

View File

@@ -0,0 +1,11 @@
import type { Bounds, Point } from '@/renderer/core/layout/types'
export function samePoint(a: Point, b: Point): boolean {
return a.x === b.x && a.y === b.y
}
export function sameBounds(a: Bounds, b: Bounds): boolean {
return (
a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height
)
}