Skip to content

Locus Manager v1.0.60

Collapses the "renderer's current position" into a single ILocus object, containing:

  • DNA-side coordinates (chr / start / end / assembly)
  • RNA-side identity (trans_* / gene_* / strand / up / down)
  • The current mode ("rna" | "dna" | "cds")
  • isFavorite (queried from favouriteManager)
  • Metadata id (random) / time (ISO timestamp) — refreshed only when the content actually changes

Accessed via an instance property (not a top-level export)

LocusManager is not exported from the @rbrowser/main top level. Use the renderer instance property only:

const lm = renderer.locusManager;

The manager itself is passive: the host calls tick() once per frame, and it emits to subscribers only when the content changes.


Method

getLocus

method

lm.getLocus(): ILocus

Returns a complete ILocus snapshot. isFavorite is re-checked on every call (cheap); the remaining fields are served from cache. This is the standard source for writing the current position into history / favourite.

const locus = renderer.locusManager.getLocus();
console.log(locus.mode, locus.rna.trans_name, locus.dna.chr, locus.isFavorite);

historyManager.add(locus);   // add() only accepts ILocus

getMode

method

lm.getMode(): ViewMode

The current coordinate system: "rna" / "dna" / "cds". Equivalent to renderer.isCdsMode ? "cds" : renderer.isRnaMode ? "rna" : "dna", providing a unified entry point.

getAssembly

method

lm.getAssembly(): string

The assembly name of the currently active reference (e.g. "GRCh38"); returns "" when there is no reference.

getRNALocus

method

lm.getRNALocus(): ILocusRna

Takes only the ILocusRna sub-object — for consumers who "only care which transcript is current".

getDNALocus

method

lm.getDNALocus(): ILocusDna

Takes only the ILocusDna sub-object — for consumers who "only care about the genomic coordinates of the current view".

getIsFavorite

method

lm.getIsFavorite(): boolean

Whether the current position is favourited in favouriteManager. DNA mode looks it up by viewRegion ("chr1:1000-2000"); RNA / CDS mode looks it up by viewRnaRegion ("VAMP3-201:5000:5000") — the same key used by the UI's favourite button.

setMode

method

lm.setMode(mode: ViewMode): void

Switches the coordinate system:

  • "dna": turns off the current RNA / CDS mode
  • "rna" / "cds": re-navigates to the transcript when there is an existing transcript context; no-op when there is no transcript
renderer.locusManager.setMode("rna");   // switch to RNA mode
renderer.locusManager.setMode("dna");   // fall back to genomic coordinates

setLocus

method

async lm.setLocus(input: ILocusSetInput): Promise<void>

Navigates to a new position from a unified flat input. Identification priority is trans_id > trans_name > gene_id > gene_name; when mode is omitted it is inferred from whether a transcript identity is provided.

// RNA mode: navigate by transcript_name
await renderer.locusManager.setLocus({
  trans_name: "VAMP3-201",
  up: 5000,
  down: 5000,
});

// CDS mode: navigate by transcript_id
await renderer.locusManager.setLocus({
  mode: "cds",
  trans_id: "ENST00000054666",
});

// DNA mode: by genomic coordinates
await renderer.locusManager.setLocus({
  mode: "dna",
  chr: "chr1",
  start: 7769296,
  end: 7783432,
});

The underlying navigateByTranscript[CDS] accepts only a single flank, so the supplied up/down are dispatched as max(up, down); the ILocus subsequently produced by tick() still retains independent up / down.

method

async lm.navigateToLocus(locus: ILocus): Promise<boolean>

A navigation entry point dedicated to clicking a history / favourite entry. It enforces three rules — no strings passed in, no assembly lost, no mode missed:

Rule Behavior
1. assembly must match On mismatch, attempts referenceManager.switchByName(targetAssembly) to auto-switch, then await lastSyncPromise. If the target reference is not loaded → rejects the navigation (returns false and console.warn), avoiding landing on the wrong chromosome coordinates
2. mode must align Turns off RNA + CDS before entering DNA; turns off CDS before entering RNA; turns off RNA before entering CDS
3. identity within the mode must match DNA → navigateTo(chr, start, end); RNA → transcript navigation that preserves the asymmetric flank; CDS → navigateByTranscriptCDS(name, max(up, down))

Identifier priority for RNA / CDS: trans_id > trans_name > gene_id > gene_name.

Return value:

  • true — the navigation was dispatched
  • false — the navigation was rejected (assembly unrecoverable, or the locus has no usable identity)
// Typical usage: clicking a favourite list item
const fav = favouriteManager.getAll()[0];
const ok = await renderer.locusManager.navigateToLocus(fav);
if (!ok) {
  alert("Cannot navigate: assembly not loaded or locus lacks required identity");
}

Why not just r.region = string

r.region = "VAMP3-201:5000:5000" can only tell the renderer "go to this transcript", but it carries no assembly. If the user is currently on GRCh37 and the favourite came from GRCh38, a blind jump would resolve VAMP3-201 against GRCh37's annotation and could land in a completely different place. navigateToLocus() handles this centrally.

tick

method

lm.tick(): ILocus | null

The RAF-driven entry point:

  1. Reassembles the ILocus "content" fields once (rna / dna / mode / assembly)
  2. Short-circuits on JSON equality — when the content is unchanged it only refreshes isFavorite and returns null
  3. Only when the content changes does it generate a new id / time, update the cache, and push to all listeners
function syncLoop() {
  const fresh = renderer.locusManager.tick();
  if (fresh) setReactState(fresh);   // update React only on change
  requestAnimationFrame(syncLoop);
}
requestAnimationFrame(syncLoop);

tick() is also optional — on() listeners are the preferred way to subscribe; the tick() return value is just for the scenario where you "don't want to register a listener and want it directly".

on

method

lm.on(listener: LocusListener): () => void

Subscribes to "content changes". Fires only when tick() detects a change in any of the rna / dna / mode / assembly fields; a standalone isFavorite toggle does not fire (to avoid a high-frequency favourite-button toggle flooding subscribers). Returns an unsubscribe function.

const off = renderer.locusManager.on((locus) => {
  console.log("locus changed:", locus.mode, locus.rna.trans_name);
});
off();

Types

ILocus

type

A snapshot of the renderer's current position. It carries both the DNA-space coordinates (dna) and the RNA-space transcript identity (rna), regardless of the current mode — consumers take what they need. id is a random identifier for this snapshot (changes only when the content materially changes), time is the ISO timestamp of that change, and isFavorite comes from FavouriteManager.

interface ILocus {
  id: string;
  rna: ILocusRna;
  dna: ILocusDna;
  mode: ViewMode;        // "dna" | "rna" | "cds"
  time: string;          // ISO timestamp
  isFavorite: boolean;
}

ILocusRna

type

The RNA-side locus. All transcript / gene identity fields are optional — populated only when navigation resolves them. up / down are the upstream / downstream flanks (bp) relative to the transcript boundaries (in the transcript's strand direction); in RNA mode the renderer computes them in real time from the visible window relative to the TSS / TES.

interface ILocusRna {
  up?: number;
  down?: number;
  strand?: string;
  trans_id?: string;
  trans_name?: string;
  trans_type?: string;
  gene_id?: string;
  gene_name?: string;
  gene_type?: string;
  assembly: string;
}

ILocusDna

type

The DNA-side locus. All fields are required — the genomic coordinates are always known (from the initial config or the current view), and assembly mirrors the active reference, making the snapshot self-describing.

interface ILocusDna {
  chr: string;
  start: number;
  end: number;
  assembly: string;
}

ILocusSetInput

type

The flat input for setLocus(). When omitted, up / down both default to 5000; supplying only one side makes it asymmetric (the other side remains 5000).

interface ILocusSetInput {
  mode?: ViewMode;
  trans_id?: string;
  trans_name?: string;
  gene_id?: string;
  gene_name?: string;
  up?: number;
  down?: number;
  // DNA mode
  chr?: string;
  start?: number;
  end?: number;
}

LocusListener

type

type LocusListener = (locus: ILocus) => void;