The application itself is based around one main React component, App
. This component holds two key pieces of state:
- A
PointCanvas
- a Three.js scene that renders the points and tracks - A
TrackManager
- an object that manages loading and querying of tracks
The rest of the application controls are rendered by this component, and most are built from SDS and mui components.
The App
is the main component of the application. This component holds nearly all of the
required state. State is held in three categories:
-
Primary state that determines configuration of application (captured in the shareable URL)
canvas
- aPointCanvas
object that holds and manages the Three.js scenetrackManager
- aTrackManager
object that manages loading and querying of tracks
-
Additional state is held in this component
dataUrl
- the URL of the Zarr bundle (duplicate oftrackManager.store
)playing
- a boolean that determines if the viewer is playingisLoadingPoints
andnumLoadingTracks
- values to determine if the viewer is loading data
The canvas
object is managed via a reducer, which is responsible for updating the canvas state
based on changes from inputs and controls. This is created by a custom usePointCanvas
hook.
Data synchronization and fetching is handled in a series of effects (useEffect
hooks) that respond
to changes in the application or canvas
state.
Additionally, this component renders the actual canvas element and the controls for the application.
The PointCanvas
holds the Three.js scene (including points and tracks), camera, and renderer. It
is responsible for rendering the points and tracks, as well as handling user interactions (camera
movement and selection).
The usePointCanvas
hook is responsible for managing the state of the PointCanvas
object. This
hook creates a reducer that updates the PointCanvas
object based on actions dispatched by the
application. This hook also creates the sceneDivRef
reference that is used to attach the Three.js
canvas element to the DOM.
The Track
class is a modified Three.js Line2
object, which renders lines as an instanced
mesh. Each timepoint is rendered as a separate instance. This class is responsible for rendering the
tracks in the scene, including highlighting the track around the current timepoint. This works by
including a time
instanced attribute in the geometry as well as minTime
and maxTime
uniforms.
Together, these allow the shader to change the width and color of the line at each segment.
The TrackManager
class is responsible for loading tracks from the Zarr bundle.
This is just a wrapper around a series of ZarrArray
objects (using Zarr.js). This class
provides a simple interface for the basic queries required by the application:
fetchPointsAtTime
fetchTrackIDsForPoint
fetchPointsForTrack
fetchLineageForTrack
The SparseZarr
class is a wrapper around a Zarr array that is stored in CSR format. This class
provides a simple interface for fetching rows of the array. Each row requires two requests to the
Zarr array: one for the indptr
array and one for the indices
array. The SparseZarr
class also
handles basic caching of the indptr
arrays to reduce the number of requests required. Additional
caching is just left to the browser cache.
The ViewerState
class wraps the state of the application that is persisted in the URL. This class
contains the following properties, taken from both the Scene
and PointCanvas
state:
dataUrl
- fromTrackManager
curTime
- fromPointCanvas
minTime
andmaxTime
- fromPointCanvas
(highlighted portion of tracks)maxPointsPerTimepoint
- fromPointCanvas
pointBrightness
- fromPointCanvas
showTracks
- fromPointCanvas
showTrackHighlights
- fromPointCanvas
selectedPointIds
- fromPointCanvas
cameraPosition
- fromPointCanvas
cameraTarget
- fromPointCanvas
This class also provides methods for updating the state from the URL and for generating a shareable URL from the current state.