MultiWaySyntenyDisplay
Auto-generated @jbrowse/mobx-state-tree API for the current JBrowse release — see pluggable elements for concepts. Provided by the linear-comparative-view plugin. View source.
draws a multi-genome ortholog track (an adapter whose features carry a
mate per other assembly, e.g. MCScanBlocksAdapter) as one lane per
assembly inside a plain linear genome view. The top lane is the view's own
assembly at genomic coordinates; every other lane is laid out in its own
local coordinate frame fitted to the viewport — non-anchored, the same move
the multi-sample variant matrix makes — with ribbons connecting each gene's
placements between adjacent lanes. The ribbons ride the pairwise synteny
display's GPU passes and the lanes the feature track's, with Canvas2D and
the SVG export drawing the same cells.
The configuration slots for this model are documented on its config schema page.
Members a composed model contributes are listed here too, so these tables are the whole surface.
Properties
| Member | Description | Defined by |
|---|---|---|
typetype: types.literal('MultiWaySyntenyDisplay') | MultiWaySyntenyDisplay | |
configurationconfiguration: ConfigurationReference(configSchema) | MultiWaySyntenyDisplay | |
| lodMode | Level-of-detail tier selection for tiered PIF adapters, the setting the synteny view, dotplot and LGVSyntenyDisplay carry under the same name: 'auto' uses the adapter's bpPerPx threshold; 'fine' pins the per-row CIGAR tier; 'coarse' the tier whose CIGAR is folded to its large indels | MultiWaySyntenyDisplay |
rowOrderrowOrder: types.array(types.string) | lanes to pin to the top, in order; lanes it does not name follow densest-first, so the chain a ribbon draws through adjacent lanes is cut as late as possible and most stacks need no order authored at all. A declared property, so it is authorable from a session spec or a config defaultSession | MultiWaySyntenyDisplay |
hiddenLanes: types.array(types.string) | mate lanes taken out of the stack, so a genome that places nothing in the region of interest stops holding a slot between two that do | MultiWaySyntenyDisplay |
selectedLanesselectedLanes: types.maybe(types.array(types.string)) | the lanes the reader chose from the picker, by assembly name, and the only lanes the stack then draws; undefined is every lane the source places, or the config's lanes where that names some. Held here rather than in the adapter's config because it is a choice about this session's picture, made in front of it, and one a shared session should carry | MultiWaySyntenyDisplay |
idid: ElementId | BaseDisplay |
Volatiles
| Member | Description | Defined by |
|---|---|---|
featuresfeatures: undefined as Feature[] | undefined | MultiWaySyntenyDisplay | |
laneGeneslaneGenes: undefined as Map<string, HeldLaneGenes> | undefined | per lane, the gene models fetched from that assembly's own gene track, so a lane draws real exon structure at that genome's coordinates, and the region key they were fetched under — the lane fetch's committed stamp, which its gate compares and dataSuperseded reads per lane. Merged a lane at a time: a pan that moves one lane's quantized window refetches that lane and leaves the others' genes as they were | MultiWaySyntenyDisplay |
laneGenesCoverMatesForlaneGenesCoverMatesFor: undefined as string | undefined | the anchor assembly under which a lane-gene commit has covered a MATE lane. The anchor's spec exists as soon as the view does, so the first commit can be the anchor alone, before the ortholog fetch has given any mate a frame; the lanes' first real filling is the commit after that, and it is the one a capture has to wait for. Keyed by anchor so a re-anchor onto another genome waits again | MultiWaySyntenyDisplay |
laneLinkslaneLinks: undefined as Map<string, HeldLaneLinks> | undefined | alignments between ADJACENT mate lanes, fetched per pair from the same track when the source is an all-vs-all alignment file — the direct records the file holds for that pair, at the lanes' own coordinates — each beside the region key it was fetched under, merged per pair | MultiWaySyntenyDisplay |
declaredLanesdeclaredLanes: undefined as DeclaredLane[] | undefined | the lanes the source's header declares, read once with the tier info; undefined until the header lands or when the adapter is one whose header is never asked for | MultiWaySyntenyDisplay |
starAnchorstarAnchor: undefined as string | undefined | the anchor a star source announces in its header. A star of pairwise alignments holds no mate-vs-mate rows, so its adjacent pairs' links are composed through the anchor rather than asked for | MultiWaySyntenyDisplay |
hoverTargethoverTarget: undefined as HoverTarget | undefined | the glyph, box or ribbon under the pointer — what a click opens and the tooltip names | MultiWaySyntenyDisplay |
| clickedTarget | clicked twin of the hover: the group or direct-link ribbon whose outline stays after the pointer leaves it, cleared by a click on empty canvas or a refetch | MultiWaySyntenyDisplay |
laneDecisionslaneDecisions: new Map<string, LaneDecision | undefined>() | what the last settle decided per mate lane — contig, orientation, rung and where the lane is pinned to the anchor. Made once per settled block set by the installer in afterAttach, holding each choice until the evidence clearly moves; the frames the lanes draw in are derived from these against the live view | MultiWaySyntenyDisplay |
pinnedLaneContigspinnedLaneContigs: new Map<string, string>() | the contig the reader pinned a lane onto from its header menu, which outranks the lane's own vote while the window still places anything on it. Volatile like the decisions it steers: a pin is a choice about this window, and the lane falls back to choosing once the pinned contig explains nothing here | MultiWaySyntenyDisplay |
renderOriginPxrenderOriginPx: 0 | the view's scroll offset the stack is laid out against, refreshed with the decisions. Between refreshes a pan is one translate of the whole stack (dragOffsetPx), not a relayout of every lane | MultiWaySyntenyDisplay |
errorerror: undefined as unknown | BaseDisplay | |
statusMessagestatusMessage: undefined as string | undefined | BaseDisplay | |
statusProgressstatusProgress: undefined as number | undefined | determinate progress fraction [0,1] for the current status, or undefined when the in-flight phase is indeterminate. Set alongside statusMessage by setStatusMessage; a display that never shows a bar simply leaves it undefined. | BaseDisplay |
scrollTopscrollTop: 0 | TrackHeightMixin | |
forceLoadTrackforceLoadTrack: false | The force-load button's track-wide approval. Volatile so it never reaches a saved session; the forceLoad config slot is the durable form. | RegionTooLargeMixin |
byteEstimatebyteEstimate: undefined as ByteEstimate | undefined | The last byte measurement: bytes, the span they were taken at, and whether zooming has been shown not to shrink them. Survives clearAllRpcData; dropped on chromosome navigation and on a tier swap. | RegionTooLargeMixin |
gateMeasuredViewportKeygateMeasuredViewportKey: undefined as string | undefined | The gateViewport key the gate last asked the adapter about, on either axis — the viewport AND the settings it asked under. Separate from byteEstimate because a density refusal measures no bytes. | RegionTooLargeMixin |
canvasDrawncanvasDrawn: false | flips true on first paint; read by test selectors to detect render | RenderLifecycleMixin |
currentRenderingBackendcurrentRenderingBackend: undefined | current backend reference, updated on context-loss recovery. Typed unknown (not generic B) on purpose: this mixin is composed by every display via a non-generic factory, so the per-display backend type B isn't known here — it's supplied at attachRenderingBackend<B> and narrowed with as B inside the autoruns. Don't "fix" the cast. | RenderLifecycleMixin |
renderTickrenderTick: 0 | counter the render autorun observes; bumped to force a re-render | RenderLifecycleMixin |
autorunsInstalledautorunsInstalled: false | guards attachRenderingBackend so the autorun pair spawns once per instance | RenderLifecycleMixin |
renderErrorrenderError: undefined | the render-backend (GPU/Canvas2D init or context-loss) error, or undefined. Single source of truth for the render-error terminal state: useRenderingBackend writes it from the canvas-init mechanism so the model — not React-local hook state — owns every terminal state. Read by displayPhase (whose renderError term outranks loading, suppressing the scrim) and by DisplayChrome (shows the retry overlay). | RenderLifecycleMixin |
loadedFetchKeyloadedFetchKey: undefined as string | undefined | currentFetchKey as it stood when the held data was committed — the loaded half of the freshness compare. Written only by commitFetchResult, so a display cannot stamp data it did not fetch, and cleared by reload for the overlay's sake rather than the refetch's (the skeleton's reload epoch is what overrides its gate). The data itself stays display-owned: arc keeps stale arcs on screen under the loading overlay, HiC the stale matrix, synteny the stale ribbons. | KeyedFetchMixin |
activeStopTokenactiveStopToken: undefined as StopToken | undefined | stop token of the in-flight fetch, or undefined when idle | FetchMixin |
fetchGenerationfetchGeneration: 0 | bumps at every fetch end; autoruns read it to re-evaluate, and it doubles as the staleness epoch inside runFetch | FetchMixin |
reloadCounterreloadCounter: 0 | Bumped by reload() and read unconditionally by the fetch autoruns, so a user retry re-runs the body even where nothing else moved — after an error every other fetch input is unchanged. It is also the half that survives a reload() override that forgets to invalidate, which is the dead Retry button makeRetryContractCheck reports. Declared here because this is the one mixin every fetch foundation composes, the same argument that put fetchInert below; the comparative family carried its own until ADR-105. | FetchMixin |
statusWindowstatusWindow: createStatusWindow(writeStatus(self)) | This display's status field, and the only thing that writes it: one throttle window, one slot per concurrent operation, so N parallel per-region fetches thin to one stream between them rather than N and a second operation cannot end the first one's label (ADR-081). Lent whole to createStopTokenRotation by a display that also runs a bare-autorun fetch — see StatusReporter. | FetchMixin |
fetchCanceledfetchCanceled: false | true after the user explicitly cancels a load (the loading overlay's cancel button → cancelFetchByUser). A durable, blocking state — unlike cancelFetch, it does not retrigger the fetch autoruns — so the load stays stopped until the user retries (reload) or the viewport changes. Any new fetch clears it (runFetch resets it at the start). | FetchMixin |
| fetchRotation | The latest-wins machine this mixin is a wrapper around, and not a second one: createStopTokenRotation owns token rotation, the isCurrent guard, the status slot and the supersede-versus-end rule (ADR-080, ADR-081), for every fetch in the codebase that has one. runFetch adds the observable bookkeeping a display needs on top — isLoading, error, fetchGeneration, fetchCanceled — and nothing else.It was two implementations of that machine until 2026-08-20, which is how they came to disagree about whether a completed fetch releases its token. A display's primary fetch is this wrapper; a second concurrent fetch on the same node holds a rotation of its own, which is why the primitive is the thing that exists and this is the thing built on it (ADR-054 §1, the one section ADR-105 keeps). It is lent this display's statusWindow, so the fetch takes a slot on the one field rather than opening a second window over it — the whole point of StatusReporter. | FetchMixin |
lodTierInfolodTierInfo: undefined as LodTierInfo | undefined | LodTierInfoMixin |
Getters
| Member | Description | Defined by |
|---|---|---|
| lgv | the hosting linear genome view. GlobalFetchMixin hands down the view-shaped host its own gating needs; a display reaching LGV's own geometry names it itself, the way the arc displays do | MultiWaySyntenyDisplay |
hoveredGroupKeystring | undefined | the ortholog group under the pointer; every ribbon of that group highlights, so one hover reads the group across all lanes | MultiWaySyntenyDisplay |
hasLodCapableAdapterboolean | whether the track's adapter has tiered storage to switch between — gates the "Level of detail" menu, the way LGVSyntenyDisplay gates it | MultiWaySyntenyDisplay |
lodTierLodTier | the tier the ortholog and lane-link fetches ask an indexed PIF for, resolved here on the main thread off the SETTLED zoom and folded into viewSignature, so a tier flip refetches and a gesture travelling through the threshold does not. 'fine' at every zoom for an adapter with no tiers, a gene table included | MultiWaySyntenyDisplay |
liveLodTierLodTier | the same tier off the live zoom, for dataSuperseded | MultiWaySyntenyDisplay |
canvasWidthnumber | MultiWaySyntenyDisplay | |
viewSignaturestring | undefined | staleness axes are the static-block set, same as arc — pan/zoom past a block boundary refetches, a scroll inside the loaded blocks does not — and the level-of-detail tier | MultiWaySyntenyDisplay |
groupsMultiWayGroup[] | anchor-sorted gene groups reconstructed from the pairwise features | MultiWaySyntenyDisplay |
featuresAreNamelessboolean | a gene-level source names its features and groups chain on the names; an alignment-level source (all-vs-all PAF) names nothing, which is what makes the per-pair link fetch worth issuing | MultiWaySyntenyDisplay |
ribbonColorstring | MultiWaySyntenyDisplay | |
ribbonColorByMultiWayRibbonColorBy | MultiWaySyntenyDisplay | |
drawCurvesboolean | MultiWaySyntenyDisplay | |
bridgeSkippedLanesboolean | MultiWaySyntenyDisplay | |
showLaneTicksboolean | MultiWaySyntenyDisplay | |
ownFeatureIdsSet<string> | every feature id a lane can draw — the group features and the lane genes, which is what laneGlyphCells colors. Rebuilt per fetch commit, not per frame | MultiWaySyntenyDisplay |
glyphColors{ color: Map<string, string>; utrColor: Map<string, string>; } | the color and utrColor slots resolved per feature a lane draws — every lane's genes, and the groups' own records for the placement boxes — keyed by feature id. Off the fetched sets and the config alone: a settle rebuilds every lane's cells against this map, so a settle runs no jexl | MultiWaySyntenyDisplay |
selectedFeatureIdstring | undefined | the session selection where it names a feature THIS display draws, else undefined — the gate that keeps a selection in some other track from recomputing and re-uploading every lane's glyph cells, since an unchanged undefined invalidates nothing downstream | MultiWaySyntenyDisplay |
anchorAssemblyNamestring | MultiWaySyntenyDisplay | |
adapterDeclaresLanesboolean | whether the adapter type says its header declares the lane universe (adapterCapabilities: ['headerLanes']), which is what earns an untiered adapter a header read | MultiWaySyntenyDisplay |
laneSelectionreadonly string[] | undefined | the lanes in force: the reader's choice, else the config's lanes where it names any, else undefined for every lane the source places | MultiWaySyntenyDisplay |
| anchorAssembly | MultiWaySyntenyDisplay | |
anchorLocStringstring | MultiWaySyntenyDisplay | |
laneUniverseLaneChoice[] | every lane the picker can offer: the header's declared lanes, in the order the source gave them, then any lane the fetched window places that the header did not name. The anchor is never a lane. Exact names throughout, since the header and the features are one adapter's spelling of the same lanes | MultiWaySyntenyDisplay |
rowAssembliesstring[] | mate assemblies densest-first, one lane each below the anchor lane, with any rowOrder lanes pinned above them, narrowed to the lane selection where one is in force. A paralogy record's mate is the anchor assembly itself; those draw on the anchor's own axis rather than as a lane | MultiWaySyntenyDisplay |
visibleBpSpannumber | MultiWaySyntenyDisplay | |
visibleGroupsMultiWayGroup[] | the groups whose anchor placement is inside the settled viewport — the population every lane's local frame is fitted to, so panning the anchor re-lays-out the other lanes | MultiWaySyntenyDisplay |
tickIntervalBpnumber | the one bp interval every lane draws its ticks at, so tick spacing is readable as bp-per-pixel across lanes drawn in different frames | MultiWaySyntenyDisplay |
scrollContentHeightnumber | the stack's full drawn height: the track height until a lane would fall under the minimum pitch, then fixed-pitch and taller than the viewport — what the scrollbar is sized against | MultiWaySyntenyDisplay |
laneGeneAdaptersMap<string, Record<string, unknown>> | per lane, the session's own gene track for that assembly: the best-ranked feature track declared for it alone. The real pipelines this display connects to (jcvi MCScan, HPRC CAT) derive their gene BEDs from exactly these annotations, so the lane's exon structure comes from the file the table was built from. RANKED, not a set. GFF3 only was too narrow — a lane annotated by a GTF or a BigBed read as · no annotation, which is the header asserting something false about a track sitting in the same session, with no error to debug from. But a flat widening picks by declaration order, and the config shape this display meets (hg38-genes beside hg38-rmsk) has the repeats in BED and the genes in GFF3 — so "anything with features" would newly prefer the repeats. Rank instead, and the old behaviour is what the top rank already gives. | MultiWaySyntenyDisplay |
scrollableHeightnumber | TrackHeightMixin's hook: 0 — no scroll, today's divide-the-height layout — until the lane count pushes the stack past the track height | MultiWaySyntenyDisplay |
anchorPlacementsMap<string, AxisPlacement> | where the view draws each visible group's anchor interval, in the view's px before the scroll offset and in the anchor's own direction — start end first, so a horizontally flipped view hands the ribbons the crossed pair it is drawing — with the clipped interval's centre as the coordinate a lane decision can pin to. The view's own bpToPx through axisPlacement, which is the only honest answer: it is piecewise over the displayed regions and no RowFrame can stand in for it. Read both by the lane-alignment seed and by the anchor lane's own ribbons, so "the lanes line up against where the anchor actually draws" holds by construction rather than by two loops agreeing | MultiWaySyntenyDisplay |
dragOffsetPxnumber | how far the view has scrolled since the stack was laid out: the one live read a pan makes, applied as a translate over the whole stack | MultiWaySyntenyDisplay |
anchorReversedboolean | the anchor axis reads right to left: a horizontally flipped view. A lane's decision is stated against the anchor's order, so this mirrors every lane with the anchor without a re-decision | MultiWaySyntenyDisplay |
anchorSpansMap<string, Span> | the anchor placements in the stack's own px: what the anchor lane draws and what every ribbon out of it starts from | MultiWaySyntenyDisplay |
anchorAbsXMap<string, { coord: AnchorCoord; x: number; }> | the first link of the alignment chain: each visible group's anchor centre and the view's px for it BEFORE the scroll offset, so a settle decision reading this does not re-run on every pan | MultiWaySyntenyDisplay |
rowFramesMap<string, RowFrame | undefined> | each mate lane's local coordinate frame: the settle's decision against where the view draws its pivot now | MultiWaySyntenyDisplay |
laneGenesFetchSpecsLaneGenesFetchSpec[] | what the lane-genes autorun fetches: one spec per lane with a gene track, over the quantized window each lane's frame slides in | MultiWaySyntenyDisplay |
laneLinksFetchSpecsLaneLinksFetchSpec[] | one spec per ADJACENT mate-lane pair when the source is an all-vs-all alignment file: the upper lane's window queried against the lower lane's assembly at the settled tier, which an all-vs-all adapter answers with the direct records it holds for that pair. None for a source that announced itself a star, which holds no such rows. Only pairs the session holds both assemblies of: the fetch renames its region through the assembly manager, which refuses a PanSN sample the config never declared, and an all-vs-all file routinely carries more of those than the config names | MultiWaySyntenyDisplay |
laneStackLaneStack | the stack the picture is drawn from: one Lane per assembly, plus the geometry every layer places against. Every layer — bands, ticks, ribbons, glyphs, boxes, headers, the hover outline — is a walk over this, and the on-screen body and the SVG export walk the same one. The lane genes are not in it: only the glyph cells read them, and a stack that carried them re-uploaded every ribbon and tick, and dropped the hover, on every gene commit | MultiWaySyntenyDisplay |
pairLinksReadonlyMap<string, { links: Feature[]; }> | the direct records between each adjacent mate-lane pair as the ribbons read them: the pair's fetched links where the file holds any, else — a star of pairwise alignments states none, whether it announced itself one or its pair fetch came back empty — the links composed through the anchor from the groups, one record per placement either lane makes. Off the fetched sets alone, never the frames, so a settle recomposes nothing | MultiWaySyntenyDisplay |
paletteJBrowsePalette | MultiWaySyntenyDisplay | |
ribbonGeometryRibbonGeometry | the ribbons between each adjacent lane pair as the synteny passes' instance data, in the stack's own px, plus what each ribbon opens | MultiWaySyntenyDisplay |
tickGeometryTickGeometry | MultiWaySyntenyDisplay | |
bandCellMultiWayCell | the opaque bands under the mate lanes, off the lane geometry rather than the stack: the stack moves on every pan and settle, the bands only when a lane comes or goes, and an unchanged cell uploads nothing | MultiWaySyntenyDisplay |
laneGlyphCellsMap<string, MultiWayCell> | two cells per lane — its gene models and baseline, and its placement boxes — since only the boxes carry an outline. Boxes first, so a hit test walking these in order answers the box over the gene the way the draw order does. Colors come off glyphColors, so neither the hover — a render parameter — nor a settle re-runs a jexl slot | MultiWaySyntenyDisplay |
renderCellsReadonlyMap<string, MultiWayCell> | everything the backend holds bytes for, keyed so an unchanged cell keeps its identity across a rebuild of the map and uploads nothing | MultiWaySyntenyDisplay |
renderLayersMultiWayLayer[] | the stack back to front: bands under everything, since they exist to cover the view's gridlines; ribbons; each lane's ticks; each lane's glyphs over its own ribbons | MultiWaySyntenyDisplay |
hoveredFeatureIdnumber | the ribbon feature id the passes highlight: every ribbon of the hovered group shares one, so a hover over any gutter lights the group in all of them | MultiWaySyntenyDisplay |
clickedFeatureIdnumber | the clicked twin, resolved the same way — a group key survives a relayout, a direct-link index only its own fetch | MultiWaySyntenyDisplay |
hoveredGroupOutlines{ lane: Lane; span: Span; }[] | the hovered group's placement in every lane that places it | MultiWaySyntenyDisplay |
renderStateMultiWayRenderState | what a frame draws with: the cells' layout and the one live transform | MultiWaySyntenyDisplay |
awaitingDependentDataboolean | FetchMixin's hook: the dependent fetches are part of loading until they FIRST land, so an export or a capture never lands between the ortholog fetch and the gene models that fill the lanes. Not for later refetches: those run over lanes that are already drawn, and holding the phase at loading puts the striped scrim over them. A failed lane fetch commits an empty result rather than hanging this (see afterAttach).The first landing is the first one that names a mate lane, not the anchor-only commit that can precede it: the anchor's spec exists before the ortholog fetch has framed any mate, so a phase that read ready off that commit let a capture shoot placement boxes while seven lanes were still downloading their indexes (the primate amylase figure, 2026-09-02) | MultiWaySyntenyDisplay |
dataSupersededboolean | GlobalFetchMixin's hook: a lane fetch is out, or some lane holds a result fetched under a key its frame has moved past, so the ortholog data the signature calls current is about to be redrawn over; or the live zoom has left the settled tier the held data was fetched at. Holds the export, where the phase above holds only the first landing's scrim. A lane fetch always commits — one failed lane is stamped with an empty result (see afterAttach) — so this cannot latch | MultiWaySyntenyDisplay |
hoveredFeatureFeature | undefined | BaseDisplay's hook, what the view publishes to session.hovered | MultiWaySyntenyDisplay |
parentTrackAbstractTrackModel | BaseDisplay | |
RenderingComponentFC<…> | BaseDisplay | |
| DisplayBlurb | BaseDisplay | |
adapterConfigRecord<string, unknown> | BaseDisplay | |
isMinimizedboolean | Returns true if the parent track is minimized. Used to skip expensive operations like autoruns when track is not visible. | BaseDisplay |
featureNounstring | Overridable hook (default 'feature'): the SINGULAR word for one of the things this display draws, as a menu row or a chip says it — "Hide this read", "Showing 3 variants".Declared here for the same reason as hoveredFeature above: it is read across the display boundary, by chrome that has no idea which display it is drawing for (SoloSelectionChip, alignments' group-label overlay), and a name only the base declares is a name every such consumer can rely on. Two displays declared it independently and one of those declarations WAS this default.A control keeps the generic word; content takes this one. "Variant height" reads as a different setting from "Feature height" when it is the same one, so the shared menus stay on "feature" however the display answers here, and the noun varies where it names what the user is looking at — "Showing 3 variants", "Hide this read". A display drawing something the generic word already fits is right to leave this alone. Distinct from the per-hit noun a context menu takes off the clicked item's own type ("mRNA", "gene"); that names one annotation, this names what the track holds. The hit noun falls back to this. | BaseDisplay |
featureWidgetType{ type: string; id: string; } | Overridable hook: which widget openFeatureWidget opens for one of this display's features. The default is the generic one, which is what a display drawing plain features wants and what the canvas base spelled out by hand.An override is a display whose features have a vocabulary of their own — a read, a variant, a synteny block — and the id is deliberately part of it: two displays naming one id share the drawer panel, which is the behaviour when the two are showing the same kind of thing. | BaseDisplay |
heightnumber | TrackHeightMixin | |
resizingboolean | True for the duration of a height drag on this track, whichever handle is running it. A display whose row geometry is a function of the track height restretches every row per animation frame, and can use this to sit an expensive per-frame layer out of the drag (MAF's dense per-base letter overlay is a Canvas2D pass that scales with rows x columns). The flag itself is the track's ( BaseTrackModel), so the view brackets a drag without needing the active display to have opted into this mixin. Reading it here is what makes self.resizing available to a display that did. | TrackHeightMixin |
hostRegionHost | The hosting view as the RegionHost contract — see containingHost for the cast it owns, why the name is host and not view, and why both foundations still declare the name over one body. | GlobalFetchMixin |
staticBlockSignaturestring | undefined | The static-block set as a signature, or undefined before the view is measured — the building block every viewSignature in this family starts from. Arc and multi-way synteny are exactly this; HiC appends its resolution. Declared here so the initialized gate is spelled once. | GlobalFetchMixin |
dynamicBlockSignaturestring | undefined | The same over dynamicBlocks, for a display whose fetch window is the live viewport rather than the snapped block set (LD). | GlobalFetchMixin |
viewportEmptyboolean | No content block is on screen, so this display has nothing to fetch and nothing to paint — see viewportEmpty.ts for the one viewport that reaches it, how narrow that is, and why the state still has to be terminal rather than a permanent scrim. Both foundations declare it over that one expression, the same way they each declare host and paintInert. | GlobalFetchMixin |
canRenderboolean | Overrides RenderLifecycleMixin's default-true hook with the LGV precondition both foundations share — see foundationCanRender. | GlobalFetchMixin |
rendersCanvasboolean | Fills RenderLifecycleMixin's hook off fetchInert: a display that will never fetch here shows a placeholder where its canvas would be, so painted and the pre-first-paint scrim term stop waiting on a paint that cannot come. Sequence and LD each carried this as a second override beside fetchInert, always its negation. | GlobalFetchMixin |
paintInertboolean | Fills RenderLifecycleMixin's paintInert hook — see there for why a failed fetch has to read as finished to the consumers outside the display, and foundationPaintInert for the second such state and why both fetch families answer it through one function. Overridable, as the hook is: a display with a third inert state of its own says so here. | GlobalFetchMixin |
svgReadyboolean | Policy single-sourced in computeSvgReady; this family supplies only the freshness half, which foundationSvgReady reads as dataCurrent or the vacuous currency of viewportEmpty. Note it requires the dataset to actually be current, NOT merely "not currently fetching": the fetch trigger is a debounced afterAttach autorun, so at export time isLoading can still be false with no data yet — a displayPhase !== 'loading' test would then capture an empty render. Never gates on canvasDrawn, which an off-screen export never sets. Off-screen renderers gate on it via awaitSvgReady(model). | GlobalFetchMixin |
displayPhaseDisplayPhase | The display's mutually-exclusive visual state, mapped in foundationDisplayPhase — every foundation calls it and supplies only its staleness argument, so a term added to computeLoadingTerm reaches all of them without being wired twice.This family's argument is the constant true, deliberately: a global display keeps the last frame up through a refetch (worker output is genomic, so the stale frame draws correctly under the live view transform), so a pan or zoom shows no scrim beyond the isLoading window. The pre-first-paint scrim it does want — the gap between mount and isLoading going true, which on HiC is the CoreGetInfo round trip its first fetch waits on — is computeLoadingTerm's shared rendersCanvas && !canvasDrawn term, not anything this family spells out.A display with no rendering backend narrows this to the backend-free DisplayStatusPhase with foundationDisplayStatusPhase, which is what arc does: it cannot reach renderError, and the narrower type is what lets DisplayStatusChrome take it with neither a cast nor a dead branch. | GlobalFetchMixin |
gateEnabledboolean | The opt-in. Overridden with a literal true by gated displays, and check-gated-adapter-budgets insists on a literal: this mixin returns early on it in an autorun and in commitFetchBytes. | RegionTooLargeMixin |
byteGateAdapterConfigRecord<string, unknown> | The adapter config the gate measures — the one at byteGateAdapterPath. Overridable for a display whose adapter config is synthesized rather than read off the track. | RegionTooLargeMixin |
configuredFetchSizeLimitnumber | undefined | The display's fetchSizeLimit slot, from regionTooLargeConfigSchemaFields. number | undefined, because getConf answers undefined for a slot a composing display's schema never declared and typing it number hid the whole failure — resolveByteLimit falls back closed, and says why. | RegionTooLargeMixin |
densityTooLargeboolean | The density axis's verdict, and the whole of that axis's opt-in: CanvasFeatureGateMixin overrides it beside the measurement that fills it, and a byte-only display leaves it false. | RegionTooLargeMixin |
byteGateAdapterPathstring[] | Where on the track config the measured adapter sits. A tiered display overrides this one hook (MAF: ['adapter', 'summaryAdapter'] while showSummary), and both the measurement and the budget follow it. | RegionTooLargeMixin |
adapterFetchSizeLimitnumber | undefined | The measured adapter's own fetchSizeLimit slot, read off the live track config rather than the adapterConfig snapshot, which omits slots at their default. | RegionTooLargeMixin |
configForceLoadboolean | The declarative forceLoad slot. | RegionTooLargeMixin |
gateViewportGateViewport | undefined | What a measurement taken now would be about: the span on screen, and a key for the stretch of genome it covers and the settings it would be taken under. Undefined until the view is measured, and the mixin's only read of the view. Captured before the fetch's round trip, never at commit, so the stamp names the settings the worker actually counted under. The settings term is rpcPropsCacheKey, the axis both families already invalidate data on. It belongs in the measurement because the worker's density probe counts ADMITTED features (densityGate's admit), so a filter admitting almost nothing is a different measurement of the same viewport — and while staleness was viewport-only, the main thread never went back to ask. The byte axis is an index read no rpcProps field can move; the rule is one rule rather than one per axis. | RegionTooLargeMixin |
byteGateAdapterKeystring | Which tier the estimate is about, as a comparable string. | RegionTooLargeMixin |
aboveForceLoadFloorboolean | Whether the span on screen is at or above AUTO_FORCE_LOAD_BP, the one comparison against that constant. False on an unmeasured view. | RegionTooLargeMixin |
gateExemptboolean | Nothing may gate on either axis: the forceLoad slot or the button. | RegionTooLargeMixin |
estimatedFetchBytesnumber | undefined | The stored estimate's bytes; undefined when nothing has been measured. | RegionTooLargeMixin |
gateMeasurementStaleboolean | Whether the last measurement still describes what a fetch issued now would ask: the viewport on screen, under the settings on screen. True before any measurement. The triple's third term, the adapter tier, is not here — a tier swap drops the measurement outright (ClearByteEstimateOnNavOrTierSwap) rather than marking it stale. | RegionTooLargeMixin |
gateByteLimitnumber | The byte budget: the adapter's limit, else the display's, doubled below AUTO_FORCE_LOAD_BP. Read only through resolvedByteLimit(). | RegionTooLargeMixin |
gateActiveboolean | Whether the gate may act right now, on any axis: opted in, not exempt, view measured. The view is read last, so an ungated display never touches it. | RegionTooLargeMixin |
densityGateActiveboolean | Whether the density axis may act: gateActive, and the span is above the floor — the one axis the floor applies to. Whether it has anything to say is densityTooLarge. | RegionTooLargeMixin |
tooLargeStatusRegionTooLargeStatus | The verdict and its banner text, from the stored estimate against resolvedByteLimit() and the density axis when it may act. | RegionTooLargeMixin |
regionTooLargeboolean | RegionTooLargeMixin | |
regionTooLargeReasonstring | Banner text for the axis that tripped; empty when not too large. | RegionTooLargeMixin |
zoomCanReleaseGateboolean | Whether "zoom in to see features" is honest advice. Density always releases on zoom; bytes only if the last zoom-in moved the estimate. | RegionTooLargeMixin |
gateSkipsMeasuredViewportboolean | The skip both fetch skeletons apply: the banner is up and its measurement already describes the viewport on screen. | RegionTooLargeMixin |
paintSupersededboolean | Overridable hook (default false): what is on the canvas was painted from data a later change has made wrong, so painted below should answer pending until the repaint lands even though canvasDrawn is still true. The per-region fetch foundation fills it with staleSettingsDrawn — held data drawn under settings that have since moved — which is the state clearAllRpcData used to express by resetting canvasDrawn on every settings change, blanking the display to do it. A capture waiting on data-display-drawn then waits for the refetch rather than snapshotting the previous setting's pixels.A hook and not a reset of the flag, because the flag is re-marked by any redraw — a pan between the settings change and the refetch would report the stale canvas drawn — and a derivation cannot be raced. | RenderLifecycleMixin |
paintedboolean | The first-paint answer every consumer outside the display should read, canvasDrawn being only the raw flag: a display that is deliberately not painting a canvas has finished, and saying otherwise is a lie that never resolves.The two rendersCanvas: false states each had three of their four consumers wired by hand — the loading scrim (rendersCanvas / fetchInert) and the SVG export (fetchInert) — while the fourth, data-display-drawn, went on publishing "false" forever off the raw flag. That attribute is what PENDING_DISPLAYS (@jbrowse/browser-test-utils) selects on, so a zoomed-out reference sequence track made every waitForDisplaysDone on the page burn its full timeout — silently, since that wait swallows its own. Same shape as fetchInert on the comparative side: the reader you forget is the one outside the display, so the display has to publish one name for it.paintInert is the third term and the same argument once more, for the state where a display would paint a canvas and never gets to — a fetch that failed before first paint. paintSuperseded is the fourth, and the one that subtracts: a canvas painted from data a settings change has made wrong is drawn and not finished. See both hooks. | RenderLifecycleMixin |
currentFetchKeystring | undefined | Key of the fetch the current view, settings and adapter call for — the display's viewSignature plus the serialized rpcProps() axis plus the adapter config. The fetch skeleton's freshness key: captured at issue, compared against the stamp above, and written to it at commit. | KeyedFetchMixin |
dataCurrentboolean | The shared freshness answer every foundation gives: data has been committed (loadedFetchKey is only ever written beside it), it was fetched for the current view and settings, and the display is not about to supersede it itself. A pan inside the loaded blocks stays current; a block entering, a tier step, a settings change or a reload() moves one side of the compare. What the fetch autorun gates on is the same compare inside installFetch, not this getter — the skeleton owns it so a reload can override it. This one is for the readers outside the fetch, the export gate above all. The per-region twin is isCacheValid: what decides a refetch, and deliberately not the whole freshness answer. | KeyedFetchMixin |
isLoadingboolean | true while a fetch is active | FetchMixin |
isLoadingOrCanceledboolean | isLoading widened to cover a user-canceled load. This, not isLoading, is what a displayPhase loading term wants. cancelFetchByUser clears the stop token synchronously, so isLoading goes false the instant the user clicks Cancel — and the loading overlay that unmounts on it is carrying the Retry button, which is the only way back: the state is deliberately durable, so no autorun restarts the fetch on its own. A bare isLoading therefore reads as ready over a display that is stopped, empty and offering nothing.Arc read isLoading directly and had exactly that hole. It is a getter here so no family has to remember the second term. | FetchMixin |
fetchInertboolean | Overridable hook (default false): the states where this display deliberately never fetches, so it holds no data and none is coming. Sequence sets it past base resolution ("Zoom in to see sequence"); LD sets it with the triangle toggled off. One hook, three readers, and that is the whole point — a display that grows such a state has one thing to say rather than three, and the reader it would have forgotten is always the one outside itself: - the loading scrim ( computeLoadingTerm), which otherwise parks over the placeholder, permanently once a cancel has been clicked; - the SVG export (computeSvgReady's extraTerminal), whose awaitSvgReady is an unbounded when, so one such display hangs the whole view's export; - the retry contract check (makeRetryContractCheck), which would otherwise report a dead Retry on a display correctly declining to load anything.It was three hooks — loadingSuppressed, svgReadyExtraTerminal on each of the two foundations, and fetchInert on the comparative family, which had already collapsed them. Both LGV displays that override it returned one expression for all three, and one of the three was hard-coded false on the global family for a while, which is how LD came to be able to express only half its own state. One declaration for all three fetch families since the comparative one composed this mixin (ADR-105), so the retry check reads one field everywhere. ADR-082.A hook rather than a displayPhase override, because overriding the getter means restating the whole loading condition — which is how sequence came to hold a verbatim copy of the other terms, one git blame away from silently missing the next one added.It lives here because this is the one mixin all three display foundations compose. Same argument, one level down, that put rendersCanvas on RenderLifecycleMixin beside canvasDrawn. | FetchMixin |
awaitingPrerequisiteboolean | Overridable hook (default false), read only by the retry contract check (makeRetryContractCheck): "this run declined because a prerequisite fetch in another autorun has not landed, and its arrival wakes this one again". It defers the retry verdict to that later run rather than waiving it, so a display cannot spend its retry on a decline it called preliminary.Two displays say it, one per fetch foundation, which is why it lives beside fetchInert rather than on either: HiC's contacts fetch declines until CoreGetInfo lands, and MultiSampleVariantBaseModel's fetchNeeded declines until sourcesBase does. Both have a reload() that wakes the prerequisite's autorun as well as their own.It has to be strictly narrower than the gate it explains. One that restates the gate's negation makes every decline a deferred one, so no run is ever judged and the display has silently opted out — an exemption by another name. HiC is in that shape deliberately, because its gate and its prerequisite are one condition; what covers its retry instead is LinearHicDisplay/infoFetchFailure.test.ts.Not for a display deliberately not fetching at all — that is fetchInert above, which the loading scrim and the export read too. | FetchMixin |
rpcPropsCacheKeystring | The RPC cache key both fetch foundations invalidate on: this display's rpcProps() payload serialized to a string. serializeRpcProps owns the why, including the silently-dead-axis corollary.Here, beside the two hooks above, for the same reason they are: it describes the display, and every foundation composes this mixin. The per-region family watches it from SettingsInvalidate and the global one from its fetch autorun's trigger list — one getter and one name, so the two cannot come to invalidate on different axes. The global side built its own local computed over the same function until 2026-08, which was the same value under a second spelling. | FetchMixin |
adapterConfigKeystring | The adapter axis of the same key, watched by the same two readers as rpcPropsCacheKey: SettingsInvalidate per-region and the global family's currentFetchKey. A track re-pointed in the config editor is a different fetch, and until 2026-09 only the comparative family said so. | FetchMixin |
Methods
| Member | Description | Defined by |
|---|---|---|
holdsAssembly(assemblyName: string) => boolean | whether the session holds a lane's genome under any spelling, which is what a navigation onto it needs and a lane drawn from a blocks table does not | MultiWaySyntenyDisplay |
pinnedContigOf(assemblyName: string) => string | undefined | MultiWaySyntenyDisplay | |
hitTest(x: number, y: number) => HoverTarget | undefined | what sits under a container-relative point: the glyph or box of the one lane whose glyph row holds it, boxes before genes since that is the order they draw, then a ribbon through the backend's pick | MultiWaySyntenyDisplay |
() => MenuItem[] | the same multi-panel launch the view menu and the rubberband offer, from the track that is already showing the lanes: every genome aligning to the visible window gets a full row of its own in a stacked linear synteny view, cut from this track's dataset. Appended to the inherited items rather than replacing them, so a mixin's item is not dropped by being composed under this one | MultiWaySyntenyDisplay |
| renderingProps | props passed to the renderer's React "Rendering" component. these are client-side only and never sent to the worker. includes displayModel and callbacks | BaseDisplay |
resolvedByteLimit() => number | undefined | The budget the worker enforces and the banner compares against — the one spelling of that pair. Undefined when the gate may not act. | RegionTooLargeMixin |
gateFetchState() => GateFetchState | The gate as it stands for a fetch about to be issued. Calling it is the capture, which is why it is a method. | RegionTooLargeMixin |
Actions
| Member | Description | Defined by |
|---|---|---|
setFeatures(f: Feature[]) => void | MultiWaySyntenyDisplay | |
clearDirectLinkClick() => void | a bare targetIdx addresses the outgoing targets array, so it goes whenever the lanes rebuild; a group KEY re-resolves against the rebuilt geometry and stays — load-bearing, since the click's own widget resizes the view and that refetches | MultiWaySyntenyDisplay |
| setLaneGenes | coversMatesFor is the anchor assembly when this commit framed a mate lane, else undefined | MultiWaySyntenyDisplay |
setLaneLinks(fetched: Map<string, HeldLaneLinks>) => void | MultiWaySyntenyDisplay | |
setStarAnchor(assemblyName: string | undefined) => void | MultiWaySyntenyDisplay | |
| setLaneFrames | MultiWaySyntenyDisplay | |
pinLaneContig(assemblyName: string, refName: string | undefined) => void | pin a lane onto one of its contigs, or undefined to let it choose again. A fresh map, so the decision autorun sees the write | MultiWaySyntenyDisplay |
setRowOrder(order: string[]) => void | MultiWaySyntenyDisplay | |
resetRowOrder() => void | back to densest-first. Its own action rather than setRowOrder([]), which now means "here is the order of the lanes I can see" and would keep every lane the caller could not | MultiWaySyntenyDisplay |
(names: string[]) => void | MultiWaySyntenyDisplay | |
setDeclaredLanes(lanes: DeclaredLane[]) => void | MultiWaySyntenyDisplay | |
setSelectedLanes(names: string[] | undefined) => void | undefined puts the choice back to every lane the source places | MultiWaySyntenyDisplay |
setBridgeSkippedLanes(flag: boolean) => void | MultiWaySyntenyDisplay | |
setRibbonColorBy(mode: MultiWayRibbonColorBy) => void | MultiWaySyntenyDisplay | |
setDrawCurves(flag: boolean) => void | MultiWaySyntenyDisplay | |
setShowLaneTicks(flag: boolean) => void | MultiWaySyntenyDisplay | |
setLodMode(mode: LodMode) => void | MultiWaySyntenyDisplay | |
openLaneSelection() => void | the lane picker, over laneUniverse | MultiWaySyntenyDisplay |
selectFeature(feature: Feature) => void | MultiWaySyntenyDisplay | |
openInNewView(assemblyName: string, loc: string) => void | a lane's assembly in a linear genome view of its own, at loc, with this track along so the new view is the same stack anchored there, and the session's annotation for the genome. Keyed on the display and the lane, so following one lane twice re-navigates the view | MultiWaySyntenyDisplay |
reanchor(assemblyName: string, loc: string) => void | the hosting view onto assemblyName at loc; the anchor lane reads off the view's first assembly, so the stack re-anchors on its own | MultiWaySyntenyDisplay |
setHoverTarget(target: HoverTarget | undefined) => void | MultiWaySyntenyDisplay | |
startRenderingBackend(backend: MultiWayRenderingBackend) => void | the backend's cells and frame, through the one installer: a cell re-uploads when its identity changes and a frame redraws on anything the render state reads, which on a pan is the drag offset alone | MultiWaySyntenyDisplay |
setPointer(state?: MouseState | undefined) => void | MultiWaySyntenyDisplay | |
clearHoveredFeature() => void | BaseDisplay's hook. Two clears call it, because two different things move the lanes under a stationary cursor: the foundation's viewport-change reaction, and this display's own relayout reaction (see afterAttach) | MultiWaySyntenyDisplay |
selectHovered() => void | MultiWaySyntenyDisplay | |
| renderSvg | MultiWaySyntenyDisplay | |
setStatusMessage(status?: RpcStatus | undefined) => void | BaseDisplay | |
setError(error?: unknown) => void | BaseDisplay | |
reload() => void | base display reload does nothing, see specialized displays for details | BaseDisplay |
| applyDisplaySettings | Apply a bag of display settings to the LIVE display, and report what landed. Each key runs through the display config schema's preProcessSnapshot (shorthand expansions, legacy-key migrations — the same lowering a session spec's inline track keys get in showTrackGeneric), then writes the matching config slot. Keys that are not slots come back in unapplied rather than vanishing: the settings vocabulary's historical failure mode is the silently dropped key.allowSetters additionally routes a non-slot key to a conventionally named single-argument set<Key> action. Opt-in, never the default: the declarative surfaces (session specs, share links, embeds) feed this whole bags of untyped JSON, and a blanket fallback would let them reach internal setters (setError, setScrollTop, ...) and call multi-argument setters with one argument. A caller that wants a specific action can also simply call it.A key whose write THREW is reported separately, in failed — it is the only one of the three that means the caller got something wrong, and the only one worth a notification. unapplied is not: at the showTrackGeneric call site it also collects keys that surface consumed itself (type) and MST display props the display snapshot already applied (resolution), so treating it as "dropped" would report a correct call as broken.Per-key errors do not abort the rest of the bag — a caller mid- showTrack has already pushed the track, and one rejected value must not strand a half-configured track. | BaseDisplay |
setScrollTop(scrollTop: number) => void | Clamped into [0, scrollableHeight], so no caller has to remember the bound. Unbounded for a display that leaves scrollableHeight at its Infinity default. | TrackHeightMixin |
setHeight(displayHeight: number) => number | TrackHeightMixin | |
resizeHeight(distance: number) => number | TrackHeightMixin | |
expandToContentHeight() => number | Grow the track by exactly the content it is currently hiding, so a display scrolled over a taller stack ends up showing all of it. The track's resize handle runs this on a double click.scrollableHeight is the whole measurement — it is already every scrolling display's answer to "how much is off the bottom", so no display has to supply a second one. A display that doesn't scroll internally leaves it at Infinity and gets a no-op, as does one already showing everything (0).Routed through resizeHeight rather than setHeight so grow mode's override still gets to leave grow first; going straight to the slot would let the reactive height re-derive grownHeight and the double click would appear to do nothing. | TrackHeightMixin |
clearByteEstimate() => void | Drops the estimate and the viewport stamp. forceLoadTrack survives: it is a track-wide approval. | RegionTooLargeMixin |
setForceLoadTrack(flag: boolean) => void | RegionTooLargeMixin | |
| commitFetchBytes | The byte axis of a finished fetch, called by the fetch runners with the gateFetchState() they captured at issue. Commits the per-region max; an empty batch, or an ungated display, commits nothing. | RegionTooLargeMixin |
forceLoad() => void | The banner's button: exempt the track on both axes and refetch. | RegionTooLargeMixin |
markCanvasDrawn() => void | RenderLifecycleMixin | |
resetCanvasDrawn() => void | RenderLifecycleMixin | |
stopRenderingBackend() => void | RenderLifecycleMixin | |
renderNow() => void | RenderLifecycleMixin | |
setRenderError(error: unknown) => void | set/clear the render-backend error. Called by useRenderingBackend: with the error when the canvas factory rejects (or context-loss re-init fails), and with undefined on successful (re)init and on retry. | RenderLifecycleMixin |
| attachRenderingBackend | attach a GPU/Canvas2D backend and install the upload + render autorun pair. Idempotent: re-calling swaps the backend and does not run setup again, so the callbacks and everything they close over are the first call's. | RenderLifecycleMixin |
commitFetchResult(commit: () => void, key: string) => void | The commit half of a keyed fetch: run the display's own store in the same transaction as the key stamp, so no observer can see fresh data under a stale key or the reverse. Being the only writer of loadedFetchKey is what makes dataCurrent derivable — a display cannot commit without stamping. | KeyedFetchMixin |
stopActiveFetch() => void | Abort the in-flight fetch (if any) and retire its slot. The shared preamble of both cancel paths; the difference between them is only what they do to fetchCanceled / fetchGeneration afterward. | FetchMixin |
openStatusStream(isCurrent: () => boolean) => StatusStream | Open one operation's slot on the display's status field: an RPC statusCallback throttled through the display-wide window and guarded so a callback that fires after the node is torn down (RPCs resolve their status stream asynchronously) is a safe no-op, plus the clear that retires the slot when the operation ends.Every operation on the display opens one, and the two come back together because an operation that never retires goes on voting for a phase that is over. The viewport fetch ( runFetch), the clustering run and a lent createStopTokenRotation are three of them on one field; before ADR-081 each blanked the field outright and the last one to finish decided what the other two were still saying.isCurrent is required and has no "node is alive" default, because alive is not the interesting question: a superseded fetch is on a live node, and its late status repainting the overlay of the fetch that replaced it is the failure this guards. runFetch passes !isStale(), which is what every display gets for free through ctx.statusCallback; a caller outside a fetch (the clustering autorun) passes its own run's flag. Defaulting to isAlive made the loose answer the easy one and five displays took it.runFetch's own slot is opened by the rotation; this is for an operation outside any fetch, the tree sidebar's clustering run. | FetchMixin |
cancelFetch() => void | cancel any in-flight fetch and bump fetchGeneration (always bumps, so callers can retrigger fetch autoruns even when nothing was in flight). This is the internal reset clearAllRpcData runs — it clears any user-cancel flag so the retrigger actually re-fetches. | FetchMixin |
cancelFetchByUser() => void | User-initiated cancel from the loading overlay. Stops the in-flight fetch and lands in a durable fetchCanceled state. Unlike cancelFetch, it does NOT bump fetchGeneration — so the fetch autoruns don't immediately restart the load. The user retries via reload (the overlay's retry button), or it clears on the next viewport change. | FetchMixin |
beforeDestroy() => void | Release an in-flight fetch's stop token on teardown. Without this, a display destroyed mid-fetch (track/view closed while loading) never signals the worker to abort the now-useless work, and its in-flight HTTP reads keep downloading. MST auto-chains lifecycle hooks, so a composing display can still define its own beforeDestroy. | FetchMixin |
beginFetch(stopToken: StopToken) => void | The onBegin half of a fetch's bookkeeping: publish the in-flight token (isLoading) and clear the durable user-cancel — a load starting is the single clear point that covers every retrigger path (reload, viewport change, settings invalidate). An action of its own for the same reason endFetch is: installFetch's lifecycle callbacks run outside any MST flow this mixin owns. | FetchMixin |
endFetch(current: boolean) => void | The finally half of runFetch's bookkeeping, an action of its own because runFetchOnce's finally resumes on a microtask the flow does not own — a direct volatile write there is outside the action context, which is the one thing hoisting the sequence into a shared function costs. The stale branch is a superseded fetch, which must not clear the loading flag the run that replaced it just set. The stop token itself is released by the rotation's own end(), one layer down. | FetchMixin |
runFetch(work: (ctx: FetchContext) => Promise<void>) => Promise<void> | Run a cancel-safe fetch (cancels any prior). The work callback gets a FetchContext with a stopToken to forward to the RPC and an isStale() check to short-circuit commits once the user has moved on. The MST-flow wrapper over the shared runFetchOnce sequence, and only the wrapper: the begin/clear/run/commit/error/end order, and the rules that keep a superseded run from writing back, are the same function every other fetch in the tree runs. What this adds is the observable bookkeeping a display needs — isLoading through activeStopToken, fetchGeneration, the user-cancel clear — and the flow itself, which is an action, so work's synchronous prefix runs untracked wherever a fetch autorun calls this. | FetchMixin |
setLodTierInfo(info: LodTierInfo | undefined) => void | LodTierInfoMixin |