perf: replace the Plotly snap marker with a projected DOM overlay
Orbiting and the snap preview felt far behind the cursor. Measured in the page: a single Plotly.restyle on a gl3d plot costs about 90 ms even for a one-trace figure, so every marker update stalled the scene and the marker trailed the mouse; each one also queued another redraw while the user was dragging. The marker is now a pointer-events-none div positioned by projecting the snapped world point through glplot.cameraParams (validated: the camera centre lands at the canvas centre), updated with one style write and re-projected on plotly_relayout so it stays glued to the target during orbit. No plotly calls at all on the hover path - 200 mouse-move events now cost 0 restyles - and the empty hover trace is gone from the figure. Also logs the WebGL renderer once (via the console bridge) since hardware acceleration decides how smooth orbit feels and is otherwise invisible.
This commit is contained in:
parent
7839f05384
commit
1b0620a392
5 changed files with 145 additions and 93 deletions
|
|
@ -26,10 +26,6 @@ def _traces(scene, name: str) -> list[dict]: # type: ignore[no-untyped-def]
|
|||
return [trace for trace in scene.data if trace.get("name") == name]
|
||||
|
||||
|
||||
def _kinds(scene) -> list[str]: # type: ignore[no-untyped-def]
|
||||
return [trace.get("meta", {}).get("kind", trace["type"]) for trace in scene.data]
|
||||
|
||||
|
||||
def test_builds_grid_nodes_and_frames() -> None:
|
||||
scene = PlotlyTraceBuilder().build(_load("basic_truss"), SceneOptions())
|
||||
names = {trace.get("name") for trace in scene.data}
|
||||
|
|
@ -37,8 +33,9 @@ def test_builds_grid_nodes_and_frames() -> None:
|
|||
assert "nodes" in names
|
||||
assert "elements" in names
|
||||
assert scene.diagonal > 0
|
||||
# The hover-snap marker is always present so JS can restyle it.
|
||||
assert scene.data[scene.hover_trace]["meta"]["kind"] == "hover"
|
||||
# The snap marker is a DOM overlay, not a trace (a gl3d restyle costs
|
||||
# ~90 ms, which made a trace marker lag behind the cursor).
|
||||
assert all(trace.get("meta", {}).get("kind") != "hover" for trace in scene.data)
|
||||
|
||||
|
||||
def test_nodes_carry_ids_as_customdata() -> None:
|
||||
|
|
@ -187,15 +184,14 @@ def test_payload_is_json_serialisable() -> None:
|
|||
assert scene.layout["scene"]["aspectmode"] == "data"
|
||||
|
||||
|
||||
def test_empty_project_yields_only_the_hover_marker() -> None:
|
||||
def test_empty_project_yields_no_traces() -> None:
|
||||
scene = PlotlyTraceBuilder().build(None, SceneOptions())
|
||||
assert scene.data == []
|
||||
assert scene.hover_trace == -1
|
||||
|
||||
from otko.core import Project
|
||||
|
||||
empty = PlotlyTraceBuilder().build(Project(ndm=3, ndf=6), SceneOptions())
|
||||
assert _kinds(empty) == ["hover"]
|
||||
assert empty.data == []
|
||||
|
||||
|
||||
def test_frame_trace_meta_marks_elements_pickable() -> None:
|
||||
|
|
|
|||
Loading…
Reference in a new issue