Skip to content

Setting to gate node hover picking during camera motion (per-mousemove gl.readPixels) #1546

Description

@alexfazio

Problem

Sigma's mousemove handler runs GPU color-picking on every pointer move: handleMove calls getNodeAtPosition (up to twice per event), which does a synchronous gl.readPixels from the picking framebuffer. readPixels without a pack buffer behaves like glFinish plus an IPC round-trip — it serializes the CPU on the whole frame's outstanding GPU work (see MDN WebGL best practices), so on dense scenes each pointer move can stall for the full frame cost.

There is currently no setting to gate this: enableEdgeEvents gates the edge picking layer, but node hover picking always runs — including while the camera is animating or the user is dragging, exactly when frames are most expensive and hover feedback is least useful. Applications that implement their own pan/drag (bypassing the mouse captor's camera drag) cannot suppress it without monkeypatching, since handleMove is a private closure bound to the captor at construction.

Proposal

Either of:

  1. A setting like enableNodeHoverOnMove: false (analogous to hideEdgesOnMove/hideLabelsOnMove) that skips getNodeAtPosition while the renderer's existing moving state is true (camera.isAnimated() || mouseCaptor.isMoving || draggedEvents || currentWheelDirection), plus ideally a public way for apps with custom pan gestures to signal motion (the internal moving flag never sets for app-driven camera.setState pans).
  2. Or an enableNodeHoverEvents: false master switch mirroring enableEdgeEvents.

Longer-term, the picking readback could use the WebGL2 async pattern (PIXEL_PACK_BUFFER + fenceSync/clientWaitSync + getBufferSubData) to avoid the pipeline sync entirely.

Context

Measured in a production Sigma v3 app (1,400-node graph, dense component, extreme zoom): pointer-driven frames show long-animation-frame entries with near-zero script attribution whose stalls track the per-move picking readbacks; suppressing hover UX at the app policy level cannot remove the cost because picking still runs and discards. Happy to provide traces or test a patch.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions