@jbrowse/plugin-linear-genome-view 5.0.0-beta.15 → 5.0.0-beta.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { canonicalLocString } from '@jbrowse/core/TextSearch/places';
2
- import { getConf } from '@jbrowse/core/configuration';
2
+ import { getConf, readConfObject } from '@jbrowse/core/configuration';
3
3
  import { BaseViewModel } from '@jbrowse/core/pluggableElementTypes/models';
4
4
  import { exportViewSvg } from '@jbrowse/core/svg/exportViewSvg';
5
5
  import { assembleLocString, clamp, getBpDisplayStr, getNotificationSink, getSession, isSessionModelWithWidgets, localStorageGetBoolean, localStorageGetItem, localStorageSetBoolean, localStorageSetItem, springAnimate, sum, } from '@jbrowse/core/util';
@@ -15,10 +15,11 @@ import { assemblyErrorMessage, computeViewStatus, viewLoading, } from '@jbrowse/
15
15
  import { pendingLaunch, withLaunchInput, } from '@jbrowse/core/util/withLaunchInput';
16
16
  import { MIN_DISPLAY_HEIGHT } from '@jbrowse/display-kit/const';
17
17
  import { contentRightEdgePx } from '@jbrowse/display-kit/regionHost';
18
- import { cast, getParent, hasParent, isAlive, types, } from '@jbrowse/mobx-state-tree';
18
+ import { cast, getParent, getSnapshot, hasParent, isAlive, types, } from '@jbrowse/mobx-state-tree';
19
19
  import { observable, when } from 'mobx';
20
20
  import { handleSelectedRegion, isOpenInView, navToOption, } from '../searchUtils.js';
21
21
  import { doAfterAttach } from './afterAttach.js';
22
+ import { linearGenomeViewAxisConfigSchema } from './axisConfigSchema.js';
22
23
  import { getCytobands, shouldSwapTracks } from './components/util.js';
23
24
  import { HEADER_BAR_HEIGHT, HEADER_OVERVIEW_HEIGHT, MIN_BP_PER_PX, MINIMIZED_TRACK_HEIGHT, MINIMUM_BLOCK_WIDTH, RESIZE_ALL_HANDLE_HEIGHT, RESIZE_HANDLE_HEIGHT, SCALE_BAR_HEIGHT, SHOW_ALL_REGIONS_FILL, TRACK_OUTLINE_BORDER, TRACK_TOP_GAP, } from './consts.js';
24
25
  import { planFlight } from './flyTo.js';
@@ -154,7 +155,7 @@ function isTrackSelectorVisible(self) {
154
155
  * views: [
155
156
  * {
156
157
  * type: 'LinearGenomeView',
157
- * colorByCDS: true,
158
+ * colorByFrame: true,
158
159
  * assembly: 'hg38',
159
160
  * loc: 'chr1:1,000,000-1,100,000',
160
161
  * tracks: ['genes', 'alignments'],
@@ -164,7 +165,7 @@ function isTrackSelectorVisible(self) {
164
165
  * ```
165
166
  * `assembly`, `loc`, `tracks`, `tracklist`, `nav` and `highlight` need
166
167
  * on-attach resolution and are captured into the `launch` property below;
167
- * `colorByCDS`, `showAminoAcids`, `showCenterLine` and `trackLabels` are plain
168
+ * `colorByFrame`, `showAminoAcids`, `showCenterLine` and `trackLabels` are plain
168
169
  * view props MST restores natively. Both are written the same way.
169
170
  * At runtime the same model is driven imperatively — every property and action
170
171
  * below is reachable on `viewState.session.views[0]`:
@@ -192,17 +193,16 @@ export function stateModelFactory(pluginManager) {
192
193
  /**
193
194
  * #property
194
195
  * Left edge of the viewport, in linearized bp — the concatenated
195
- * `displayedRegions` space that `offsetPx` indexes, which carries no
196
+ * `displayedRegions` space that `offsetPx` indexes, which has no
196
197
  * inter-region padding, so the two differ only by `bpPerPx`. May be
197
- * negative, which is the view scrolled past the left end.
198
+ * negative when the view is scrolled past the left end.
198
199
  *
199
- * The viewport is stored as the genomic WINDOW it frames rather than as
200
- * the pixels that framed it, because pixels mean nothing without the
201
- * width they were measured at and a snapshot does not carry one. Storing
202
- * them anyway is why a session authored in a 1000px window used to open
203
- * at 500px showing half the region its author was looking at, while the
204
- * same location as a `&loc=` opened correctly — the two ways to share a
205
- * view disagreed, and only the one that stores intent was right.
200
+ * The view stores the genomic window it frames rather than the pixels
201
+ * that framed it, because pixels mean nothing without the width they
202
+ * were measured at and a snapshot does not include one. A session
203
+ * authored in a 1000px window therefore shows the same region when
204
+ * opened at 500px, as the same location given as a `&loc=` does: both
205
+ * ways to share a view store intent.
206
206
  */
207
207
  windowStartBp: types.stripDefault(types.number, 0),
208
208
  /**
@@ -215,14 +215,15 @@ export function stateModelFactory(pluginManager) {
215
215
  windowWidthBp: types.stripDefault(types.number, 0),
216
216
  /**
217
217
  * #property
218
- * MIGRATION ONLY, and permanent: share links written before the window
219
- * was stored carry `bpPerPx`/`offsetPx`, and there are many of them.
218
+ * Used for migration only, and permanent: share links written before the
219
+ * window was stored contain `bpPerPx`/`offsetPx`, and there are many of
220
+ * them.
220
221
  *
221
- * A snapshot written before the window was stored carries `offsetPx` and
222
+ * A snapshot written before the window was stored has `offsetPx` and
222
223
  * `bpPerPx` but not the width they were measured at, so the window they
223
224
  * framed cannot be recovered. `windowStartBp` can (it is
224
225
  * `offsetPx * bpPerPx`, no width needed); the width in bp cannot. This
225
- * carries the old `bpPerPx` to the first measure, which adopts it at
226
+ * property holds the old `bpPerPx` until the first measure, which adopts it at
226
227
  * whatever width arrives — exactly what the old code did — and clears
227
228
  * this. So an old link keeps its old behavior rather than being
228
229
  * reinterpreted, and everything authored since restores its window.
@@ -231,9 +232,8 @@ export function stateModelFactory(pluginManager) {
231
232
  /**
232
233
  * #property
233
234
  * currently displayed regions, can be a single chromosome, arbitrary
234
- * subsections, or the entire set of chromosomes in the genome, but it not
235
- * advised to use the entire set of chromosomes if your assembly is very
236
- * fragmented
235
+ * subsections, or the entire set of chromosomes in the genome. The entire
236
+ * set is not advised if your assembly is very fragmented
237
237
  */
238
238
  displayedRegions: types.stripDefault(types.frozen(), []),
239
239
  /**
@@ -268,7 +268,7 @@ export function stateModelFactory(pluginManager) {
268
268
  /**
269
269
  * #property
270
270
  * show the "center line". A personal preference: never in a session
271
- * snapshot. It, showCytobands, trackLabels, colorByCDS, showAminoAcids
271
+ * snapshot. It, showCytobands, trackLabels, colorByFrame, showAminoAcids
272
272
  * and showTrackOutlines start from this browser's last choice, which
273
273
  * their setters record.
274
274
  */
@@ -283,29 +283,30 @@ export function stateModelFactory(pluginManager) {
283
283
  /**
284
284
  * #property
285
285
  * how to display the track labels, can be "overlapping", "offset", or
286
- * "hidden", or empty string "" (which results in the
287
- * LinearGenomeViewPlugin config default being used). the resolved value
288
- * is the `effectiveTrackLabels` getter. see LinearGenomeViewPlugin
289
- * https://jbrowse.org/jb2/docs/config/lineargenomeviewconfigschema/ docs for
290
- * how conf is used
286
+ * "hidden", or empty string "" (which uses the LinearGenomeViewPlugin
287
+ * config default). The resolved value is the `effectiveTrackLabels`
288
+ * getter. See the LinearGenomeViewPlugin docs at
289
+ * https://jbrowse.org/jb2/docs/config/lineargenomeviewconfigschema/ for
290
+ * how the config is used
291
291
  */
292
292
  trackLabels: types.optional(types.string, () => localStorageGetItem('lgv-trackLabels') ?? ''),
293
293
  /**
294
294
  * #property
295
- * show the "gridlines" in the track area
295
+ * The ruler's guide, a [](/docs/config/lineargenomeviewaxis) object:
296
+ * `{ grid: false }` stops its ticks running down through the tracks.
296
297
  */
297
- showGridlines: types.stripDefault(types.boolean, true),
298
+ axis: types.stripDefault(linearGenomeViewAxisConfigSchema, {}),
298
299
  /**
299
300
  * #property
300
301
  * color CDS segments by reading frame
301
302
  */
302
- colorByCDS: types.optional(types.boolean, () => localStorageGetBoolean('lgv-colorByCDS', false)),
303
+ colorByFrame: types.optional(types.boolean, () => localStorageGetBoolean('lgv-colorByFrame', false)),
303
304
  /**
304
305
  * #property
305
306
  * draw translated codons on coding features once zoomed in far enough:
306
307
  * an alternating per-codon shading, and the amino acid letters on top of
307
- * it at base-level zoom. Independent of `colorByCDS`, which only recolors
308
- * the segments by frame.
308
+ * it at base-level zoom. Independent of `colorByFrame`, which only
309
+ * recolors the segments by frame.
309
310
  */
310
311
  showAminoAcids: types.optional(types.boolean, () => localStorageGetBoolean('lgv-showAminoAcids', true)),
311
312
  /**
@@ -407,6 +408,13 @@ export function stateModelFactory(pluginManager) {
407
408
  };
408
409
  })
409
410
  .views(self => ({
411
+ /**
412
+ * #getter
413
+ * `axis.grid`: whether the ruler's ticks run down through the tracks.
414
+ */
415
+ get axisGrid() {
416
+ return readConfObject(self.axis, 'grid');
417
+ },
410
418
  // The viewport in pixels, derived from the window it frames — declared
411
419
  // ahead of every other getter so that the ~300 reads of `self.bpPerPx` /
412
420
  // `self.offsetPx` across the codebase go on resolving by name. Only the
@@ -659,8 +667,8 @@ export function stateModelFactory(pluginManager) {
659
667
  },
660
668
  /**
661
669
  * #getter
662
- * What the loading screen says while `showLoading`, read off the
663
- * assembly whose load is the wait; undefined otherwise.
670
+ * The loading screen's text while `showLoading`, taken from the
671
+ * assembly being waited on; undefined otherwise.
664
672
  */
665
673
  get loading() {
666
674
  return viewLoading(this.showLoading, () => this.loadingAssembly);
@@ -714,12 +722,12 @@ export function stateModelFactory(pluginManager) {
714
722
  * `width`/`staticBlocks` throw by design before the view has been
715
723
  * measured and navigated.
716
724
  *
717
- * **Not `initialized`**, which is the trap this getter exists to close.
725
+ * Use this getter rather than `initialized`.
718
726
  * That one answers "have the assembly's regions loaded", which is only
719
727
  * the first of two async steps: navigating then populates
720
728
  * `displayedRegions`, and in the window between the two `initialized` is
721
729
  * already true while there is still nothing on screen. `showLoading`
722
- * folds in `awaitingInitNavigation`, the getter that exists for exactly
730
+ * folds in `awaitingInitNavigation`, the getter for exactly
723
731
  * that gap.
724
732
  *
725
733
  * `error` is the third outcome and is why this is not a bare
@@ -796,7 +804,7 @@ export function stateModelFactory(pluginManager) {
796
804
  },
797
805
  /**
798
806
  * #method
799
- * rendered height of a single track, collapsing to a fixed height when
807
+ * rendered height of a single track, using a fixed height when
800
808
  * minimized. Shared by trackHeights and getTrackYOffset so the two can't
801
809
  * disagree. Reads `activeDisplay` — the display TrackContainer actually
802
810
  * mounts — rather than re-picking `displays[0]`, so the view's height math
@@ -926,8 +934,8 @@ export function stateModelFactory(pluginManager) {
926
934
  * or 0 for a standalone view, a mode that is off, and a stack that cannot
927
935
  * answer yet.
928
936
  *
929
- * Pulled rather than pushed down into a volatile: the number is a
930
- * function of every row's fit, all of which move on a resize, and a
937
+ * A getter rather than a volatile the container writes: the number is a
938
+ * function of every row's fit, all of which change on a resize, and a
931
939
  * stored copy would be stale by the next layout.
932
940
  */
933
941
  get sharedFitBpPerPx() {
@@ -1054,9 +1062,9 @@ export function stateModelFactory(pluginManager) {
1054
1062
  /**
1055
1063
  * #action
1056
1064
  */
1057
- setColorByCDS(flag) {
1058
- self.colorByCDS = flag;
1059
- localStorageSetBoolean('lgv-colorByCDS', flag);
1065
+ setColorByFrame(flag) {
1066
+ self.colorByFrame = flag;
1067
+ localStorageSetBoolean('lgv-colorByFrame', flag);
1060
1068
  },
1061
1069
  /**
1062
1070
  * #action
@@ -1172,8 +1180,8 @@ export function stateModelFactory(pluginManager) {
1172
1180
  /**
1173
1181
  * #action
1174
1182
  */
1175
- setShowGridlines(b) {
1176
- self.showGridlines = b;
1183
+ setAxisGrid(grid) {
1184
+ self.axis = cast({ ...getSnapshot(self.axis), grid });
1177
1185
  },
1178
1186
  /**
1179
1187
  * #action
@@ -1454,7 +1462,7 @@ export function stateModelFactory(pluginManager) {
1454
1462
  /**
1455
1463
  * #method
1456
1464
  * Helper method for the fetchSequence.
1457
- * Retrieves the corresponding regions that were selected by the
1465
+ * Returns the regions the user selected with the
1458
1466
  * rubberband
1459
1467
  *
1460
1468
  * @param leftOffset - `object as {start, end, index, offset}`, offset = start
@@ -1584,8 +1592,8 @@ export function stateModelFactory(pluginManager) {
1584
1592
  }
1585
1593
  /**
1586
1594
  * #action
1587
- * cancel an in-flight animated zoom. The animation already yields to any
1588
- * other zoom on its own, so this is for stopping it *without* changing the
1595
+ * cancel an in-flight animated zoom. Any other zoom already stops the
1596
+ * animation, so this is for stopping it *without* changing the
1589
1597
  * zoom — the slider grabbing the thumb, before it has a value to commit.
1590
1598
  */
1591
1599
  function cancelZoomAnimation() {
@@ -1613,8 +1621,8 @@ export function stateModelFactory(pluginManager) {
1613
1621
  * #getter
1614
1622
  * an ideogram only reads correctly against an entire chromosome: on a
1615
1623
  * sub-region it is a meaningless slice of bands, and the centromere shows
1616
- * up as a lone half-triangle. The chromosome needs bands of its own too:
1617
- * a cytoband file often lists only the main chromosomes, not chrM or the
1624
+ * up as a lone half-triangle. The chromosome also needs bands: a cytoband
1625
+ * file often lists only the main chromosomes, not chrM or the
1618
1626
  * unplaced scaffolds
1619
1627
  */
1620
1628
  get canShowCytobands() {
@@ -1626,7 +1634,7 @@ export function stateModelFactory(pluginManager) {
1626
1634
  /**
1627
1635
  * #getter
1628
1636
  * the `showCytobands` setting gated by whether cytobands can be shown at
1629
- * all (whole chromosome with bands of its own) and by the header
1637
+ * all (whole chromosome with bands in the cytoband file) and by the header
1630
1638
  * overview they draw in being on, which the SVG export follows too
1631
1639
  */
1632
1640
  get effectiveShowCytobands() {
@@ -1750,9 +1758,8 @@ export function stateModelFactory(pluginManager) {
1750
1758
  /**
1751
1759
  * #getter
1752
1760
  * dynamic blocks represent the exact coordinates of the currently
1753
- * visible genome regions on the screen. they are similar to static
1754
- * blocks, but static blocks can go offscreen while dynamic blocks
1755
- * represent exactly what is on screen
1761
+ * visible genome regions on the screen. Static blocks can go
1762
+ * offscreen, while dynamic blocks represent exactly what is on screen
1756
1763
  */
1757
1764
  get dynamicBlocks() {
1758
1765
  return calculateDynamicBlocks(self);
@@ -1794,12 +1801,10 @@ export function stateModelFactory(pluginManager) {
1794
1801
  * The frame exists because those three are laid out across every
1795
1802
  * displayed region rather than across the viewport — it overhangs on
1796
1803
  * both sides — so their `x` values are stable under a scroll and only
1797
- * this number moves. `scalebarRefNameLabels` is the exception and says
1798
- * so: its `transform` is already a screen x, because a sticky label's
1804
+ * this number moves. `scalebarRefNameLabels` is the exception: its `transform` is already a screen x, because a sticky label's
1799
1805
  * position is a function of the scroll rather than of block geometry.
1800
1806
  *
1801
- * **The subtraction must happen here, in float64, and that is the
1802
- * load-bearing part.** `offsetPx` is a whole-genome pixel coordinate —
1807
+ * **The subtraction must happen here, in float64.** `offsetPx` is a whole-genome pixel coordinate —
1803
1808
  * hg38 chr1 at base resolution is already past 1e10 — and a length that
1804
1809
  * size does not survive the trip through CSS: the transform matrix is
1805
1810
  * float32 by the time it reaches the compositor, where consecutive
@@ -1811,13 +1816,12 @@ export function stateModelFactory(pluginManager) {
1811
1816
  * assemblies at high zoom, which is not where anyone tests. Both
1812
1817
  * operands here are large and their difference is bounded by the
1813
1818
  * overhang (a block or two), so what reaches CSS is small and exact.
1814
- * Same rule as the GPU side, one layer up —
1819
+ * This applies the GPU side's rule one layer up; see
1815
1820
  * `agent-docs/reference/BP_PRECISION.md`.
1816
1821
  *
1817
1822
  * Published because it is the one piece of coordinate arithmetic a host
1818
1823
  * drawing its own chrome would otherwise have to know, and because
1819
- * having it written out at each call site is how the two in-tree copies
1820
- * came to disagree about rounding. Round it where the content is text
1824
+ * copies written out at each call site disagree about rounding. Round it where the content is text
1821
1825
  * (a fractional offset blurs a label); leave it alone for paths and
1822
1826
  * boxes.
1823
1827
  */
@@ -1870,11 +1874,11 @@ export function stateModelFactory(pluginManager) {
1870
1874
  * sticky, transform, maxWidth, paddingLeft, text}` each. One per run of
1871
1875
  * same-refName regions, plus a "sticky" one pinned to the viewport's
1872
1876
  * left edge naming the refName under it, so panning into a chromosome
1873
- * does not scroll its own name off the screen.
1877
+ * does not scroll the chromosome's name off the screen.
1874
1878
  *
1875
- * Three rules live in here that a host drawing region names will
1876
- * otherwise rediscover the hard way, and two of them are invisible until
1877
- * the data is awkward:
1879
+ * This getter applies three rules that a host drawing region names would
1880
+ * otherwise have to rediscover, and two of them are invisible until the
1881
+ * data is awkward:
1878
1882
  *
1879
1883
  * - the sticky label rides the rightmost run that has scrolled off the
1880
1884
  * left, not the region's first block — that one is gone from
@@ -1886,7 +1890,7 @@ export function stateModelFactory(pluginManager) {
1886
1890
  * is fitted to the whole run, and `displayedRegionIndex` /
1887
1891
  * `lastDisplayedRegionIndex` bracket what it stands for.
1888
1892
  * - a name is drawn whole or not at all, measured against the space its
1889
- * run leaves. Clipped to its own width, `chr16` reads as `chr1` —
1893
+ * run leaves. Clipped to that space, `chr16` reads as `chr1` —
1890
1894
  * a different chromosome rather than a shortened name, which is why
1891
1895
  * this is a fit test rather than an ellipsis.
1892
1896
  *
@@ -1906,7 +1910,7 @@ export function stateModelFactory(pluginManager) {
1906
1910
  * pins to its right edge rather than the viewport's, and the coordinate
1907
1911
  * numbers stay out from under it. The SVG export deliberately
1908
1912
  * calls `getScalebarRefNameLabels` itself with no prefix rather than
1909
- * reading this, since it draws its own assembly name above the ruler.
1913
+ * reading this, since it draws the assembly name itself above the ruler.
1910
1914
  */
1911
1915
  get scalebarRefNameLabels() {
1912
1916
  return getScalebarRefNameLabels({
@@ -1921,7 +1925,7 @@ export function stateModelFactory(pluginManager) {
1921
1925
  * Every span along the row that is not track data, as plain geometry in
1922
1926
  * the staticBlocks frame — the same frame as gridlineTicks and
1923
1927
  * scalebarLabels, so one `translateX(staticBlocksTranslateX)` places all
1924
- * three. A host drawing its own chrome needs all three kinds:
1928
+ * three. A host that draws the row's chrome itself needs all three kinds:
1925
1929
  *
1926
1930
  * - `seam`: the 3px bar at a region's right edge. Displayed regions are
1927
1931
  * laid out **contiguously** (calculateStaticBlocks emits boundary
@@ -1936,11 +1940,11 @@ export function stateModelFactory(pluginManager) {
1936
1940
  * but the 24 chromosomes are under a pixel wide), so a host that
1937
1941
  * skips them leaves that part of the row empty.
1938
1942
  * - `boundary`: past the start of the first region or the end of the
1939
- * last. Greying it shows the last region's seam as the edge of a
1943
+ * last. Greying it makes the last region's seam read as the edge of a
1940
1944
  * filled area, where it would otherwise look like a line in the
1941
1945
  * middle of the track.
1942
1946
  *
1943
- * Elided blocks get no seam even though they carry the flag: at the
1947
+ * Elided blocks get no seam even though they have the flag: at the
1944
1948
  * zoom where regions elide, one bar per region would fill the row solid
1945
1949
  * grey.
1946
1950
  *
@@ -2042,7 +2046,7 @@ export function stateModelFactory(pluginManager) {
2042
2046
  * array of fresh objects on every pan and zoom frame, so a component
2043
2047
  * that derived this number itself re-rendered on every frame of every
2044
2048
  * gesture — to produce, whenever content fills the track, the unchanged
2045
- * `trackWidthPx`. Reading the scalar lets MobX's `===` stop the chain at
2049
+ * `trackWidthPx`. A component that reads the scalar lets MobX's `===` stop the chain at
2046
2050
  * this computed instead. Measured over 20 zoom frames: the wiggle
2047
2051
  * family's three body instances fell from 66 renders to 7.
2048
2052
  */
@@ -2181,17 +2185,16 @@ export function stateModelFactory(pluginManager) {
2181
2185
  * as a navigation that didn't happen, and wiggle's autoscale domain is
2182
2186
  * computed over the window the user just left — measured at `[0,200]`
2183
2187
  * against a correct `[0,300]` when a 40bp coarse window survived a jump to
2184
- * 4040bp on screen. Only the per-region fetch moving to the leading edge
2185
- * made that reachable: at 600ms the data never landed inside the hole.
2188
+ * 4040bp on screen.
2186
2189
  *
2187
- * **The continuous paths deliberately do not come through here.** The
2190
+ * **The continuous paths do not call this.** The
2188
2191
  * spring zoom writes through `zoomTo` per frame and a drag through
2189
2192
  * `scrollTo`, so this adds no per-frame work; the settle is idempotent
2190
2193
  * (`setCoarseDynamicBlocks` compares block keys), so the debounced
2191
- * autorun's own follow-up run costs nothing.
2194
+ * autorun's follow-up run costs nothing.
2192
2195
  *
2193
- * Every placer calls it, and `placersSettleCoarseBlocks.test.ts` is what
2194
- * makes that true of the next one — it scans this file for the writes and
2196
+ * Every placer calls it, and `placersSettleCoarseBlocks.test.ts` enforces
2197
+ * that for the next one: it scans this file for the writes and
2195
2198
  * fails on a placer that reaches neither the settle nor its named list of
2196
2199
  * continuous paths. Two passes by hand missed four.
2197
2200
  */
@@ -2252,8 +2255,8 @@ export function stateModelFactory(pluginManager) {
2252
2255
  },
2253
2256
  /**
2254
2257
  * #action
2255
- * Place the viewport by the pair of PIXEL quantities it used to be stored
2256
- * as. Prefer `setWindow`: pixels mean nothing without the width they were
2258
+ * Place the viewport by `bpPerPx` and `offsetPx`, the pixel pair the view
2259
+ * stored before it stored the window. Prefer `setWindow`: pixels mean nothing without the width they were
2257
2260
  * measured at, so a round trip through here is only exact while the width
2258
2261
  * holds still. Kept for callers that genuinely have pixels — a wheel
2259
2262
  * gesture, a rubberband.
@@ -2266,7 +2269,7 @@ export function stateModelFactory(pluginManager) {
2266
2269
  /**
2267
2270
  * #action
2268
2271
  * Place the viewport by the pair it is actually STORED as: the window's
2269
- * width and left edge, both in bp. `setNewView`'s bp-space twin, and the
2272
+ * width and left edge, both in bp. The bp-space counterpart of `setNewView`, and the
2270
2273
  * right one for anything that captures a viewport and puts it back later
2271
2274
  * (an Undo, a saved location) — those two moments can be a window resize
2272
2275
  * apart, and this pair survives one where a pixel pair does not.
@@ -2296,8 +2299,8 @@ export function stateModelFactory(pluginManager) {
2296
2299
  },
2297
2300
  /**
2298
2301
  * #action
2299
- * The worst jump of them to leave unsettled: the coarse blocks are keyed
2300
- * by `displayedRegionIndex`, so a set that outlives the region list has a
2302
+ * Settles the coarse blocks, since this is the worst jump to leave
2303
+ * unsettled: they are keyed by `displayedRegionIndex`, so a set that outlives the region list has a
2301
2304
  * consumer reading one contig's data against another's blocks.
2302
2305
  */
2303
2306
  setDisplayedRegions(regions) {
@@ -2756,7 +2759,7 @@ export function stateModelFactory(pluginManager) {
2756
2759
  /**
2757
2760
  * #method
2758
2761
  * returns menu items for a highlight context menu. plugins can extend
2759
- * this via Core-extendPluggableElement to add their own items
2762
+ * this via Core-extendPluggableElement to add items
2760
2763
  */
2761
2764
  highlightMenuItems(_highlight) {
2762
2765
  return [];
@@ -2897,12 +2900,14 @@ export function stateModelFactory(pluginManager) {
2897
2900
  return snap;
2898
2901
  }
2899
2902
  // v4's `showCytobandsSetting` persists as the bare `showCytobands` prop
2900
- // (the capability-gated getter is `effectiveShowCytobands`).
2901
- const { showCytobandsSetting, offsetPx, bpPerPx, ...rest } = snap;
2903
+ // (the capability-gated getter is `effectiveShowCytobands`), and v4's
2904
+ // `colorByCDS` as `colorByFrame`.
2905
+ const { showCytobandsSetting, colorByCDS, offsetPx, bpPerPx, ...rest } = snap;
2902
2906
  return {
2903
2907
  ...(showCytobandsSetting !== undefined
2904
2908
  ? { showCytobands: showCytobandsSetting }
2905
2909
  : {}),
2910
+ ...(colorByCDS !== undefined ? { colorByFrame: colorByCDS } : {}),
2906
2911
  // The viewport used to persist as pixels. Half of that converts
2907
2912
  // exactly and needs no width — the left edge in bp is offsetPx *
2908
2913
  // bpPerPx — and half of it cannot convert at all, because the width
@@ -11,6 +11,7 @@ const READERS = {
11
11
  adapters: {
12
12
  Gff3TabixAdapter: { slot: 'gffGzLocation', ext: /\.gff3?\.gz$/ },
13
13
  Gff3Adapter: { slot: 'gffLocation', ext: /\.gff3?$/ },
14
+ GtfTabixAdapter: { slot: 'gtfGzLocation', ext: /\.gtf\.gz$/ },
14
15
  GtfAdapter: { slot: 'gtfLocation', ext: /\.gtf$/ },
15
16
  BedTabixAdapter: { slot: 'bedGzLocation', ext: /\.bed\.gz$/ },
16
17
  BedAdapter: { slot: 'bedLocation', ext: /\.bed$/ },
@@ -126,7 +126,7 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
126
126
  * (hidden sections, collapses, height overrides: `groupStateKey`), which are
127
127
  * volatile and in no snapshot; **the reload counter**, since a Retry or a Force
128
128
  * load leaves every snapshot as it was while the figure has an error or a
129
- * too-large note to replace; **the view's coloring toggles** (`colorByCDS`,
129
+ * too-large note to replace; **the view's coloring toggles** (`colorByFrame`,
130
130
  * `showAminoAcids`), named one by one because the view's own snapshot moves
131
131
  * every pan frame; **the width**, since a resize can widen the canvas without
132
132
  * moving the locus; **the theme**, since each display bakes colors into its own
@@ -172,7 +172,7 @@ function figureKey(view, themeName) {
172
172
  display?.reloadCounter,
173
173
  ];
174
174
  }),
175
- view.colorByCDS,
175
+ view.colorByFrame,
176
176
  view.showAminoAcids,
177
177
  session.getActiveThemeOptions?.(themeName),
178
178
  session.highlightsVisible ? view.highlights : false,
package/esm/index.js CHANGED
@@ -19,7 +19,7 @@ export default class LinearGenomeViewPlugin extends Plugin {
19
19
  configurationSchema = ConfigurationSchema('LinearGenomeViewConfigSchema', {
20
20
  /**
21
21
  * #slot configuration.LinearGenomeViewPlugin.trackLabels
22
- * The placement of a track's name: `offset` gives it its own line above the
22
+ * The placement of a track's name: `offset` puts it on a line above the
23
23
  * data, `overlapping` floats it over the top of the data to save vertical
24
24
  * space, `hidden` omits it. The view menu's "Track labels" submenu sets the
25
25
  * same thing per session
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jbrowse/plugin-linear-genome-view",
3
- "version": "5.0.0-beta.15",
3
+ "version": "5.0.0-beta.17",
4
4
  "type": "module",
5
5
  "description": "JBrowse 2 linear genome view",
6
6
  "keywords": [
@@ -26,10 +26,10 @@
26
26
  "@mui/material": "^9.5.0",
27
27
  "mobx": "^7.0.6",
28
28
  "mobx-react": "^10.0.2",
29
- "@jbrowse/display-kit": "^5.0.0-beta.15",
30
- "@jbrowse/display-ui": "^5.0.0-beta.15",
31
- "@jbrowse/core": "^5.0.0-beta.15",
32
- "@jbrowse/render-core": "^5.0.0-beta.15"
29
+ "@jbrowse/core": "^5.0.0-beta.17",
30
+ "@jbrowse/display-ui": "^5.0.0-beta.17",
31
+ "@jbrowse/render-core": "^5.0.0-beta.17",
32
+ "@jbrowse/display-kit": "^5.0.0-beta.17"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "react": ">=19.0.0",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "sideEffects": false,
42
42
  "devDependencies": {
43
- "@jbrowse/display-test-utils": "^5.0.0-beta.15"
43
+ "@jbrowse/display-test-utils": "^5.0.0-beta.17"
44
44
  },
45
45
  "scripts": {
46
46
  "prebuild": "pnpm clean",