@jbrowse/plugin-linear-genome-view 5.0.0-beta.2 → 5.0.0-beta.20
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.
- package/esm/LinearGenomeView/afterAttach.d.ts +22 -5
- package/esm/LinearGenomeView/afterAttach.js +129 -106
- package/esm/LinearGenomeView/axisConfigSchema.d.ts +18 -0
- package/esm/LinearGenomeView/axisConfigSchema.js +22 -0
- package/esm/LinearGenomeView/components/CenterLine.js +10 -5
- package/esm/LinearGenomeView/components/ConnectedHoverHighlight.js +2 -3
- package/esm/LinearGenomeView/components/CrisprGuidePanel.js +3 -5
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +9 -4
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +45 -8
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +2 -2
- package/esm/LinearGenomeView/components/Header.js +11 -1
- package/esm/LinearGenomeView/components/HeaderClearHighlightButton.js +2 -2
- package/esm/LinearGenomeView/components/HeaderPanControls.d.ts +3 -3
- package/esm/LinearGenomeView/components/HeaderPanControls.js +6 -3
- package/esm/LinearGenomeView/components/HeaderSearchBoxes.js +4 -1
- package/esm/LinearGenomeView/components/HeaderZoomControls.js +6 -35
- package/esm/LinearGenomeView/components/Highlight.js +27 -11
- package/esm/LinearGenomeView/components/HighlightBand.d.ts +11 -2
- package/esm/LinearGenomeView/components/HighlightBand.js +32 -13
- package/esm/LinearGenomeView/components/HighlightChip.d.ts +3 -3
- package/esm/LinearGenomeView/components/HighlightChip.js +13 -8
- package/esm/LinearGenomeView/components/HighlightLabelDialog.d.ts +6 -0
- package/esm/LinearGenomeView/components/HighlightLabelDialog.js +18 -0
- package/esm/LinearGenomeView/components/HoverPositionHighlight.js +3 -3
- package/esm/LinearGenomeView/components/ImportForm.js +7 -9
- package/esm/LinearGenomeView/components/LinearGenomeView.js +5 -12
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +13 -14
- package/esm/LinearGenomeView/components/MiniControls.js +11 -5
- package/esm/LinearGenomeView/components/OverviewHighlight.js +3 -3
- package/esm/LinearGenomeView/components/OverviewHighlightBand.d.ts +3 -2
- package/esm/LinearGenomeView/components/OverviewHighlightBand.js +6 -5
- package/esm/LinearGenomeView/components/OverviewRubberband.js +25 -48
- package/esm/LinearGenomeView/components/OverviewScalebar.js +4 -5
- package/esm/LinearGenomeView/components/OverviewScalebarPolygon.js +5 -3
- package/esm/LinearGenomeView/components/PaddingBlocks.js +3 -8
- package/esm/LinearGenomeView/components/RangeSelectOverlay.js +5 -6
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.d.ts +3 -2
- package/esm/LinearGenomeView/components/RegionWidthEditorDialog.js +4 -4
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.d.ts +5 -0
- package/esm/LinearGenomeView/components/ResizeAllTracksHandle.js +74 -0
- package/esm/LinearGenomeView/components/Rubberband.d.ts +1 -2
- package/esm/LinearGenomeView/components/Rubberband.js +3 -2
- package/esm/LinearGenomeView/components/SVGHighlightBand.d.ts +10 -1
- package/esm/LinearGenomeView/components/SVGHighlightBand.js +16 -5
- package/esm/LinearGenomeView/components/Scalebar.d.ts +2 -6
- package/esm/LinearGenomeView/components/Scalebar.js +8 -5
- package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +51 -36
- package/esm/LinearGenomeView/components/SearchBox.js +10 -16
- package/esm/LinearGenomeView/components/SearchPanelForm.d.ts +3 -2
- package/esm/LinearGenomeView/components/SearchPanelForm.js +4 -2
- package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +4 -8
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +7 -4
- package/esm/LinearGenomeView/components/SearchResultsTable.d.ts +4 -7
- package/esm/LinearGenomeView/components/SearchResultsTable.js +25 -53
- package/esm/LinearGenomeView/components/SequenceFeatureHoverHighlight.js +2 -3
- package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +2 -4
- package/esm/LinearGenomeView/components/StrandCheckboxes.d.ts +3 -2
- package/esm/LinearGenomeView/components/StrandCheckboxes.js +4 -2
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +2 -3
- package/esm/LinearGenomeView/components/TrackContainer.js +63 -10
- package/esm/LinearGenomeView/components/TrackLabel.js +14 -4
- package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +4 -5
- package/esm/LinearGenomeView/components/TrackLabelMenu.js +11 -14
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.d.ts +3 -4
- package/esm/LinearGenomeView/components/TrackLabelRefNameWarning.js +23 -10
- package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +6 -4
- package/esm/LinearGenomeView/components/TrackRenderingContainer.js +12 -24
- package/esm/LinearGenomeView/components/TracksContainer.js +11 -23
- package/esm/LinearGenomeView/components/VerticalGuide.d.ts +1 -2
- package/esm/LinearGenomeView/components/VerticalGuide.js +3 -16
- package/esm/LinearGenomeView/components/fetchSequence.d.ts +1 -2
- package/esm/LinearGenomeView/components/fetchSequence.js +15 -7
- package/esm/LinearGenomeView/components/recentLocationsMenu.js +10 -0
- package/esm/LinearGenomeView/components/useRangeSelect.d.ts +0 -3
- package/esm/LinearGenomeView/components/useRangeSelect.js +26 -61
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.d.ts +3 -1
- package/esm/LinearGenomeView/components/useSearchBoxPrefs.js +4 -2
- package/esm/LinearGenomeView/components/useSideScroll.d.ts +17 -2
- package/esm/LinearGenomeView/components/useSideScroll.js +156 -102
- package/esm/LinearGenomeView/components/util.d.ts +4 -0
- package/esm/LinearGenomeView/components/util.js +4 -2
- package/esm/LinearGenomeView/consts.d.ts +2 -0
- package/esm/LinearGenomeView/consts.js +3 -1
- package/esm/LinearGenomeView/containingLgv.d.ts +21 -0
- package/esm/LinearGenomeView/containingLgv.js +23 -0
- package/esm/LinearGenomeView/headerFit.d.ts +4 -2
- package/esm/LinearGenomeView/headerFit.js +20 -7
- package/esm/LinearGenomeView/index.d.ts +2 -7
- package/esm/LinearGenomeView/index.js +5 -7
- package/esm/LinearGenomeView/keyboardHandler.d.ts +8 -7
- package/esm/LinearGenomeView/keyboardHandler.js +61 -23
- package/esm/LinearGenomeView/launchKeys.d.ts +1 -1
- package/esm/LinearGenomeView/launchKeys.js +11 -6
- package/esm/LinearGenomeView/lazyDialogs.d.ts +16 -3
- package/esm/LinearGenomeView/lazyDialogs.js +1 -0
- package/esm/LinearGenomeView/linkedViewSync.d.ts +3 -11
- package/esm/LinearGenomeView/linkedViewSync.js +27 -49
- package/esm/LinearGenomeView/menuItems.d.ts +16 -18
- package/esm/LinearGenomeView/menuItems.js +264 -164
- package/esm/LinearGenomeView/model.d.ts +1192 -560
- package/esm/LinearGenomeView/model.js +805 -590
- package/esm/LinearGenomeView/rExport/exportLinearView.d.ts +17 -0
- package/esm/LinearGenomeView/rExport/exportLinearView.js +117 -0
- package/esm/LinearGenomeView/rExport/rScript.d.ts +110 -0
- package/esm/LinearGenomeView/rExport/rScript.js +524 -0
- package/esm/LinearGenomeView/sharedScaleContainer.d.ts +1 -1
- package/esm/LinearGenomeView/sharedScaleContainer.js +2 -12
- package/esm/LinearGenomeView/showFiles.d.ts +2 -0
- package/esm/LinearGenomeView/showFiles.js +19 -0
- package/esm/LinearGenomeView/showRegionsWithUndo.d.ts +1 -1
- package/esm/LinearGenomeView/showRegionsWithUndo.js +13 -5
- package/esm/LinearGenomeView/stickyChrome.d.ts +5 -9
- package/esm/LinearGenomeView/stickyChrome.js +5 -9
- package/esm/LinearGenomeView/svgcomponents/SVGGridlines.js +4 -4
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.d.ts +4 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHeader.js +8 -21
- package/esm/LinearGenomeView/svgcomponents/SVGHighlights.d.ts +3 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHighlights.js +9 -9
- package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.d.ts +3 -1
- package/esm/LinearGenomeView/svgcomponents/SVGHighlightsOverlay.js +5 -5
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +13 -18
- package/esm/LinearGenomeView/svgcomponents/SVGRegionSeparators.js +2 -5
- package/esm/LinearGenomeView/svgcomponents/SVGRowHeader.js +5 -6
- package/esm/LinearGenomeView/svgcomponents/SVGRuler.js +9 -10
- package/esm/LinearGenomeView/svgcomponents/SVGScalebar.js +3 -3
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.d.ts +26 -0
- package/esm/LinearGenomeView/svgcomponents/SVGStackedRow.js +12 -0
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +21 -13
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.d.ts +4 -5
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +7 -6
- package/esm/LinearGenomeView/svgcomponents/SVGView.d.ts +2 -3
- package/esm/LinearGenomeView/svgcomponents/SVGView.js +17 -3
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +24 -20
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.js +42 -29
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +74 -77
- package/esm/LinearGenomeView/svgcomponents/util.d.ts +28 -12
- package/esm/LinearGenomeView/svgcomponents/util.js +41 -29
- package/esm/LinearGenomeView/types.d.ts +13 -10
- package/esm/LinearGenomeView/types.js +0 -1
- package/esm/LinearGenomeView/util.d.ts +103 -46
- package/esm/LinearGenomeView/util.js +222 -170
- package/esm/MultiLevelRubberband/MultiLevelRubberband.js +9 -6
- package/esm/MultiLevelRubberband/index.d.ts +2 -0
- package/esm/MultiLevelRubberband/index.js +2 -0
- package/esm/MultiLevelRubberband/menuItems.d.ts +34 -0
- package/esm/MultiLevelRubberband/menuItems.js +52 -0
- package/esm/MultiLevelRubberband/rowLabel.d.ts +22 -0
- package/esm/MultiLevelRubberband/rowLabel.js +27 -0
- package/esm/MultiLevelRubberband/types.d.ts +1 -0
- package/esm/MultiLevelRubberband/useRangeSelect.d.ts +2 -1
- package/esm/MultiLevelRubberband/useRangeSelect.js +45 -59
- package/esm/TrackModifiers/index.d.ts +83 -0
- package/esm/TrackModifiers/index.js +231 -0
- package/esm/displayKitTests/perRegionTestEnv.d.ts +244 -68
- package/esm/displayKitTests/perRegionTestEnv.js +30 -26
- package/esm/index.d.ts +21 -99
- package/esm/index.js +17 -38
- package/esm/searchUtils.d.ts +26 -10
- package/esm/searchUtils.js +137 -137
- package/esm/shared/RubberbandSpan.d.ts +3 -2
- package/esm/shared/RubberbandSpan.js +6 -3
- package/esm/shared/coordLabels.d.ts +11 -4
- package/esm/shared/coordLabels.js +20 -5
- package/esm/shared/useWindowDrag.d.ts +18 -0
- package/esm/shared/useWindowDrag.js +47 -0
- package/package.json +12 -11
- package/esm/FeatureTrack/configSchema.d.ts +0 -124
- package/esm/FeatureTrack/configSchema.js +0 -54
- package/esm/FeatureTrack/index.d.ts +0 -2
- package/esm/FeatureTrack/index.js +0 -13
- package/esm/LinearGenomeView/initKeys.d.ts +0 -12
- package/esm/LinearGenomeView/initKeys.js +0 -68
- package/esm/MultiLevelRubberband/VerticalGuide.d.ts +0 -6
- package/esm/MultiLevelRubberband/VerticalGuide.js +0 -21
- package/esm/lazyPluginExports.d.ts +0 -23
- package/esm/lazyPluginExports.js +0 -36
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ExportSvgOptions, TrackLabelMode } from '../types.ts';
|
|
2
|
+
import type { LgvSvgExportable } from '@jbrowse/display-kit/renderDisplaySvg';
|
|
2
3
|
import type { ExportSvgDisplayOptions } from '@jbrowse/display-kit/types';
|
|
3
4
|
import type { ThemeOptions } from '@mui/material';
|
|
4
5
|
import type { ReactNode } from 'react';
|
|
@@ -6,7 +7,8 @@ export interface SvgExportTrack {
|
|
|
6
7
|
minimized: boolean;
|
|
7
8
|
displays: {
|
|
8
9
|
height: number;
|
|
9
|
-
|
|
10
|
+
regionTooLarge?: boolean;
|
|
11
|
+
svgSidebarWidth?: LgvSvgExportable['svgSidebarWidth'];
|
|
10
12
|
/**
|
|
11
13
|
* Optional, and the option is the point: SVG export is a substantial extra
|
|
12
14
|
* implementation for a display type, and a third-party plugin that has not
|
|
@@ -21,13 +23,18 @@ export interface SvgExportTrack {
|
|
|
21
23
|
export interface ViewTracksSvg<T> {
|
|
22
24
|
/** the tracks that were rendered, in the order they were laid out */
|
|
23
25
|
tracks: T[];
|
|
26
|
+
/**
|
|
27
|
+
* `legendHeight` is the room a track's key has in the gutter, absent for a
|
|
28
|
+
* track with no key to draw
|
|
29
|
+
*/
|
|
24
30
|
displayResults: {
|
|
25
31
|
track: T;
|
|
26
32
|
result: ReactNode;
|
|
33
|
+
legendHeight?: number;
|
|
27
34
|
}[];
|
|
28
35
|
/** total height of the stack, valid only because the renders above resolved */
|
|
29
36
|
tracksHeight: number;
|
|
30
|
-
/**
|
|
37
|
+
/** px the caller widens its canvas by for the keys right of the plot */
|
|
31
38
|
legendWidth: number;
|
|
32
39
|
/**
|
|
33
40
|
* Visible tracks left out because their display implements no `renderSvg`.
|
|
@@ -40,30 +47,28 @@ export interface ViewTracksSvg<T> {
|
|
|
40
47
|
* One view's worth of exported track bodies: which tracks are in, their
|
|
41
48
|
* rendered SVG, and how tall the stack ends up.
|
|
42
49
|
*
|
|
43
|
-
* It exists to own
|
|
44
|
-
*
|
|
45
|
-
*
|
|
50
|
+
* It exists to own an ordering that each of the three view exports got wrong at
|
|
51
|
+
* least once, because it is not visible at a call site that merely lists the
|
|
52
|
+
* same statements in some order: the geometry is measured **after** the
|
|
53
|
+
* awaits.
|
|
46
54
|
*
|
|
47
|
-
* - `
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* `
|
|
51
|
-
* the
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
* and the taller bodies ran off the bottom of the export — and in the
|
|
58
|
-
* breakpoint-split export it also desynced the overlay anchors, resolved
|
|
59
|
-
* after, from the view tops, which weren't.
|
|
55
|
+
* - `tracksHeight`: a display whose height follows its data (grow mode;
|
|
56
|
+
* `LinearMultiRowFeatureDisplay` is `nrow * effectiveRowHeight`) only reaches
|
|
57
|
+
* its final height once `renderSvg`'s readiness wait resolves, and
|
|
58
|
+
* `SVGTracks` re-reads `displays[0].height` later still. Measuring up front
|
|
59
|
+
* sized the canvas for the pre-fetch height and the taller bodies ran off the
|
|
60
|
+
* bottom of the export — and in the breakpoint-split export it also desynced
|
|
61
|
+
* the overlay anchors, resolved after, from the view tops, which weren't.
|
|
62
|
+
* - `legendWidth`: most keys list what was loaded, and on a headless export
|
|
63
|
+
* (jbrowse-img) nothing has loaded before the waits. Measured after, a track
|
|
64
|
+
* with no key reserves nothing and the figure has no empty strip.
|
|
60
65
|
*
|
|
61
66
|
* The minimized filter and the track order are here for the same reason: the
|
|
62
67
|
* reserved height, the rendered bodies, the label gutter and (breakpoint-split)
|
|
63
68
|
* the ribbon anchors must all be derived from one list, and pinned tracks are
|
|
64
69
|
* drawn at the top of a view on screen.
|
|
65
70
|
*/
|
|
66
|
-
export declare function renderViewTracks<T extends SvgExportTrack>({ view, opts, theme, textHeight, trackLabels,
|
|
71
|
+
export declare function renderViewTracks<T extends SvgExportTrack>({ view, opts, theme, textHeight, trackLabels, }: {
|
|
67
72
|
view: {
|
|
68
73
|
pinnedTracks: T[];
|
|
69
74
|
unpinnedTracks: T[];
|
|
@@ -72,5 +77,4 @@ export declare function renderViewTracks<T extends SvgExportTrack>({ view, opts,
|
|
|
72
77
|
theme: ThemeOptions | undefined;
|
|
73
78
|
textHeight: number;
|
|
74
79
|
trackLabels: TrackLabelMode;
|
|
75
|
-
reserveLegendWidth?: boolean;
|
|
76
80
|
}): Promise<ViewTracksSvg<T>>;
|
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
import { awaitSvgRenders } from '@jbrowse/core/svg/svgReady';
|
|
2
2
|
import { max } from '@jbrowse/core/util';
|
|
3
|
-
import {
|
|
3
|
+
import { svgLegendGutterWidth } from '@jbrowse/display-kit/renderDisplaySvg';
|
|
4
|
+
import { labelOffset, totalHeight, trackBoxOffsets } from './util.js';
|
|
4
5
|
/**
|
|
5
6
|
* One view's worth of exported track bodies: which tracks are in, their
|
|
6
7
|
* rendered SVG, and how tall the stack ends up.
|
|
7
8
|
*
|
|
8
|
-
* It exists to own
|
|
9
|
-
*
|
|
10
|
-
*
|
|
9
|
+
* It exists to own an ordering that each of the three view exports got wrong at
|
|
10
|
+
* least once, because it is not visible at a call site that merely lists the
|
|
11
|
+
* same statements in some order: the geometry is measured **after** the
|
|
12
|
+
* awaits.
|
|
11
13
|
*
|
|
12
|
-
* - `
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* `
|
|
16
|
-
* the
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* and the taller bodies ran off the bottom of the export — and in the
|
|
23
|
-
* breakpoint-split export it also desynced the overlay anchors, resolved
|
|
24
|
-
* after, from the view tops, which weren't.
|
|
14
|
+
* - `tracksHeight`: a display whose height follows its data (grow mode;
|
|
15
|
+
* `LinearMultiRowFeatureDisplay` is `nrow * effectiveRowHeight`) only reaches
|
|
16
|
+
* its final height once `renderSvg`'s readiness wait resolves, and
|
|
17
|
+
* `SVGTracks` re-reads `displays[0].height` later still. Measuring up front
|
|
18
|
+
* sized the canvas for the pre-fetch height and the taller bodies ran off the
|
|
19
|
+
* bottom of the export — and in the breakpoint-split export it also desynced
|
|
20
|
+
* the overlay anchors, resolved after, from the view tops, which weren't.
|
|
21
|
+
* - `legendWidth`: most keys list what was loaded, and on a headless export
|
|
22
|
+
* (jbrowse-img) nothing has loaded before the waits. Measured after, a track
|
|
23
|
+
* with no key reserves nothing and the figure has no empty strip.
|
|
25
24
|
*
|
|
26
25
|
* The minimized filter and the track order are here for the same reason: the
|
|
27
26
|
* reserved height, the rendered bodies, the label gutter and (breakpoint-split)
|
|
28
27
|
* the ribbon anchors must all be derived from one list, and pinned tracks are
|
|
29
28
|
* drawn at the top of a view on screen.
|
|
30
29
|
*/
|
|
31
|
-
export async function renderViewTracks({ view, opts, theme, textHeight, trackLabels,
|
|
30
|
+
export async function renderViewTracks({ view, opts, theme, textHeight, trackLabels, }) {
|
|
32
31
|
// Partitioned before anything is measured, so a skipped track reserves no
|
|
33
32
|
// height and takes no place in the label gutter — the alternative is a figure
|
|
34
33
|
// with a labelled empty band where the track would have been. One pass, so
|
|
@@ -42,25 +41,39 @@ export async function renderViewTracks({ view, opts, theme, textHeight, trackLab
|
|
|
42
41
|
(track.displays[0]?.renderSvg ? tracks : skippedTracks).push(track);
|
|
43
42
|
}
|
|
44
43
|
}
|
|
45
|
-
const legendWidth = reserveLegendWidth
|
|
46
|
-
? max(tracks.map(track => track.displays[0].svgLegendWidth?.() ?? 0), 0)
|
|
47
|
-
: 0;
|
|
48
44
|
// `awaitSvgRenders` over `Promise.all`: a track whose data won't load fails
|
|
49
45
|
// the export, and a view with three broken tracks should say so once rather
|
|
50
46
|
// than name whichever rejected first
|
|
51
47
|
const displayResults = await awaitSvgRenders(tracks.map(async (track) => ({
|
|
52
48
|
track,
|
|
53
|
-
result: await track.displays[0].renderSvg({
|
|
54
|
-
...opts,
|
|
55
|
-
theme,
|
|
56
|
-
legendWidth,
|
|
57
|
-
}),
|
|
49
|
+
result: await track.displays[0].renderSvg({ ...opts, theme }),
|
|
58
50
|
})));
|
|
51
|
+
const tracksHeight = totalHeight(tracks, trackLabels, textHeight);
|
|
52
|
+
const keyed = tracks.map(track => !track.displays[0].regionTooLarge &&
|
|
53
|
+
svgLegendGutterWidth(track.displays[0], theme, Infinity) > 0);
|
|
54
|
+
const bodyTops = trackBoxOffsets(tracks, trackLabels, textHeight).map((top, i) => top + labelOffset(tracks[i], trackLabels, textHeight));
|
|
55
|
+
// A key runs from its body's top to the next keyed body's, or to the foot of
|
|
56
|
+
// the stack, so a long key beside a short track carries on past the unkeyed
|
|
57
|
+
// tracks below it before it cuts to "+N more".
|
|
58
|
+
const legendHeights = keyed.map((isKeyed, i) => {
|
|
59
|
+
const next = keyed.findIndex((k, j) => k && j > i);
|
|
60
|
+
return isKeyed
|
|
61
|
+
? (next === -1 ? tracksHeight : bodyTops[next]) - bodyTops[i]
|
|
62
|
+
: undefined;
|
|
63
|
+
});
|
|
59
64
|
return {
|
|
60
65
|
tracks,
|
|
61
|
-
displayResults,
|
|
62
|
-
|
|
63
|
-
|
|
66
|
+
displayResults: displayResults.map((r, i) => ({
|
|
67
|
+
...r,
|
|
68
|
+
legendHeight: legendHeights[i],
|
|
69
|
+
})),
|
|
70
|
+
tracksHeight,
|
|
71
|
+
legendWidth: max(tracks.map((track, i) => {
|
|
72
|
+
const height = legendHeights[i];
|
|
73
|
+
return height === undefined
|
|
74
|
+
? 0
|
|
75
|
+
: svgLegendGutterWidth(track.displays[0], theme, height);
|
|
76
|
+
}), 0),
|
|
64
77
|
skippedTracks,
|
|
65
78
|
};
|
|
66
79
|
}
|
|
@@ -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
|
|
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';
|
|
@@ -19,12 +16,11 @@ import { defaultTextHeight, getRowHeaderLayout, trackLabelLeftOffset, } from './
|
|
|
19
16
|
* One figure: every visible track rendered to SVG elements, and the geometry
|
|
20
17
|
* that lays them out.
|
|
21
18
|
*
|
|
22
|
-
* `renderViewTracks` owns the
|
|
23
|
-
* legend gutter measured
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* below is read after the awaits for the same reason.
|
|
19
|
+
* `renderViewTracks` owns the ordering this cannot state for itself: the stack
|
|
20
|
+
* height and the legend gutter are measured after the renders, since a
|
|
21
|
+
* display's height and its key follow data that lands only once its readiness
|
|
22
|
+
* wait resolves. Everything read below is read after the awaits for the same
|
|
23
|
+
* reason.
|
|
28
24
|
*/
|
|
29
25
|
async function renderFigure(view, opts) {
|
|
30
26
|
const { fontSize, rulerHeight, trackLabels, rasterizeLayers, showScalebar } = opts;
|
|
@@ -42,9 +38,6 @@ async function renderFigure(view, opts) {
|
|
|
42
38
|
theme,
|
|
43
39
|
textHeight,
|
|
44
40
|
trackLabels,
|
|
45
|
-
// an inline figure has room to give: a legend sits beside the plot rather
|
|
46
|
-
// than over it
|
|
47
|
-
reserveLegendWidth: true,
|
|
48
41
|
});
|
|
49
42
|
// the room the row header needs *above* its own origin — it draws the assembly
|
|
50
43
|
// name and the scalebar at negative y, so the caller reserves the band and
|
|
@@ -64,7 +57,6 @@ async function renderFigure(view, opts) {
|
|
|
64
57
|
height: bandHeight + rulerHeight + tracksHeight + opts.margin,
|
|
65
58
|
bandHeight,
|
|
66
59
|
tracksHeight,
|
|
67
|
-
legendWidth,
|
|
68
60
|
trackLabelOffset,
|
|
69
61
|
textHeight,
|
|
70
62
|
locstring: view.visibleLocStrings,
|
|
@@ -87,17 +79,16 @@ async function renderFigure(view, opts) {
|
|
|
87
79
|
* render. Where it matters, this line is the only thing holding the two halves
|
|
88
80
|
* together.
|
|
89
81
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
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.
|
|
82
|
+
* The export's theme providers, as the file path mounts them: a host that
|
|
83
|
+
* installs neither would otherwise get JBrowse's default light theme whatever
|
|
84
|
+
* the session is set to.
|
|
95
85
|
*
|
|
96
86
|
* No background rect, unlike a file — that has nothing behind it, and a figure
|
|
97
|
-
* in a page has the page. No `
|
|
98
|
-
* decision from the file path on purpose: the counter is
|
|
99
|
-
*
|
|
100
|
-
* pointing at. Letting it run is what makes several live figures
|
|
87
|
+
* in a page has the page. No `withFreshSvgClipIds` either, and that is the
|
|
88
|
+
* opposite decision from the file path on purpose: the counter is
|
|
89
|
+
* document-global, so restarting it here would reuse ids that a figure already
|
|
90
|
+
* on the page is pointing at. Letting it run is what makes several live figures
|
|
91
|
+
* unique.
|
|
101
92
|
*/
|
|
102
93
|
const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
|
|
103
94
|
const { width, height, margin, theme } = snapshot;
|
|
@@ -105,20 +96,14 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
|
|
|
105
96
|
// INSIDE the tree, which the memo above is not between
|
|
106
97
|
const ref = useRef(null);
|
|
107
98
|
useFrozenFigureContract(ref, snapshot);
|
|
108
|
-
return (_jsx(
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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 }) }) }) }) }));
|
|
99
|
+
return (_jsx(SvgThemeProviders, { theme: theme, children: _jsx("svg", { ref: ref, width: width, height: height, viewBox: `0 0 ${width} ${height}`,
|
|
100
|
+
// It is a vector, so a narrower container scales it rather than
|
|
101
|
+
// clipping it; the height attribute stays, so a box reserved for it
|
|
102
|
+
// does not change size when that happens. Deliberately not a prop:
|
|
103
|
+
// anything passed per-render would have to reach past the memo above,
|
|
104
|
+
// which is the one thing holding the figure's two halves together. A
|
|
105
|
+
// host that wants other sizing wraps this in a box of its own.
|
|
106
|
+
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, showScalebar: snapshot.showScalebar }) }) }));
|
|
122
107
|
});
|
|
123
108
|
/**
|
|
124
109
|
* What "the figure is out of date" means, as a string.
|
|
@@ -135,17 +120,26 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
|
|
|
135
120
|
* question about regions and is true before a track is instantiated (the first
|
|
136
121
|
* figure then draws a header over nothing, and nothing else ever changes to
|
|
137
122
|
* correct it); **their heights and minimized flags**, since the geometry is
|
|
138
|
-
* derived from them; **
|
|
123
|
+
* derived from them; **their configs**, since a display's settings are slots on
|
|
124
|
+
* the track config and a shown track's snapshot spells that config as its id;
|
|
125
|
+
* **the legend sections a reader dismissed** and **the per-group state**
|
|
126
|
+
* (hidden sections, collapses, height overrides: `groupStateKey`), which are
|
|
127
|
+
* volatile and in no snapshot; **the reload counter**, since a Retry or a Force
|
|
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** (`colorByFrame`,
|
|
130
|
+
* `showAminoAcids`), named one by one because the view's own snapshot moves
|
|
131
|
+
* every pan frame; **the width**, since a resize can widen the canvas without
|
|
139
132
|
* moving the locus; **the theme**, since each display bakes colors into its own
|
|
140
133
|
* bodies, so a figure from the other mode is not stale but unreadable; and **the
|
|
141
134
|
* highlight bands**, which are drawn in the figure and are the one thing in it a
|
|
142
135
|
* reader adds without navigating anywhere.
|
|
143
136
|
*
|
|
144
|
-
* A plugin's own overlay
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
* see the note at the top of
|
|
137
|
+
* A plugin's own overlay, through `LinearGenomeView-HighlightSVGComponent`, is
|
|
138
|
+
* state this cannot see, so a change to it shows up at the figure's next
|
|
139
|
+
* redraw rather than at once. So does a track's vertical scroll, which moves
|
|
140
|
+
* every wheel frame and has no settled copy to key on. Subscribing from inside
|
|
141
|
+
* the figure is the thing that must not happen — see the note at the top of
|
|
142
|
+
* the file.
|
|
149
143
|
*/
|
|
150
144
|
function figureKey(view, themeName) {
|
|
151
145
|
// A closed view is not an error, it is a host doing an ordinary thing in an
|
|
@@ -156,10 +150,10 @@ function figureKey(view, themeName) {
|
|
|
156
150
|
// throw a TypeError inside the reaction, where MobX swallows it. No key means
|
|
157
151
|
// no figure, which is what a host that closed the view wanted anyway.
|
|
158
152
|
//
|
|
159
|
-
// `view.width` throws by design before the view has been measured
|
|
160
|
-
//
|
|
161
|
-
//
|
|
162
|
-
if (!isAlive(view) ||
|
|
153
|
+
// `view.width` throws by design before the view has been measured. `status`
|
|
154
|
+
// is ready only once it has been AND there are regions to draw — `ready` is
|
|
155
|
+
// also true for a view nothing has told where to look, measured or not
|
|
156
|
+
if (!isAlive(view) || view.status.type !== 'ready') {
|
|
163
157
|
return '';
|
|
164
158
|
}
|
|
165
159
|
const session = getSession(view);
|
|
@@ -167,14 +161,22 @@ function figureKey(view, themeName) {
|
|
|
167
161
|
view.coarseVisibleLocStrings,
|
|
168
162
|
view.coarseBpPerPx,
|
|
169
163
|
view.width,
|
|
170
|
-
view.tracks.map(track =>
|
|
171
|
-
track.
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
164
|
+
view.tracks.map(track => {
|
|
165
|
+
const display = track.displays[0];
|
|
166
|
+
return [
|
|
167
|
+
getSnapshot(track),
|
|
168
|
+
getSnapshot(track.configuration),
|
|
169
|
+
display?.height,
|
|
170
|
+
display?.dismissedLegendSections,
|
|
171
|
+
display?.groupStateKey,
|
|
172
|
+
display?.reloadCounter,
|
|
173
|
+
];
|
|
174
|
+
}),
|
|
175
|
+
view.colorByFrame,
|
|
176
|
+
view.showAminoAcids,
|
|
175
177
|
session.getActiveThemeOptions?.(themeName),
|
|
176
|
-
session.highlightsVisible ? view.
|
|
177
|
-
|
|
178
|
+
session.highlightsVisible ? view.highlights : false,
|
|
179
|
+
session.highlightLabelsVisible,
|
|
178
180
|
]);
|
|
179
181
|
}
|
|
180
182
|
/**
|
|
@@ -212,25 +214,7 @@ function useFigureKey(view, themeName) {
|
|
|
212
214
|
export function useViewSvgFigure(view, { fontSize = 12, rulerHeight = 30, trackLabels = 'offset', showGridlines = true, showScalebar = true, rasterizeLayers = false, margin = exportMargin, themeName, } = {}) {
|
|
213
215
|
const key = useFigureKey(view, themeName);
|
|
214
216
|
useOneFigurePerView(view);
|
|
215
|
-
const
|
|
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, {
|
|
217
|
+
const opts = {
|
|
234
218
|
fontSize,
|
|
235
219
|
rulerHeight,
|
|
236
220
|
trackLabels,
|
|
@@ -239,7 +223,20 @@ export function useViewSvgFigure(view, { fontSize = 12, rulerHeight = 30, trackL
|
|
|
239
223
|
rasterizeLayers,
|
|
240
224
|
margin,
|
|
241
225
|
themeName,
|
|
242
|
-
}
|
|
226
|
+
};
|
|
227
|
+
const { data: snapshot, error, isLoading, } = useFetch(
|
|
228
|
+
// Every option is in the key by value, so an inline options object costs
|
|
229
|
+
// nothing and a changed option redraws. The view's id too: two views can
|
|
230
|
+
// share every other term. A null key is `useFetch`'s own "not yet", which
|
|
231
|
+
// is what an unready view reports.
|
|
232
|
+
key
|
|
233
|
+
? [
|
|
234
|
+
'lgv-svg-figure',
|
|
235
|
+
svgNodeId(view),
|
|
236
|
+
key,
|
|
237
|
+
JSON.stringify(opts),
|
|
238
|
+
]
|
|
239
|
+
: null, () => renderFigure(view, opts));
|
|
243
240
|
// Written in an effect and read during render, which is the order that makes
|
|
244
241
|
// it work: a key change clears `data` on the render where the ref still holds
|
|
245
242
|
// the previous commit's size, so the host's box keeps the height it had rather
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import type { TrackLabelMode } from '../types.ts';
|
|
2
2
|
import type { AnyConfigurationModel } from '@jbrowse/core/configuration';
|
|
3
3
|
import type { TrackCatalog } from '@jbrowse/core/util';
|
|
4
|
+
import type { LgvSvgExportable } from '@jbrowse/display-kit/renderDisplaySvg';
|
|
5
|
+
import type { ExportTextStyle } from '@jbrowse/display-kit/types';
|
|
4
6
|
import type { ReactNode } from 'react';
|
|
7
|
+
type SidebarDisplay = Pick<LgvSvgExportable, 'svgSidebarWidth'>;
|
|
5
8
|
interface TrackHeights {
|
|
6
|
-
displays: {
|
|
9
|
+
displays: ({
|
|
7
10
|
height: number;
|
|
8
|
-
|
|
11
|
+
prefersOffset?: boolean;
|
|
12
|
+
} & SidebarDisplay)[];
|
|
9
13
|
}
|
|
10
14
|
export interface SvgDisplayResult {
|
|
11
15
|
track: {
|
|
12
16
|
configuration: AnyConfigurationModel;
|
|
13
|
-
displays: {
|
|
17
|
+
displays: ({
|
|
14
18
|
height: number;
|
|
15
|
-
|
|
19
|
+
regionTooLarge?: boolean;
|
|
20
|
+
drawsGenomicCoordinates?: boolean;
|
|
21
|
+
} & SidebarDisplay)[];
|
|
16
22
|
};
|
|
17
23
|
result: ReactNode;
|
|
24
|
+
/** the room its key has in the export's legend gutter, absent for no key */
|
|
25
|
+
legendHeight?: number;
|
|
18
26
|
}
|
|
19
27
|
export declare const trackSpacing = 2;
|
|
20
28
|
export declare function gridlineTickXs(model: {
|
|
@@ -58,6 +66,7 @@ export declare function getRowHeaderLayout({ fontSize, showScalebar, }: {
|
|
|
58
66
|
assemblyLabelBaselineY: number;
|
|
59
67
|
bandHeight: number;
|
|
60
68
|
};
|
|
69
|
+
export type HeaderLayout = ReturnType<typeof getHeaderLayout>;
|
|
61
70
|
export declare function getHeaderLayout({ fontSize, showCytobands, rulerHeight, }: {
|
|
62
71
|
fontSize: number;
|
|
63
72
|
showCytobands: boolean;
|
|
@@ -71,25 +80,32 @@ export declare function getHeaderLayout({ fontSize, showCytobands, rulerHeight,
|
|
|
71
80
|
};
|
|
72
81
|
export declare const RULER_MAJOR_TICK = 5;
|
|
73
82
|
export declare const RULER_MINOR_TICK = 3;
|
|
74
|
-
export declare const RULER_TICK_FONT_SIZE = 11;
|
|
75
83
|
export declare function getRulerLayout(rulerHeight: number): {
|
|
76
84
|
tickTopY: number;
|
|
77
85
|
numbersBaselineY: number;
|
|
78
86
|
};
|
|
79
87
|
export declare const refNameLabelBoxHeight: number;
|
|
80
88
|
export declare const refNameLabelBaselineY: number;
|
|
81
|
-
export declare function
|
|
89
|
+
export declare function trackLabelMode(track: {
|
|
90
|
+
displays: ({
|
|
91
|
+
prefersOffset?: boolean;
|
|
92
|
+
} & SidebarDisplay)[];
|
|
93
|
+
}, trackLabels: TrackLabelMode): TrackLabelMode;
|
|
94
|
+
export declare function labelOffset(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
|
|
95
|
+
interface SidebarTrack {
|
|
96
|
+
configuration: AnyConfigurationModel;
|
|
97
|
+
displays: SidebarDisplay[];
|
|
98
|
+
}
|
|
82
99
|
export declare const TRACK_LABEL_GAP = 40;
|
|
83
100
|
export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }: {
|
|
84
|
-
tracks:
|
|
85
|
-
configuration: AnyConfigurationModel;
|
|
86
|
-
}[];
|
|
101
|
+
tracks: SidebarTrack[];
|
|
87
102
|
trackLabels: TrackLabelMode;
|
|
88
103
|
fontSize: number;
|
|
89
104
|
fontFamily?: string;
|
|
90
105
|
session: TrackCatalog;
|
|
91
106
|
}): number;
|
|
92
|
-
export declare function
|
|
93
|
-
export declare function
|
|
94
|
-
export declare function
|
|
107
|
+
export declare function trackSidebarWidth(track: Pick<SidebarTrack, 'displays'>, text?: ExportTextStyle): number;
|
|
108
|
+
export declare function trackBoxHeight(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
|
|
109
|
+
export declare function trackBoxOffsets(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number[];
|
|
110
|
+
export declare function totalHeight(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number;
|
|
95
111
|
export {};
|