Skip to content

Selection & Sync

Hatchlings provides a shared SelectionState class that synchronizes selection, caret position, and keyboard navigation across multiple views of the same sequence.

Overview

When PlasmidViewer and SequenceViewer display the same construct, you often want selection in one view to be reflected in the other. SelectionState is a Svelte 5 reactive class that manages this.

svelte
<script>
  import { PlasmidViewer, SequenceViewer, SelectionState } from '@molbiohive/hatchlings';

  const selection = new SelectionState(2686); // sequence length

  let plasmidData = { ... };
  let sequenceData = { ... };
</script>

<PlasmidViewer data={plasmidData} selectionState={selection} width={500} height={500} />
<SequenceViewer data={sequenceData} selectionState={selection} width={660} height={400} />

Click or drag in either view — the selection updates in both.

SelectionState API

Constructor

ts
const selection = new SelectionState(sequenceLength: number);

Reactive Properties

PropertyTypeDescription
caretPositionnumberCurrent cursor position (bp)
selectionStartnumber | nullStart of selection range
selectionEndnumber | nullEnd of selection range
isDraggingbooleanWhether a drag is in progress
selectedAnnotationIdsSet<string>IDs of selected features

Computed Properties

PropertyTypeDescription
range{ start, end } | nullCurrent selection range (handles circular wrapping)
hasSelectionbooleanWhether a range is selected
wrapsbooleanWhether selection wraps around origin (circular)
selectionLengthnumberLength of selection in bp

Methods

MethodDescription
setCaret(position)Move cursor without selecting
setSelection(start, end)Set explicit selection range
clearSelection()Clear all selection
selectAnnotation(id, multi?)Select a feature by ID
selectAll()Select the entire sequence
moveCaret(delta, extend?)Keyboard navigation (extend = shift-held)
startDrag(position)Begin drag selection
updateDragLinear(position)Update drag for linear topology
updateDragCircular(start, end)Update drag for circular topology
endDrag()Finish drag selection

Event Callbacks

Components emit selection events alongside the shared state:

EventPayloadDescription
onselect{ start, end }Region selected (drag completed)
onselectionchange{ start, end } | nullSelection changed (real-time during drag)
oncaretmovenumberCaret position changed
onpartclickPartFeature clicked
oncopysequencestringSequence copied to clipboard
svelte
<PlasmidViewer
  data={plasmidData}
  selectionState={selection}
  onselect={(sel) => console.log(`Selected ${sel.start}..${sel.end}`)}
  onpartclick={(part) => console.log(`Clicked ${part.name}`)}
/>

Circular Wrapping

For circular sequences, selection can wrap around the origin (position 0). When start > end, the selection spans from start to the end of the sequence and continues from 0 to end:

Sequence: 0 ──────────── 2686
Selection:     ████               ████
               end=500            start=2400

Wraps: true
Length: (2686 - 2400) + 500 = 786 bp

SelectionState handles this automatically — both PlasmidViewer (arc selection) and SequenceViewer (highlighted rows) display wrapping correctly.

Components with Selection Support

ComponentselectionState propSelection behavior
PlasmidVieweryesArc selection on circular map, range on linear
SequenceVieweryesRow-based text selection with shift+click
TraceViewernoInternal scrollbar-based navigation
AlignmentViewernoColumn highlight on hover