Skip to content

Conversation

@kswenson
Copy link
Member

Summary

This PR adds an implementation plan for two new renderers to address WebGL context limitations and SVG export needs:

  • CanvasPointRenderer: Canvas 2D fallback when WebGL contexts are exhausted (browsers limit to ~16)
  • SVG Export Utility: Clean SVG generation for image export (replacing foreignObject approach)

Purpose

This is a Request for Comments - the PR contains only the plan document (v3/doc/point-rendering-plan.md) for team review before implementation begins.

Key Design Decisions

  1. Keep PIXI.js - Continue using PIXI for WebGL rendering rather than writing custom WebGL code
  2. Canvas for runtime fallback - Use Canvas 2D when WebGL unavailable (better performance than SVG for large datasets)
  3. SVG as utility function - Export-only, no event handling needed, simpler than full renderer class
  4. d3-quadtree for hit testing - O(log n) lookups for Canvas event handling

Open Questions

  1. Is d3-quadtree already available as a dependency?
  2. What performance threshold should trigger degraded experience messaging?
  3. Should SVG export read from CanvasPointRenderer state or directly from PointsState?

Review Request

Please review the plan and leave comments on:

  • Overall approach
  • Implementation phases
  • Any concerns or alternative suggestions

🤖 Generated with Claude Code

kswenson and others added 11 commits January 17, 2026 17:03
Refactor point rendering to support WebGL context pooling, addressing
the browser's ~16 context limit when documents have many graphs.

Key changes:
- Add PointRendererBase abstraction with PixiPointRenderer and
  NullPointRenderer implementations
- Add WebGLContextManager singleton to manage context pool (max 14)
- Add PointsState to preserve point data across renderer switches
- Add usePointRenderer/usePointRendererArray hooks for React integration
- Implement priority-based context allocation (point count + user clicks)
- Show placeholder message when context unavailable; clicking prioritizes
- Clean up unused PIXI imports throughout codebase

Graphs without WebGL contexts now show a helpful message and can be
prioritized by clicking/selecting them. When a graph becomes visible
or is selected, it requests a context and may evict a lower-priority
graph's context if the pool is full.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document the WebGL context pooling system and point renderer abstraction,
including motivation, architecture overview, key components, and usage
examples. This provides context for engineers and LLMs working in this area.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive test coverage for the new point rendering architecture:
- PointsState: state management and sync with case data
- NullPointRenderer: no-op renderer behavior and base class template methods
- WebGLContextManager: context pooling, priority, eviction, and yield/release
- point-renderer-compat: type guards and compatibility utilities

Also export WebGLContextManager class to enable test isolation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update MapPointLayer to use PixiPointRenderer instead of PixiPoints
- Update usePixiPointsArray hook to use PointRendererBase types
- Update Background, MapBackground, MapInterior to use PointRendererArray
- Update Graph and GraphComponent to use PointRendererArray directly
- Add x/y coordinates to IPointMetadata for marquee selection support
- Update tests for new metadata structure

This completes the migration of map components to the new renderer
architecture, bringing maps in line with graphs.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove point-renderer-compat.ts and its tests
- Rename PixiPointsCompatible -> PointRendererBase
- Rename PixiPointsCompatibleArray -> PointRendererArray
- Rename pixiPoints -> renderer throughout codebase
- Rename pixiPointsArray -> rendererArray
- Rename hook files:
  - use-pixi-points-array.ts -> use-renderer-array.ts
  - use-pixi-pointer-down.ts -> use-renderer-pointer-down.ts
  - use-pixi-pointer-down-deselect.ts -> use-renderer-pointer-down-deselect.ts
- Rename hook functions:
  - usePixiPointsArray -> useRendererArray
  - usePixiPointerDown -> useRendererPointerDown
  - usePixiPointerDownDeselect -> useRendererPointerDownDeselect
- Update point-rendering.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Move event-to-renderer mapping from PixiPointRenderer to PointRendererBase
- Rename getPixiPointRendererDispatcher to getRendererForEvent
- Add registerDispatchedEvent() method for subclasses to use
- Remove unused hasWebGLContext prop from Graph component
- Update point-rendering.md documentation:
  - Fix usePointRendererArray description (maps, not graphs with multiple Y)
  - Clarify context recovery vs dynamic context limit in Future Considerations
  - Remove hasWebGLContext from examples

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove `any` types from DataTip, replacing with IPoint/IPointMetadata
- Change hideDataTip to use PointerEvent for consistency with showDataTip
- Rename event handlers from onPoint* to onPointer* (onPointerOver,
  onPointerLeave, onPointerClick, onPointerDragStart, onPointerDrag,
  onPointerDragEnd) since the pointer is moving, not the point
- Move PointRendererArray type to point-renderer-base.ts to avoid
  circular dependency with inline import
- Extract usePointRendererArray into its own file
- Rename IPixiDragHandlers to IRendererDragHandlers and
  usePixiDragHandlers to useRendererDragHandlers
- Remove CompatiblePointEventHandler type, use PointEventHandler instead
- Fix types in plot components (scatter-plot, case-plot, dot-chart,
  dot-line-plot, binned-dot-plot, map-point-layer)
- Fix case-plot drag to use renderer.setPointPosition() instead of
  direct property mutation
- Remove outdated comments about old/new API compatibility
- Update point-rendering.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
… maps

- Delete unused pixi-points.ts (legacy PixiPoints class)
- Delete use-renderer-array.ts (replaced by context-based approach)
- Remove unused getSpriteForPoint() and migration comments
- Rename PixiBackgroundPassThroughEvent to BackgroundPassThroughEvent
  and move to point-renderer-types.ts for broader applicability
- Add WebGL context management for map layers:
  - Add PointRendererArrayContext for sharing renderer settings
  - Add useLayerRenderer hook for child layers to get context-managed renderers
  - Update MapComponent/CodapMap/MapPointLayer to use new context system
- Add setupResizeObserver to PointRendererBase for post-init configuration

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add skipContextRegistration option to usePointRenderer to prevent unused
  primary renderer in usePointRendererArray from consuming context slots
- Add effect in MapPointLayer to refresh points when renderer changes
- Fix canvas replacement in MapPointLayer to clear old canvas before
  appending new one (old canvas was blocking new canvas from being added)
- Update point-rendering.md documentation with new hooks and patterns

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update Cypress helpers and fix test timing issues discovered during CI testing
of the point renderer refactoring.

Cypress helper updates:
- Update axis-helper, graph-canvas-helper, and map-canvas-helper to use
  new renderer API (rendererArrayMap, getPointsBounds, etc.)

Test stability fixes:
- Add waits after drag operations for graph/axis rendering to complete
- Re-select tiles after drag operations to ensure inspector panel updates
- Add existence checks before clicking inspector panel buttons
- Wait for cell values to change after formula rerandomize operations
- Split table.spec.ts into table.spec.ts and table-index.spec.ts for
  better parallelization

Code fixes discovered during testing:
- Fix D3 transition race condition in connecting lines by interrupting
  existing transitions before starting new ones
- Fix stale closure issue in showConnectingLines by reading from store
- Add console.log/warn/error capture in Cypress for debugging CI failures

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This plan outlines the approach for adding:
- CanvasPointRenderer: Canvas 2D fallback when WebGL contexts exhausted
- SVG export utility: Clean SVG generation for image export

The plan is intended for team review and discussion before implementation.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@codecov
Copy link

codecov bot commented Jan 19, 2026

Codecov Report

❌ Patch coverage is 77.49382% with 273 lines in your changes missing coverage. Please review.
✅ Project coverage is 69.39%. Comparing base (98bcf2b) to head (46addba).
⚠️ Report is 5 commits behind head on main.

Files with missing lines Patch % Lines
...nents/data-display/renderer/pixi-point-renderer.ts 61.45% 156 Missing and 19 partials ⚠️
...mponents/graph/plots/scatter-plot/scatter-plot.tsx 13.33% 12 Missing and 1 partial ⚠️
...isplay/components/no-webgl-context-placeholder.tsx 28.57% 10 Missing ⚠️
...onents/data-display/renderer/use-point-renderer.ts 89.15% 9 Missing ⚠️
.../src/components/map/components/map-point-layer.tsx 76.47% 8 Missing ⚠️
...ponents/data-display/hooks/use-connecting-lines.ts 22.22% 4 Missing and 3 partials ⚠️
...nents/data-display/renderer/point-renderer-base.ts 94.91% 6 Missing ⚠️
...s/data-display/renderer/point-renderer-context.tsx 44.44% 4 Missing and 1 partial ⚠️
.../components/data-display/components/background.tsx 55.55% 4 Missing ⚠️
...isplay/hooks/use-renderer-pointer-down-deselect.ts 55.55% 4 Missing ⚠️
... and 15 more

❗ There is a different number of reports uploaded between BASE (98bcf2b) and HEAD (46addba). Click for more details.

HEAD has 9 uploads less than BASE
Flag BASE (98bcf2b) HEAD (46addba)
cypress 10 1
Additional details and impacted files
@@             Coverage Diff             @@
##             main    #2299       +/-   ##
===========================================
- Coverage   86.69%   69.39%   -17.30%     
===========================================
  Files         724      733        +9     
  Lines       38770    39292      +522     
  Branches     9588     9688      +100     
===========================================
- Hits        33610    27266     -6344     
- Misses       5151    11288     +6137     
- Partials        9      738      +729     
Flag Coverage Δ
cypress 40.54% <63.77%> (-31.24%) ⬇️
jest 55.94% <37.01%> (+0.20%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@cypress
Copy link

cypress bot commented Jan 19, 2026

codap-v3    Run #9660

Run Properties:  status check passed Passed #9660  •  git commit 46addba789: docs: add implementation plan for Canvas and SVG renderers
Project codap-v3
Branch Review CODAP-295-canvas-svg-renderer-plan
Run status status check passed Passed #9660
Run duration 03m 13s
Commit git commit 46addba789: docs: add implementation plan for Canvas and SVG renderers
Committer Kirk Swenson
View all properties for this run ↗︎

Test results
Tests that failed  Failures 0
Tests that were flaky  Flaky 0
Tests that did not run due to a developer annotating a test with .skip  Pending 0
Tests that did not run due to a failure in a mocha hook  Skipped 0
Tests that passed  Passing 4
View all changes introduced in this branch ↗︎

@kswenson kswenson added the v3 CODAP v3 label Jan 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

v3 CODAP v3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants