@jbrowse/plugin-linear-genome-view 5.0.0-beta.1 → 5.0.0-beta.10

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.
Files changed (145) hide show
  1. package/esm/FeatureTrack/configSchema.d.ts +142 -50
  2. package/esm/LaunchLinearGenomeView/index.js +2 -13
  3. package/esm/LinearGenomeView/afterAttach.d.ts +5 -5
  4. package/esm/LinearGenomeView/afterAttach.js +73 -59
  5. package/esm/LinearGenomeView/components/CenterLine.js +5 -3
  6. package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
  7. package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +3 -2
  8. package/esm/LinearGenomeView/components/ExportSvgDialog.js +6 -2
  9. package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
  10. package/esm/LinearGenomeView/components/Header.js +11 -1
  11. package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
  12. package/esm/LinearGenomeView/components/HeaderPanControls.js +2 -1
  13. package/esm/LinearGenomeView/components/HeaderZoomControls.js +4 -34
  14. package/esm/LinearGenomeView/components/Highlight.js +7 -7
  15. package/esm/LinearGenomeView/components/HighlightBand.js +2 -2
  16. package/esm/LinearGenomeView/components/HighlightChip.d.ts +1 -2
  17. package/esm/LinearGenomeView/components/HighlightChip.js +5 -7
  18. package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
  19. package/esm/LinearGenomeView/components/ImportForm.js +2 -2
  20. package/esm/LinearGenomeView/components/LinearGenomeView.js +3 -3
  21. package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +3 -4
  22. package/esm/LinearGenomeView/components/MiniControls.js +3 -2
  23. package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
  24. package/esm/LinearGenomeView/components/OverviewHighlightBand.js +2 -3
  25. package/esm/LinearGenomeView/components/OverviewRubberband.js +20 -45
  26. package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
  27. package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
  28. package/esm/LinearGenomeView/components/PaddingBlocks.d.ts +1 -1
  29. package/esm/LinearGenomeView/components/PaddingBlocks.js +14 -9
  30. package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
  31. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
  32. package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +71 -0
  33. package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
  34. package/esm/LinearGenomeView/components/Rubberband.js +3 -2
  35. package/esm/LinearGenomeView/components/SVGHighlightBand.js +2 -3
  36. package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
  37. package/esm/LinearGenomeView/components/Scalebar.js +8 -5
  38. package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +49 -34
  39. package/esm/LinearGenomeView/components/SearchBox.js +8 -7
  40. package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +2 -1
  41. package/esm/LinearGenomeView/components/SearchResultsDialog.js +2 -2
  42. package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +2 -1
  43. package/esm/LinearGenomeView/components/SearchResultsTable.js +12 -29
  44. package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
  45. package/esm/LinearGenomeView/components/TrackContainer.js +63 -9
  46. package/esm/LinearGenomeView/components/TrackLabel.js +10 -3
  47. package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
  48. package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +2 -2
  49. package/esm/LinearGenomeView/components/TrackLabelMenu.js +3 -2
  50. package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +4 -1
  51. package/esm/LinearGenomeView/components/TrackRenderingContainer.js +11 -23
  52. package/esm/LinearGenomeView/components/TracksContainer.js +10 -22
  53. package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
  54. package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
  55. package/esm/LinearGenomeView/components/ZoomButton.js +6 -1
  56. package/esm/LinearGenomeView/components/ZoomTransform.js +4 -0
  57. package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
  58. package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
  59. package/esm/LinearGenomeView/components/searchModes.d.ts +1 -1
  60. package/esm/LinearGenomeView/components/searchModes.js +1 -1
  61. package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
  62. package/esm/LinearGenomeView/components/useRangeSelect.js +20 -59
  63. package/esm/LinearGenomeView/components/useSideScroll.d.ts +16 -2
  64. package/esm/LinearGenomeView/components/useSideScroll.js +153 -103
  65. package/esm/LinearGenomeView/components/util.d.ts +4 -0
  66. package/esm/LinearGenomeView/components/util.js +4 -2
  67. package/esm/LinearGenomeView/consts.d.ts +2 -0
  68. package/esm/LinearGenomeView/consts.js +3 -1
  69. package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
  70. package/esm/LinearGenomeView/containingLgv.js +23 -0
  71. package/esm/LinearGenomeView/headerFit.d.ts +4 -2
  72. package/esm/LinearGenomeView/headerFit.js +20 -7
  73. package/esm/LinearGenomeView/index.d.ts +1 -5
  74. package/esm/LinearGenomeView/index.js +10 -7
  75. package/esm/LinearGenomeView/keyboardHandler.d.ts +2 -0
  76. package/esm/LinearGenomeView/keyboardHandler.js +15 -1
  77. package/esm/LinearGenomeView/launchKeys.d.ts +2 -0
  78. package/esm/LinearGenomeView/launchKeys.js +27 -0
  79. package/esm/LinearGenomeView/lazyDialogs.d.ts +2 -4
  80. package/esm/LinearGenomeView/lazyDialogs.js +1 -0
  81. package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
  82. package/esm/LinearGenomeView/linkedViewSync.js +27 -43
  83. package/esm/LinearGenomeView/menuItems.d.ts +16 -18
  84. package/esm/LinearGenomeView/menuItems.js +242 -151
  85. package/esm/LinearGenomeView/model.d.ts +2009 -200
  86. package/esm/LinearGenomeView/model.js +545 -395
  87. package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
  88. package/esm/LinearGenomeView/showRegionsWithUndo.js +7 -1
  89. package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
  90. package/esm/LinearGenomeView/stickyChrome.js +5 -9
  91. package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
  92. package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
  93. package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
  94. package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +8 -8
  95. package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +3 -3
  96. package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +7 -11
  97. package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
  98. package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
  99. package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
  100. package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
  101. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +27 -0
  102. package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
  103. package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +15 -6
  104. package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -4
  105. package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +6 -5
  106. package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +1 -1
  107. package/esm/LinearGenomeView/svgcomponents/SVGView.js +1 -1
  108. package/esm/LinearGenomeView/svgcomponents/figureContract.js +14 -14
  109. package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +1 -1
  110. package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +50 -68
  111. package/esm/LinearGenomeView/svgcomponents/util.d.ts +9 -5
  112. package/esm/LinearGenomeView/svgcomponents/util.js +26 -21
  113. package/esm/LinearGenomeView/types.d.ts +8 -11
  114. package/esm/LinearGenomeView/util.d.ts +60 -45
  115. package/esm/LinearGenomeView/util.js +131 -160
  116. package/esm/MultiLevelRubberband/MultiLevelRubberband.js +7 -4
  117. package/esm/MultiLevelRubberband/index.d.ts +2 -0
  118. package/esm/MultiLevelRubberband/index.js +2 -0
  119. package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
  120. package/esm/MultiLevelRubberband/menuItems.js +52 -0
  121. package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
  122. package/esm/MultiLevelRubberband/rowLabel.js +27 -0
  123. package/esm/MultiLevelRubberband/types.d.ts +1 -0
  124. package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
  125. package/esm/MultiLevelRubberband/useRangeSelect.js +31 -47
  126. package/esm/displayKitTests/perRegionTestEnv.d.ts +214 -86
  127. package/esm/displayKitTests/perRegionTestEnv.js +30 -29
  128. package/esm/index.d.ts +15 -85
  129. package/esm/index.js +13 -36
  130. package/esm/searchUtils.d.ts +18 -9
  131. package/esm/searchUtils.js +85 -69
  132. package/esm/shared/RubberbandSpan.js +2 -1
  133. package/esm/shared/coordLabels.d.ts +7 -0
  134. package/esm/shared/coordLabels.js +15 -1
  135. package/esm/shared/useWindowDrag.d.ts +18 -0
  136. package/esm/shared/useWindowDrag.js +45 -0
  137. package/package.json +10 -10
  138. package/esm/LinearGenomeView/FloatingSvgOverlay.d.ts +0 -5
  139. package/esm/LinearGenomeView/FloatingSvgOverlay.js +0 -25
  140. package/esm/LinearGenomeView/initKeys.d.ts +0 -13
  141. package/esm/LinearGenomeView/initKeys.js +0 -104
  142. package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
  143. package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
  144. package/esm/lazyPluginExports.d.ts +0 -23
  145. package/esm/lazyPluginExports.js +0 -36
@@ -1,17 +1,14 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { memo, useCallback, useEffect, useRef, useSyncExternalStore, } from 'react';
3
+ import { SvgThemeProviders } from '@jbrowse/core/svg/SvgThemeProviders';
3
4
  import { exportMargin } from '@jbrowse/core/svg/constants';
5
+ import { svgNodeId } from '@jbrowse/core/svg/svgId';
4
6
  import { svgTrackName } from '@jbrowse/core/svg/trackNames';
5
- import { StyleThemeProvider } from '@jbrowse/core/ui/PaletteContext';
6
- import { resolveStyleTheme } from '@jbrowse/core/ui/styleTheme';
7
- import { createJBrowseTheme } from '@jbrowse/core/ui/theme';
8
7
  import { getSession } from '@jbrowse/core/util';
9
8
  import { useFetch } from '@jbrowse/core/util/useFetch';
10
- import { isAlive } from '@jbrowse/mobx-state-tree';
11
- import { ThemeProvider } from '@mui/material';
9
+ import { getSnapshot, isAlive } from '@jbrowse/mobx-state-tree';
12
10
  import { reaction } from 'mobx';
13
- import SVGRowHeader from './SVGRowHeader.js';
14
- import SVGView from './SVGView.js';
11
+ import SVGStackedRow from './SVGStackedRow.js';
15
12
  import { useFrozenFigureContract, useOneFigurePerView, } from './figureContract.js';
16
13
  import { renderViewTracks } from './renderViewTracks.js';
17
14
  import { defaultTextHeight, getRowHeaderLayout, trackLabelLeftOffset, } from './util.js';
@@ -87,38 +84,31 @@ async function renderFigure(view, opts) {
87
84
  * render. Where it matters, this line is the only thing holding the two halves
88
85
  * together.
89
86
  *
90
- * Both providers, as `wrapSvgExport` mounts for the file path, and for the same
91
- * reason: the chrome takes its colors from the Material UI theme and a
92
- * `makeStyles` component would take its own from the style theme, so a figure
93
- * mounted in a host that installs neither would otherwise draw itself in
94
- * JBrowse's *default light* theme whatever the session is set to.
87
+ * The export's theme providers, as the file path mounts them: a host that
88
+ * installs neither would otherwise get JBrowse's default light theme whatever
89
+ * the session is set to.
95
90
  *
96
91
  * No background rect, unlike a file — that has nothing behind it, and a figure
97
- * in a page has the page. No `resetSvgClipIds` either, and that is the opposite
98
- * decision from the file path on purpose: the counter is document-global, so
99
- * resetting it here would renumber ids that a figure already on the page is
100
- * pointing at. Letting it run is what makes several live figures unique.
92
+ * in a page has the page. No `withFreshSvgClipIds` either, and that is the
93
+ * opposite decision from the file path on purpose: the counter is
94
+ * document-global, so restarting it here would reuse ids that a figure already
95
+ * on the page is pointing at. Letting it run is what makes several live figures
96
+ * unique.
101
97
  */
102
98
  const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
103
99
  const { width, height, margin, theme } = snapshot;
104
- // dev-only, and it watches for the one thing this component cannot enforce:
105
- // an observer INSIDE the tree, which the memo above is not between
100
+ // it watches for the one thing this component cannot enforce: an observer
101
+ // INSIDE the tree, which the memo above is not between
106
102
  const ref = useRef(null);
107
103
  useFrozenFigureContract(ref, snapshot);
108
- return (_jsx(ThemeProvider, { theme: createJBrowseTheme(theme), children: _jsx(StyleThemeProvider, { theme: resolveStyleTheme({ configTheme: theme }), children: _jsx("svg", { ref: ref, width: width, height: height, viewBox: `0 0 ${width} ${height}`,
109
- // It is a vector, so a narrower container scales it rather than
110
- // clipping it; the height attribute stays, so a box reserved for it
111
- // does not change size when that happens. Deliberately not a prop:
112
- // anything passed per-render would have to reach past the memo above,
113
- // which is the one thing holding the figure's two halves together. A
114
- // host that wants other sizing wraps this in a box of its own.
115
- style: { display: 'block', maxWidth: '100%' }, children: _jsx("g", { transform: `translate(${margin} ${snapshot.bandHeight})`, children: _jsx(SVGView, { view: view, displayResults: snapshot.displayResults, header: _jsx(SVGRowHeader, { view: view, fontSize: snapshot.fontSize, rulerHeight: snapshot.rulerHeight, showScalebar: snapshot.showScalebar }), fontSize: snapshot.fontSize, textHeight: snapshot.textHeight, trackLabels: snapshot.trackLabels, trackLabelOffset: snapshot.trackLabelOffset,
116
- // the row header is exactly the ruler, so the bodies start at its
117
- // height
118
- contentTop: snapshot.rulerHeight, tracksHeight: snapshot.tracksHeight, showGridlines: snapshot.showGridlines,
119
- // the left gutter the per-track clip may bleed into, so content
120
- // drawn left of zero — a wiggle's y-axis — survives
121
- leftBuffer: snapshot.margin, legendWidth: snapshot.legendWidth }) }) }) }) }));
104
+ return (_jsx(SvgThemeProviders, { theme: theme, children: _jsx("svg", { ref: ref, width: width, height: height, viewBox: `0 0 ${width} ${height}`,
105
+ // It is a vector, so a narrower container scales it rather than
106
+ // clipping it; the height attribute stays, so a box reserved for it
107
+ // does not change size when that happens. Deliberately not a prop:
108
+ // anything passed per-render would have to reach past the memo above,
109
+ // which is the one thing holding the figure's two halves together. A
110
+ // host that wants other sizing wraps this in a box of its own.
111
+ style: { display: 'block', maxWidth: '100%' }, children: _jsx(SVGStackedRow, { view: view, rendered: snapshot, top: snapshot.bandHeight, margin: margin, fontSize: snapshot.fontSize, textHeight: snapshot.textHeight, rulerHeight: snapshot.rulerHeight, trackLabels: snapshot.trackLabels, trackLabelOffset: snapshot.trackLabelOffset, showGridlines: snapshot.showGridlines, legendWidth: snapshot.legendWidth, showScalebar: snapshot.showScalebar }) }) }));
122
112
  });
123
113
  /**
124
114
  * What "the figure is out of date" means, as a string.
@@ -141,11 +131,10 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
141
131
  * highlight bands**, which are drawn in the figure and are the one thing in it a
142
132
  * reader adds without navigating anywhere.
143
133
  *
144
- * A plugin's own overlay (grid-bookmark's bookmarks, through
145
- * `LinearGenomeView-HighlightSVGComponent`) is state this cannot see, so a
146
- * bookmark added under a drawn figure shows up at its next redraw rather than at
147
- * once. Subscribing from inside the figure is the thing that must not happen —
148
- * see the note at the top of the file.
134
+ * A plugin's own overlay, through `LinearGenomeView-HighlightSVGComponent`, is
135
+ * state this cannot see, so a change to it shows up at the figure's next
136
+ * redraw rather than at once. Subscribing from inside the figure is the thing
137
+ * that must not happen — see the note at the top of the file.
149
138
  */
150
139
  function figureKey(view, themeName) {
151
140
  // A closed view is not an error, it is a host doing an ordinary thing in an
@@ -156,10 +145,10 @@ function figureKey(view, themeName) {
156
145
  // throw a TypeError inside the reaction, where MobX swallows it. No key means
157
146
  // no figure, which is what a host that closed the view wanted anyway.
158
147
  //
159
- // `view.width` throws by design before the view has been measured, and
160
- // `ready` is the gate that says it has been — and that there are regions to
161
- // draw, which is the second async step `initialized` does not cover
162
- if (!isAlive(view) || !view.ready) {
148
+ // `view.width` throws by design before the view has been measured. `status`
149
+ // is ready only once it has been AND there are regions to draw — `ready` is
150
+ // also true for a view nothing has told where to look, measured or not
151
+ if (!isAlive(view) || view.status.type !== 'ready') {
163
152
  return '';
164
153
  }
165
154
  const session = getSession(view);
@@ -167,14 +156,12 @@ function figureKey(view, themeName) {
167
156
  view.coarseVisibleLocStrings,
168
157
  view.coarseBpPerPx,
169
158
  view.width,
170
- view.tracks.map(track => [
171
- track.configuration.trackId,
172
- track.minimized,
173
- track.displays[0]?.height,
174
- ]),
159
+ // the snapshot carries pinned, minimized and the display settings a body
160
+ // bakes in; the effective height is a getter, so it is read beside it
161
+ view.tracks.map(track => [getSnapshot(track), track.displays[0]?.height]),
175
162
  session.getActiveThemeOptions?.(themeName),
176
- session.highlightsVisible ? view.highlight : false,
177
- view.labelsVisible,
163
+ session.highlightsVisible ? view.highlights : false,
164
+ session.highlightLabelsVisible,
178
165
  ]);
179
166
  }
180
167
  /**
@@ -212,25 +199,7 @@ function useFigureKey(view, themeName) {
212
199
  export function useViewSvgFigure(view, { fontSize = 12, rulerHeight = 30, trackLabels = 'offset', showGridlines = true, showScalebar = true, rasterizeLayers = false, margin = exportMargin, themeName, } = {}) {
213
200
  const key = useFigureKey(view, themeName);
214
201
  useOneFigurePerView(view);
215
- const { data: snapshot, error, isLoading, } = useFetch(
216
- // Every option is in the key by value, so an inline options object costs
217
- // nothing and a changed option redraws. A null key is `useFetch`'s own "not
218
- // yet", which is what an unready view reports.
219
- key
220
- ? [
221
- 'lgv-svg-figure',
222
- key,
223
- JSON.stringify([
224
- fontSize,
225
- rulerHeight,
226
- trackLabels,
227
- showGridlines,
228
- showScalebar,
229
- rasterizeLayers,
230
- margin,
231
- ]),
232
- ]
233
- : null, () => renderFigure(view, {
202
+ const opts = {
234
203
  fontSize,
235
204
  rulerHeight,
236
205
  trackLabels,
@@ -239,7 +208,20 @@ export function useViewSvgFigure(view, { fontSize = 12, rulerHeight = 30, trackL
239
208
  rasterizeLayers,
240
209
  margin,
241
210
  themeName,
242
- }));
211
+ };
212
+ const { data: snapshot, error, isLoading, } = useFetch(
213
+ // Every option is in the key by value, so an inline options object costs
214
+ // nothing and a changed option redraws. The view's id too: two views can
215
+ // share every other term. A null key is `useFetch`'s own "not yet", which
216
+ // is what an unready view reports.
217
+ key
218
+ ? [
219
+ 'lgv-svg-figure',
220
+ svgNodeId(view),
221
+ key,
222
+ JSON.stringify(opts),
223
+ ]
224
+ : null, () => renderFigure(view, opts));
243
225
  // Written in an effect and read during render, which is the order that makes
244
226
  // it work: a key change clears `data` on the render where the ref still holds
245
227
  // the previous commit's size, so the host's box keeps the height it had rather
@@ -5,6 +5,7 @@ import type { ReactNode } from 'react';
5
5
  interface TrackHeights {
6
6
  displays: {
7
7
  height: number;
8
+ prefersOffset?: boolean;
8
9
  }[];
9
10
  }
10
11
  export interface SvgDisplayResult {
@@ -12,6 +13,8 @@ export interface SvgDisplayResult {
12
13
  configuration: AnyConfigurationModel;
13
14
  displays: {
14
15
  height: number;
16
+ regionTooLarge?: boolean;
17
+ drawsWhenTooLarge?: boolean;
15
18
  }[];
16
19
  };
17
20
  result: ReactNode;
@@ -58,6 +61,7 @@ export declare function getRowHeaderLayout({ fontSize, showScalebar, }: {
58
61
  assemblyLabelBaselineY: number;
59
62
  bandHeight: number;
60
63
  };
64
+ export type HeaderLayout = ReturnType<typeof getHeaderLayout>;
61
65
  export declare function getHeaderLayout({ fontSize, showCytobands, rulerHeight, }: {
62
66
  fontSize: number;
63
67
  showCytobands: boolean;
@@ -71,14 +75,14 @@ export declare function getHeaderLayout({ fontSize, showCytobands, rulerHeight,
71
75
  };
72
76
  export declare const RULER_MAJOR_TICK = 5;
73
77
  export declare const RULER_MINOR_TICK = 3;
74
- export declare const RULER_TICK_FONT_SIZE = 11;
75
78
  export declare function getRulerLayout(rulerHeight: number): {
76
79
  tickTopY: number;
77
80
  numbersBaselineY: number;
78
81
  };
79
82
  export declare const refNameLabelBoxHeight: number;
80
83
  export declare const refNameLabelBaselineY: number;
81
- export declare function labelOffset(trackLabels: TrackLabelMode, textHeight: number): number;
84
+ export declare function trackLabelMode(track: TrackHeights, trackLabels: TrackLabelMode): TrackLabelMode;
85
+ export declare function labelOffset(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
82
86
  export declare const TRACK_LABEL_GAP = 40;
83
87
  export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }: {
84
88
  tracks: {
@@ -89,7 +93,7 @@ export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fo
89
93
  fontFamily?: string;
90
94
  session: TrackCatalog;
91
95
  }): number;
92
- export declare function trackBoxHeight(track: TrackHeights, textOffset: number): number;
93
- export declare function trackBoxOffsets(tracks: TrackHeights[], textOffset: number): number[];
94
- export declare function totalHeight(tracks: TrackHeights[], textHeight: number, trackLabels: TrackLabelMode): number;
96
+ export declare function trackBoxHeight(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
97
+ export declare function trackBoxOffsets(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number[];
98
+ export declare function totalHeight(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number;
95
99
  export {};
@@ -80,7 +80,7 @@ export function defaultTextHeight(fontSize) {
80
80
  export function offsetLabelBaselineY(textHeight, fontSize) {
81
81
  return textHeight - LABEL_PAD_BOTTOM - labelDescent(fontSize);
82
82
  }
83
- // Baseline for a label inset into the top of the box it draws over ('overlay'
83
+ // Baseline for a label inset into the top of the box it draws over ('overlapping'
84
84
  // mode), measured down from that top edge so the ascenders stay inside it.
85
85
  export function insetLabelBaselineY(fontSize) {
86
86
  return labelBaselineFromTop(LABEL_PAD_TOP, fontSize);
@@ -99,6 +99,9 @@ export function insetLabelBaselineY(fontSize) {
99
99
  // scale in each row the only thing saying whether two rows are at the same zoom
100
100
  // is their ruler coordinates, which are unreadable at the size a figure is
101
101
  // published at. The standalone LGV export has drawn this bar all along.
102
+ //
103
+ // The name's band is reserved whether or not the row draws one: a breakpoint
104
+ // split view names its first row only, and the rest stay the same height as it.
102
105
  export function getRowHeaderLayout({ fontSize, showScalebar, }) {
103
106
  const label = labelInkHeight(fontSize);
104
107
  // the bp label hangs a cap below the bar's line and its own ink box ends a gap
@@ -111,8 +114,10 @@ export function getRowHeaderLayout({ fontSize, showScalebar, }) {
111
114
  // ink box rather than by baseline, because the gaps are fixed while a font's
112
115
  // descent is not: laying the label out from its baseline instead put its
113
116
  // descenders through that cap at the larger export fonts.
117
+ // without a scalebar the name sits on its baseline at the origin, its
118
+ // descenders into the ruler's top, so only the ink above the baseline counts
114
119
  const assemblyInkTop = scalebarLineY === undefined
115
- ? -label
120
+ ? -labelBaselineFromTop(0, fontSize)
116
121
  : scalebarLineY - SVG_SCALEBAR_CAP - ROW_GAP - label;
117
122
  return {
118
123
  // undefined rather than an unused number: a row without a scalebar has no
@@ -123,17 +128,9 @@ export function getRowHeaderLayout({ fontSize, showScalebar, }) {
123
128
  assemblyLabelBaselineY: showScalebar
124
129
  ? labelBaselineFromTop(assemblyInkTop, fontSize)
125
130
  : 0,
126
- // up from the ruler to the top of the topmost ink box — the assembly
127
- // label's, in both cases
128
131
  bandHeight: -assemblyInkTop,
129
132
  };
130
133
  }
131
- // Compact vertical layout for the exported header: rows (assembly name,
132
- // cytoband overview, "you are here" polygon, total-bp scalebar, ruler) are
133
- // stacked with a small fixed gap rather than reserving loose fixed-height
134
- // bands, so nothing is separated by dead space. `tracksTop` is where the track
135
- // bodies begin (renderToSvg's `offset`). Shared by SVGHeader and renderToSvg so
136
- // the header height and the track origin can't drift.
137
134
  export function getHeaderLayout({ fontSize, showCytobands, rulerHeight, }) {
138
135
  // the assembly name is drawn on its ink box, not on `fontSize`: at y=0 with a
139
136
  // hanging baseline its ascenders rose above the export's top edge and got
@@ -161,7 +158,6 @@ export function getHeaderLayout({ fontSize, showCytobands, rulerHeight, }) {
161
158
  // Ruler tick geometry, shared by the tick marks and their number labels.
162
159
  export const RULER_MAJOR_TICK = 5;
163
160
  export const RULER_MINOR_TICK = 3;
164
- export const RULER_TICK_FONT_SIZE = 11;
165
161
  // clearance between the tick-number baseline and the marks below it
166
162
  const RULER_TICK_LABEL_GAP = 2;
167
163
  // Vertical positions within a ruler of the given budget: tick marks hang just
@@ -180,9 +176,17 @@ export function getRulerLayout(rulerHeight) {
180
176
  // 13, and both ends of the glyphs at any smaller export font.
181
177
  export const refNameLabelBoxHeight = labelInkHeight(REF_NAME_LABEL_FONT_SIZE);
182
178
  export const refNameLabelBaselineY = labelBaselineFromTop(0, REF_NAME_LABEL_FONT_SIZE);
183
- // space the label pushes a track down by; only 'offset' mode does
184
- export function labelOffset(trackLabels, textHeight) {
185
- return trackLabels === 'offset' ? textHeight : 0;
179
+ // The mode one track's label is drawn in. 'overlapping' yields to 'offset' for a
180
+ // display that `prefersOffset`, as TrackContainer does on screen: its left edge
181
+ // carries content — an axis, a sample's genotypes — the label would print over.
182
+ export function trackLabelMode(track, trackLabels) {
183
+ return trackLabels === 'overlapping' && track.displays[0]?.prefersOffset
184
+ ? 'offset'
185
+ : trackLabels;
186
+ }
187
+ // space the label pushes a track's body down by; only 'offset' mode does
188
+ export function labelOffset(track, trackLabels, textHeight) {
189
+ return trackLabelMode(track, trackLabels) === 'offset' ? textHeight : 0;
186
190
  }
187
191
  // Gap between a 'left' track label's right edge and the track body.
188
192
  // SVGTrackLabel right-aligns its text at `trackLabelOffset - TRACK_LABEL_GAP`,
@@ -216,23 +220,24 @@ export function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily
216
220
  }
217
221
  // vertical box a single track occupies. Shared by totalHeight (sum) and
218
222
  // trackBoxOffsets (prefix-sum) so the two can't drift.
219
- export function trackBoxHeight(track, textOffset) {
220
- return track.displays[0].height + textOffset + trackSpacing;
223
+ export function trackBoxHeight(track, trackLabels, textHeight) {
224
+ return (track.displays[0].height +
225
+ labelOffset(track, trackLabels, textHeight) +
226
+ trackSpacing);
221
227
  }
222
228
  // Top y of each track's box within a stack of them. SVGTracks lays the bodies
223
229
  // out with it and the breakpoint-split export anchors its overlay ribbons with
224
230
  // it, so one implementation rather than two prefix-sums that must agree —
225
231
  // they drifted by trackSpacing per track when they didn't.
226
- export function trackBoxOffsets(tracks, textOffset) {
232
+ export function trackBoxOffsets(tracks, trackLabels, textHeight) {
227
233
  const offsets = [];
228
234
  let total = 0;
229
235
  for (const track of tracks) {
230
236
  offsets.push(total);
231
- total += trackBoxHeight(track, textOffset);
237
+ total += trackBoxHeight(track, trackLabels, textHeight);
232
238
  }
233
239
  return offsets;
234
240
  }
235
- export function totalHeight(tracks, textHeight, trackLabels) {
236
- const textOffset = labelOffset(trackLabels, textHeight);
237
- return sum(tracks.map(t => trackBoxHeight(t, textOffset)));
241
+ export function totalHeight(tracks, trackLabels, textHeight) {
242
+ return sum(tracks.map(t => trackBoxHeight(t, trackLabels, textHeight)));
238
243
  }
@@ -1,20 +1,16 @@
1
1
  import type { LinearGenomeViewStateModel } from './model.ts';
2
- import type { HighlightType } from '@jbrowse/core/util/highlights';
2
+ import type { BpOffset as CoreBpOffset } from '@jbrowse/core/util/Base1DUtils';
3
+ import type { HighlightInput, HighlightType } from '@jbrowse/core/util/highlights';
3
4
  import type { TrackInit } from '@jbrowse/core/util/tracks';
4
5
  import type { SnapshotIn } from '@jbrowse/mobx-state-tree';
5
- export interface BpOffset {
6
- refName?: string;
7
- index: number;
8
- offset: number;
9
- start?: number;
10
- end?: number;
6
+ export interface BpOffset extends CoreBpOffset {
11
7
  coord?: number;
12
8
  reversed?: boolean;
13
9
  assemblyName?: string;
14
10
  oob?: boolean;
15
11
  }
16
- export type { ExportSvgOptions, TrackLabelMode, } from '@jbrowse/display-kit/types';
17
- export type { HighlightType };
12
+ export type { ExportSvgOptions, TrackLabelMode, ViewTrackLabelMode, } from '@jbrowse/display-kit/types';
13
+ export type { HighlightInput, HighlightType };
18
14
  export interface NavLocation {
19
15
  refName: string;
20
16
  start?: number;
@@ -34,11 +30,12 @@ export interface InitState {
34
30
  */
35
31
  loc?: string;
36
32
  grow?: number;
33
+ showHitTrack?: boolean;
37
34
  assembly: string;
38
35
  displayedRegionNames?: string[];
39
36
  tracks?: TrackInit[];
40
37
  tracklist?: boolean;
41
38
  nav?: boolean;
42
- highlight?: (string | HighlightType)[];
39
+ highlight?: (string | HighlightInput)[];
43
40
  }
44
- export type LinearGenomeViewLaunchProps = Partial<Omit<SnapshotIn<LinearGenomeViewStateModel>, keyof InitState | 'id' | 'type' | 'init'>>;
41
+ export type LinearGenomeViewLaunchProps = Partial<Omit<SnapshotIn<LinearGenomeViewStateModel>, keyof InitState | 'id' | 'type' | 'launch'>>;
@@ -1,6 +1,14 @@
1
1
  import type { AssemblyManager, ParsedLocString } from '@jbrowse/core/util';
2
+ import type { PxToBpResult } from '@jbrowse/core/util/Base1DUtils';
2
3
  import type { BaseBlock, ContentBlock } from '@jbrowse/core/util/blockTypes';
3
4
  import type { Region } from '@jbrowse/core/util/types';
5
+ interface CenterKeepingView {
6
+ width: number;
7
+ displayedRegions: Region[];
8
+ pxToBp: (px: number) => PxToBpResult;
9
+ setDisplayedRegions: (regions: Region[]) => void;
10
+ centerAt: (coord: number, refName: string, index?: number) => void;
11
+ }
4
12
  /**
5
13
  * The stored viewport of a view showing `totalBp` of displayed regions fitted to
6
14
  * `width` — the regions filling it edge to edge, and centered in it only where
@@ -64,7 +72,7 @@ export interface Tick {
64
72
  * `makeBlockTicks`. What the two do share is already shared: `chooseGridPitch`,
65
73
  * and `base` as the 0-based coordinate that `getTickDisplayStr` labels `base+1`.
66
74
  */
67
- export declare function makeTicks(start: number, end: number, bpPerPx: number, emitMajor?: boolean, emitMinor?: boolean): Tick[];
75
+ export declare function makeTicks(start: number, end: number, bpPerPx: number, includeMinor?: boolean): Tick[];
68
76
  /** A block's refName, or undefined for non-content (elided/padding) blocks. */
69
77
  export declare function getBlockRefName(block: BaseBlock): string | undefined;
70
78
  /**
@@ -104,48 +112,31 @@ export interface ScalebarRefNameLabel {
104
112
  }
105
113
  /**
106
114
  * Builds the refName labels drawn along the scalebar as plain data (no JSX): one
107
- * label per run of same-refName regions (deduped so collapsed introns don't
108
- * repeat the name) plus a "sticky" label pinned to the left edge naming the
109
- * refName under the viewport's left border.
110
- *
111
- * `caption` is the row-level chip at the viewport's left edge, and it says two
112
- * things: which assembly this row is (`prefix`, an assembly name, synteny only)
113
- * and whether the row is flipped. Without it a row of stacked genomes would
114
- * label some rows with the assembly name and some without, depending only on
115
- * how wide their leftmost chromosome happens to be.
115
+ * label per run of same-refName regions, the leftmost of them "sticky" — pinned
116
+ * so the run under the left edge stays named once its own left edge scrolls off.
116
117
  *
117
- * The assembly name alone folds into the sticky label instead — "prefix:refName"
118
- * — whenever the two would collide at the left edge, and stands alone when the
119
- * sticky label sits far enough right not to (a view scrolled left of its first
120
- * region, so the row's data starts mid-viewport) or when there is no sticky
121
- * label at all.
118
+ * `caption` is the row-level chip at the viewport's left edge: which assembly
119
+ * the row is (`prefix`, synteny only) and whether the whole row is flipped. The
120
+ * chip takes `captionSpanPx` of the strip and the labels get the rest, so the
121
+ * sticky label pins to the chip's right edge ("hg38" then "chr1") and rides the
122
+ * run under THAT edge. A run the chip covers entirely goes unnamed, and the
123
+ * chip is not shortened to uncover it: a width fitted to the run under it
124
+ * changes with every run that pans past, and a fixed cap short enough to
125
+ * uncover a 55px chromosome cuts ordinary names. The assembly's `displayName`
126
+ * is where a long name gets shortened.
122
127
  *
123
- * `orientation` decides the ` [rev]` marker, and it is the row's
124
- * (`displayedRegionsOrientation`) rather than anything read off the blocks —
125
- * blocks cover the window, and a row is flipped or not whatever part of it you
126
- * are looking at. The rule is `assembleLocStrings`': say it where it
127
- * distinguishes, once where it does not.
128
+ * `orientation` decides the ` [rev]` marker, following `assembleLocStrings`: say
129
+ * it where it distinguishes, once where it does not.
128
130
  *
129
- * - `reversed`: the whole row is flipped, which is a fact about the row, so the
130
- * caption carries it and NO name does. The caption cannot fold in this state
131
- * — the sticky label is pushed clear of it instead — because a marker sitting
132
- * on a chromosome name is how the mixed case spells a fact about that one
133
- * region. `chr1 [rev] | chr2` would otherwise mean both "the row is flipped,
134
- * said once" and "chr1 is flipped and chr2 is not", in identical pixels.
135
- * - `mixed`: only some regions are flipped — reachable through the label menu's
136
- * per-region "Reverse region" — so every reversed run is marked and the
137
- * forward ones are left alone. Here the marker on a name is the only thing
138
- * telling two labels apart.
131
+ * - `reversed`: the caption carries the marker and no name does. A marker on a
132
+ * chromosome name is how the mixed case flags that one region.
133
+ * - `mixed`: every reversed run is marked. A marked label that fails the fit
134
+ * test falls back to the bare name rather than dropping.
139
135
  * - `forward`: no marker.
140
136
  *
141
- * Saying it once is the point: a flipped whole-genome row would otherwise
142
- * repeat `[rev]` after all 24 chromosomes to say a single thing about the row.
143
- *
144
- * Under `mixed` the marker never costs a name: a suffixed label that fails the
145
- * fit test falls back to the bare name rather than being dropped. Widening the
146
- * text moves the region width a name needs from ~30px to ~56px at 11px bold,
147
- * and a feature meant to surface information should not be deleting chromosome
148
- * names in the narrow half of that gap.
137
+ * `maxWidth` is the whole label box, `paddingLeft` included — both consumers
138
+ * clip from the box's left edge. A name is drawn whole or not at all: clipped
139
+ * mid-glyph, "chr16" reads as "chr1".
149
140
  */
150
141
  export declare function getScalebarRefNameLabels({ blocks, offsetPx, prefix, orientation, }: {
151
142
  blocks: BaseBlock[];
@@ -192,13 +183,35 @@ export declare function regionMoveActions(idx: number, numRegions: number): {
192
183
  to: number;
193
184
  }[];
194
185
  /**
195
- * The region reorderings offered by the refName-label menu, as pure list
196
- * transforms feeding setDisplayedRegions (which re-clamps bpPerPx/offsetPx for
197
- * the new region set).
186
+ * A new region list, and where each old index went in it (-1 for a region it
187
+ * dropped). The index map is what lets a region displayed twice be followed.
198
188
  */
199
- export declare function withRegionMoved(regions: Region[], from: number, to: number): Region[];
200
- export declare function withRegionRemoved(regions: Region[], index: number): Region[];
201
- export declare function withRegionReversed(regions: Region[], index: number): Region[];
189
+ export interface RegionEdit {
190
+ regions: Region[];
191
+ newIndexOf: (oldIndex: number) => number;
192
+ }
193
+ export declare function withRegionMoved(regions: Region[], from: number, to: number): RegionEdit;
194
+ export declare function withRegionRemoved(regions: Region[], index: number): RegionEdit;
195
+ export declare function withRegionsKept(regions: Region[], first: number, last: number): RegionEdit;
196
+ export declare function withRegionReversed(regions: Region[], index: number): RegionEdit;
197
+ /**
198
+ * Apply a region edit and keep the base under the middle of the viewport
199
+ * there, where the edit kept its region. `setDisplayedRegions` alone carries
200
+ * `offsetPx` into a coordinate space the edit redefined, which lands on
201
+ * whatever region now sits at that offset.
202
+ */
203
+ export declare function setDisplayedRegionsKeepingCenter(model: CenterKeepingView, { regions, newIndexOf }: RegionEdit): void;
204
+ /**
205
+ * The full run of same-orientation regions on one refName that a scalebar
206
+ * label's `firstRegionIndex`..`lastRegionIndex` sits inside. Those come off the
207
+ * static blocks, which are clipped to the viewport and broken by an elided
208
+ * block, so a zoomed-in collapsed-introns view brackets only the exons on
209
+ * screen — which is the wrong answer for anything acting on the whole run.
210
+ */
211
+ export declare function regionRunBounds(regions: Region[], firstIndex: number, lastIndex: number): {
212
+ first: number;
213
+ last: number;
214
+ };
202
215
  /**
203
216
  * Whether a label occupying [leftPx, leftPx + labelWidth] fits within a block
204
217
  * of the given pixel width, used to skip tick labels that would be clipped at a
@@ -264,6 +277,7 @@ export interface BlockRun {
264
277
  reversed: boolean;
265
278
  refName: string;
266
279
  isLeftEndOfDisplayedRegion: boolean;
280
+ labeled: boolean;
267
281
  }
268
282
  export declare function groupContiguousBlocks(blocks: BaseBlock[]): BlockRun[];
269
283
  /**
@@ -300,7 +314,7 @@ export declare function makeBlockTicks({ start, end, reversed, }: {
300
314
  start: number;
301
315
  end: number;
302
316
  reversed?: boolean;
303
- }, bpPerPx: number, emitMajor?: boolean, emitMinor?: boolean): {
317
+ }, bpPerPx: number, includeMinor?: boolean): {
304
318
  type: 'major' | 'minor';
305
319
  base: number;
306
320
  x: number;
@@ -348,3 +362,4 @@ export declare function generateLocations({ regions, assemblyManager, assemblyNa
348
362
  */
349
363
  export declare function parseLocStrings(input: string, assemblyName: string, isValidRefName: (str: string, assemblyName: string) => boolean): ParsedLocString[];
350
364
  export declare function calculateVisibleLocStrings(contentBlocks: ContentBlock[]): string;
365
+ export {};