@jbrowse/plugin-linear-genome-view 5.0.0-beta.11 → 5.0.0-beta.13
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/components/HeaderSearchBoxes.js +4 -1
- package/esm/LinearGenomeView/components/LinearGenomeViewContainer.js +3 -4
- package/esm/LinearGenomeView/components/MiniControls.js +8 -3
- package/esm/LinearGenomeView/components/SearchResultsTable.js +1 -2
- package/esm/LinearGenomeView/components/TrackLabel.js +4 -1
- package/esm/LinearGenomeView/svgcomponents/SVGLinearGenomeView.js +1 -1
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.d.ts +1 -2
- package/esm/LinearGenomeView/svgcomponents/SVGTrackLabel.js +5 -10
- package/esm/LinearGenomeView/svgcomponents/SVGTracks.js +2 -2
- package/esm/LinearGenomeView/svgcomponents/renderViewTracks.d.ts +2 -1
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +26 -6
- package/esm/LinearGenomeView/svgcomponents/util.d.ts +14 -12
- package/esm/LinearGenomeView/svgcomponents/util.js +10 -19
- package/package.json +7 -7
|
@@ -13,8 +13,11 @@ const useStyles = makeStyles()(theme => ({
|
|
|
13
13
|
display: 'flex',
|
|
14
14
|
alignItems: 'center',
|
|
15
15
|
gap: theme.spacing(0.5),
|
|
16
|
+
minWidth: 0,
|
|
16
17
|
},
|
|
17
18
|
}));
|
|
19
|
+
const MIN_BOX_WIDTH = 100;
|
|
20
|
+
const boxStyle = { margin: 0, minWidth: MIN_BOX_WIDTH };
|
|
18
21
|
// One row's locate control in a header that stacks several linear genome views:
|
|
19
22
|
// the compact search box, then the assembly name and the span on screen. The
|
|
20
23
|
// comparative view and the breakpoint split view each draw one per row, and each
|
|
@@ -23,6 +26,6 @@ const useStyles = makeStyles()(theme => ({
|
|
|
23
26
|
const HeaderSearchBoxes = observer(function HeaderSearchBoxes({ view, }) {
|
|
24
27
|
const { classes } = useStyles();
|
|
25
28
|
const { assemblyDisplayNames, coarseTotalBp } = view;
|
|
26
|
-
return (_jsxs("span", { className: classes.searchBox, children: [_jsx(SearchBox, { model: view, showHelp: false, maxWidth: 250, minWidth:
|
|
29
|
+
return (_jsxs("span", { className: classes.searchBox, children: [_jsx(SearchBox, { model: view, showHelp: false, maxWidth: 250, minWidth: MIN_BOX_WIDTH, style: boxStyle }), _jsxs(Typography, { variant: "body2", color: "text.secondary", className: classes.bp, children: [assemblyDisplayNames.join(','), " ", getBpDisplayStr(coarseTotalBp)] })] }));
|
|
27
30
|
});
|
|
28
31
|
export default HeaderSearchBoxes;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import {
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
3
|
import { VIEW_HEADER_HEIGHT } from '@jbrowse/core/ui';
|
|
4
4
|
import { getSession } from '@jbrowse/core/util';
|
|
5
5
|
import { LGV_HEADER_HEIGHT_VAR, SCROLL_PORT_HEIGHT_VAR, VIEW_HEADER_HEIGHT_VAR, useChromeHeightVar, useFocusOnInteraction, } from '@jbrowse/core/util/hooks';
|
|
@@ -11,12 +11,11 @@ import { stickyChromeTops } from '../stickyChrome.js';
|
|
|
11
11
|
import Header from './Header.js';
|
|
12
12
|
import MiniControls from './MiniControls.js';
|
|
13
13
|
import NavigationAnnouncer from './NavigationAnnouncer.js';
|
|
14
|
+
import NoTracksActiveButton from './NoTracksActiveButton.js';
|
|
14
15
|
import ResizeAllTracksHandle from './ResizeAllTracksHandle.js';
|
|
15
16
|
import Rubberband from './Rubberband.js';
|
|
16
17
|
import TrackContainer from './TrackContainer.js';
|
|
17
18
|
import TracksContainer from './TracksContainer.js';
|
|
18
|
-
// lazies
|
|
19
|
-
const NoTracksActiveButton = lazy(() => import('./NoTracksActiveButton.js'));
|
|
20
19
|
const useStyles = makeStyles()(theme => ({
|
|
21
20
|
header: {
|
|
22
21
|
background: theme.palette.background.paper,
|
|
@@ -104,7 +103,7 @@ const LinearGenomeViewContainer = observer(function LinearGenomeViewContainer({
|
|
|
104
103
|
.map(d => d.hoveredFeature)
|
|
105
104
|
.find(Boolean);
|
|
106
105
|
session.setHovered({ hoverPosition, hoverFeature });
|
|
107
|
-
}, children: [_jsx(NavigationAnnouncer, { model: model }), _jsxs("div", { ref: headerRef, "data-testid": `lgv-header-${model.id}`, className: classes.header, style: { position: stickyViewHeaders ? 'sticky' : undefined }, children: [_jsx(Header, { model: model }), hideHeader ? _jsx(MiniControls, { model: model }) : null] }), _jsx("div", { ref: tracksRef, children: model.scalebarOnly ? (_jsx(Rubberband, { model: model })) : (_jsx(TracksContainer, { model: model, children: !tracks.length ? (_jsx(
|
|
106
|
+
}, children: [_jsx(NavigationAnnouncer, { model: model }), _jsxs("div", { ref: headerRef, "data-testid": `lgv-header-${model.id}`, className: classes.header, style: { position: stickyViewHeaders ? 'sticky' : undefined }, children: [_jsx(Header, { model: model }), hideHeader ? _jsx(MiniControls, { model: model }) : null] }), _jsx("div", { ref: tracksRef, children: model.scalebarOnly ? (_jsx(Rubberband, { model: model })) : (_jsx(TracksContainer, { model: model, children: !tracks.length ? (_jsx(NoTracksActiveButton, { model: model })) : (_jsxs(_Fragment, { children: [pinnedTracks.length ? (_jsx(Paper, { elevation: 2, "data-testid": "pinned-tracks", className: classes.pinnedTracks, style: {
|
|
108
107
|
top: stickyTops.pinnedTracks,
|
|
109
108
|
// the scroll port this sticks in, not the window: it is
|
|
110
109
|
// under the app bar in the classic stack, a dockview
|
|
@@ -14,19 +14,24 @@ const useStyles = makeStyles()(theme => ({
|
|
|
14
14
|
background: {
|
|
15
15
|
position: 'absolute',
|
|
16
16
|
right: 0,
|
|
17
|
-
background: theme.palette.background.paper,
|
|
18
17
|
// needed when sticky header is off in lgv, e.g. in breakpoint split view
|
|
19
18
|
zIndex: 2,
|
|
20
19
|
},
|
|
21
20
|
focusedBackground: {
|
|
22
|
-
|
|
21
|
+
backgroundColor: alpha(theme.palette.secondary.light, 0.2),
|
|
23
22
|
},
|
|
24
23
|
}));
|
|
25
24
|
const MiniControls = observer(function MiniControls({ model, }) {
|
|
26
25
|
const { classes } = useStyles();
|
|
27
26
|
const { id, scalebarOnly } = model;
|
|
28
27
|
const { focusedViewId } = getSession(model);
|
|
29
|
-
|
|
28
|
+
// A ruler-only row is shorter than these controls, so they rise from the
|
|
29
|
+
// ruler's bottom edge rather than hang from its top: a nested row always has
|
|
30
|
+
// chrome above it, while the last row of a stack has only the view's frame
|
|
31
|
+
// below.
|
|
32
|
+
return (_jsx(Paper, { "data-testid": "lgv-mini-controls", className: classes.background, style: scalebarOnly
|
|
33
|
+
? { top: model.scalebarHeight, transform: 'translateY(-100%)' }
|
|
34
|
+
: undefined, children: _jsxs(Paper, { className: focusedViewId === id ? classes.focusedBackground : undefined, children: [_jsx(Tooltip, { title: "Open track selector", children: _jsx(IconButton, { size: "small", onClick: () => {
|
|
30
35
|
model.activateTrackSelector();
|
|
31
36
|
}, children: _jsx(TrackSelectorIcon, { fontSize: "small" }) }) }), _jsx(CascadingMenuButton, { menuItems: () => model.menuItems(), children: _jsx(MoreVertIcon, { fontSize: "small" }) }), _jsx(Tooltip, { title: scalebarOnly ? 'Show tracks' : 'Show ruler only', children: _jsx(IconButton, { size: "small", onClick: () => {
|
|
32
37
|
model.setScalebarOnly(!scalebarOnly);
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { canonicalLocString } from '@jbrowse/core/TextSearch/places';
|
|
3
|
-
import { readConfObject } from '@jbrowse/core/configuration';
|
|
4
3
|
import { SanitizedHTML } from '@jbrowse/core/ui';
|
|
5
4
|
import { getSession } from '@jbrowse/core/util';
|
|
6
5
|
import { Button, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, } from '@mui/material';
|
|
@@ -12,7 +11,7 @@ const SearchResultsTable = observer(function SearchResultsTable({ searchResults,
|
|
|
12
11
|
const assembly = assemblyManager.get(assemblyName);
|
|
13
12
|
function getTrackName(trackId) {
|
|
14
13
|
const conf = trackId !== undefined ? session.getTrackById(trackId) : undefined;
|
|
15
|
-
return conf
|
|
14
|
+
return conf?.name ?? '';
|
|
16
15
|
}
|
|
17
16
|
// A location the assembly can't resolve is listed as-is: Go navigates
|
|
18
17
|
// through navToOption, which reports its own failure
|
|
@@ -13,7 +13,10 @@ const useStyles = makeStyles()(theme => ({
|
|
|
13
13
|
root: {
|
|
14
14
|
// above breakpoint split view
|
|
15
15
|
zIndex: 200,
|
|
16
|
-
|
|
16
|
+
...(theme.palette.mode === 'dark' && {
|
|
17
|
+
outline: `1px solid ${theme.palette.divider}`,
|
|
18
|
+
outlineOffset: -1,
|
|
19
|
+
}),
|
|
17
20
|
display: 'inline-flex',
|
|
18
21
|
alignItems: 'center',
|
|
19
22
|
maxWidth: 'calc(100% - 16px)',
|
|
@@ -34,7 +34,7 @@ export async function renderToSvg(model, opts) {
|
|
|
34
34
|
// itself.
|
|
35
35
|
const { tracks, displayResults, tracksHeight, legendWidth, skippedTracks } = await renderViewTracks({
|
|
36
36
|
view: model,
|
|
37
|
-
opts,
|
|
37
|
+
opts: { ...opts, fontSize },
|
|
38
38
|
theme,
|
|
39
39
|
textHeight,
|
|
40
40
|
trackLabels,
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import type { TrackLabelMode } from '../types.ts';
|
|
2
|
-
export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x,
|
|
2
|
+
export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, }: {
|
|
3
3
|
trackName: string;
|
|
4
4
|
trackLabels: TrackLabelMode;
|
|
5
5
|
fontSize: number;
|
|
6
6
|
textHeight: number;
|
|
7
7
|
trackLabelOffset: number;
|
|
8
8
|
x: number;
|
|
9
|
-
raised?: boolean;
|
|
10
9
|
}): import("react").JSX.Element | null;
|
|
@@ -4,24 +4,20 @@ import { stripAlpha } from '@jbrowse/core/util';
|
|
|
4
4
|
import { TRACK_LABEL_GAP, insetLabelBaselineY, offsetLabelBaselineY, } from './util.js';
|
|
5
5
|
// Where the label sits, per mode. 'left' right-aligns in the gutter
|
|
6
6
|
// trackLabelLeftOffset reserved (hence the shared TRACK_LABEL_GAP), beside the
|
|
7
|
-
// first row
|
|
8
|
-
// gutter beside its rows. The other modes hang off the leftmost visible content
|
|
7
|
+
// first row. The other modes hang off the leftmost visible content
|
|
9
8
|
// at `x`, either just above the track body ('offset') or inset over it
|
|
10
9
|
// ('overlapping').
|
|
11
10
|
//
|
|
12
11
|
// Every mode is placed on its alphabetic baseline (the SVG default, so no
|
|
13
|
-
// dominantBaseline is emitted at all): 'offset'
|
|
14
|
-
// descenders land a known distance above the track body — the band is
|
|
12
|
+
// dominantBaseline is emitted at all): 'offset' so its descenders land a known distance above the track body — the band is
|
|
15
13
|
// `textHeight` tall, and offsetLabelBaselineY owns that arithmetic — and
|
|
16
14
|
// 'left'/'overlapping' so their ascenders stay inside the track box they align
|
|
17
15
|
// with.
|
|
18
|
-
function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x,
|
|
16
|
+
function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x, }) {
|
|
19
17
|
if (trackLabels === 'left') {
|
|
20
18
|
return {
|
|
21
19
|
x: trackLabelOffset - TRACK_LABEL_GAP,
|
|
22
|
-
y:
|
|
23
|
-
? offsetLabelBaselineY(textHeight, fontSize)
|
|
24
|
-
: insetLabelBaselineY(fontSize),
|
|
20
|
+
y: insetLabelBaselineY(fontSize),
|
|
25
21
|
textAnchor: 'end',
|
|
26
22
|
};
|
|
27
23
|
}
|
|
@@ -34,7 +30,7 @@ function labelPosition({ trackLabels, trackLabelOffset, textHeight, fontSize, x,
|
|
|
34
30
|
// stay inside it (at y=0 they rose into the track above)
|
|
35
31
|
return { x: x + 5, y: insetLabelBaselineY(fontSize) };
|
|
36
32
|
}
|
|
37
|
-
export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x,
|
|
33
|
+
export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHeight, trackLabelOffset, x, }) {
|
|
38
34
|
const palette = usePalette();
|
|
39
35
|
if (trackLabels === 'hidden') {
|
|
40
36
|
return null;
|
|
@@ -45,7 +41,6 @@ export default function SVGTrackLabel({ trackLabels, trackName, fontSize, textHe
|
|
|
45
41
|
textHeight,
|
|
46
42
|
fontSize,
|
|
47
43
|
x,
|
|
48
|
-
raised,
|
|
49
44
|
});
|
|
50
45
|
// 'overlapping' prints over the track's own data, which the on-screen label
|
|
51
46
|
// clears with a paper box, so it carries the halo text over a plot needs
|
|
@@ -6,7 +6,7 @@ import { getSession } from '@jbrowse/core/util';
|
|
|
6
6
|
import { exportsTooLargeNote } from '@jbrowse/display-kit/renderDisplaySvg';
|
|
7
7
|
import SVGRegionSeparators from './SVGRegionSeparators.js';
|
|
8
8
|
import SVGTrackLabel from './SVGTrackLabel.js';
|
|
9
|
-
import { labelOffset,
|
|
9
|
+
import { labelOffset, trackBoxOffsets, trackLabelMode } from './util.js';
|
|
10
10
|
export default function SVGTracks({ displayResults, model, textHeight, fontSize, trackLabels, trackLabelOffset, leftBuffer, legendWidth, }) {
|
|
11
11
|
const session = getSession(model);
|
|
12
12
|
const x = Math.max(-model.offsetPx, 0);
|
|
@@ -17,6 +17,6 @@ export default function SVGTracks({ displayResults, model, textHeight, fontSize,
|
|
|
17
17
|
const display = track.displays[0];
|
|
18
18
|
const currentOffset = offsets[i];
|
|
19
19
|
const textOffset = labelOffset(track, trackLabels, textHeight);
|
|
20
|
-
return (_jsxs("g", { transform: `translate(0 ${currentOffset})`, children: [_jsx(SvgClipRect, { id: `track-clip-${svgNodeId(model)}-${conf.trackId}`, x: -leftBuffer, y: textOffset, width: model.width + trackLabelOffset + leftBuffer + legendWidth, height: display.height, children: _jsxs("g", { transform: `translate(${trackLabelOffset} ${textOffset})`, children: [result, exportsTooLargeNote(display) ? null : (_jsx(SVGRegionSeparators, { model: model, height: display.height }))] }) }), _jsx(SVGTrackLabel, { trackName: trackName, fontSize: fontSize, textHeight: textHeight, trackLabels: trackLabelMode(track, trackLabels), trackLabelOffset: trackLabelOffset,
|
|
20
|
+
return (_jsxs("g", { transform: `translate(0 ${currentOffset})`, children: [_jsx(SvgClipRect, { id: `track-clip-${svgNodeId(model)}-${conf.trackId}`, x: -leftBuffer, y: textOffset, width: model.width + trackLabelOffset + leftBuffer + legendWidth, height: display.height, children: _jsxs("g", { transform: `translate(${trackLabelOffset} ${textOffset})`, children: [result, exportsTooLargeNote(display) ? null : (_jsx(SVGRegionSeparators, { model: model, height: display.height }))] }) }), _jsx(SVGTrackLabel, { trackName: trackName, fontSize: fontSize, textHeight: textHeight, trackLabels: trackLabelMode(track, trackLabels), trackLabelOffset: trackLabelOffset, x: x + trackLabelOffset })] }, conf.trackId));
|
|
21
21
|
}) }));
|
|
22
22
|
}
|
|
@@ -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';
|
|
@@ -7,7 +8,7 @@ export interface SvgExportTrack {
|
|
|
7
8
|
displays: {
|
|
8
9
|
height: number;
|
|
9
10
|
svgLegendWidth?: () => number;
|
|
10
|
-
svgSidebarWidth?:
|
|
11
|
+
svgSidebarWidth?: LgvSvgExportable['svgSidebarWidth'];
|
|
11
12
|
/**
|
|
12
13
|
* Optional, and the option is the point: SVG export is a substantial extra
|
|
13
14
|
* implementation for a display type, and a third-party plugin that has not
|
|
@@ -125,7 +125,15 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
|
|
|
125
125
|
* question about regions and is true before a track is instantiated (the first
|
|
126
126
|
* figure then draws a header over nothing, and nothing else ever changes to
|
|
127
127
|
* correct it); **their heights and minimized flags**, since the geometry is
|
|
128
|
-
* derived from them; **
|
|
128
|
+
* derived from them; **their configs**, since a display's settings are slots on
|
|
129
|
+
* the track config and a shown track's snapshot spells that config as its id;
|
|
130
|
+
* **the legend sections a reader dismissed** and **the per-group state**
|
|
131
|
+
* (hidden sections, collapses, height overrides: `groupStateKey`), which are
|
|
132
|
+
* volatile and in no snapshot; **the reload counter**, since a Retry or a Force
|
|
133
|
+
* load leaves every snapshot as it was while the figure has an error or a
|
|
134
|
+
* too-large note to replace; **the view's coloring toggles** (`colorByCDS`,
|
|
135
|
+
* `showAminoAcids`), named one by one because the view's own snapshot moves
|
|
136
|
+
* every pan frame; **the width**, since a resize can widen the canvas without
|
|
129
137
|
* moving the locus; **the theme**, since each display bakes colors into its own
|
|
130
138
|
* bodies, so a figure from the other mode is not stale but unreadable; and **the
|
|
131
139
|
* highlight bands**, which are drawn in the figure and are the one thing in it a
|
|
@@ -133,8 +141,10 @@ const FrozenSvgFigure = memo(function FrozenSvgFigure({ view, snapshot, }) {
|
|
|
133
141
|
*
|
|
134
142
|
* A plugin's own overlay, through `LinearGenomeView-HighlightSVGComponent`, is
|
|
135
143
|
* state this cannot see, so a change to it shows up at the figure's next
|
|
136
|
-
* redraw rather than at once.
|
|
137
|
-
*
|
|
144
|
+
* redraw rather than at once. So does a track's vertical scroll, which moves
|
|
145
|
+
* every wheel frame and has no settled copy to key on. Subscribing from inside
|
|
146
|
+
* the figure is the thing that must not happen — see the note at the top of
|
|
147
|
+
* the file.
|
|
138
148
|
*/
|
|
139
149
|
function figureKey(view, themeName) {
|
|
140
150
|
// A closed view is not an error, it is a host doing an ordinary thing in an
|
|
@@ -156,9 +166,19 @@ function figureKey(view, themeName) {
|
|
|
156
166
|
view.coarseVisibleLocStrings,
|
|
157
167
|
view.coarseBpPerPx,
|
|
158
168
|
view.width,
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
view.tracks.map(track => {
|
|
170
|
+
const display = track.displays[0];
|
|
171
|
+
return [
|
|
172
|
+
getSnapshot(track),
|
|
173
|
+
getSnapshot(track.configuration),
|
|
174
|
+
display?.height,
|
|
175
|
+
display?.dismissedLegendSections,
|
|
176
|
+
display?.groupStateKey,
|
|
177
|
+
display?.reloadCounter,
|
|
178
|
+
];
|
|
179
|
+
}),
|
|
180
|
+
view.colorByCDS,
|
|
181
|
+
view.showAminoAcids,
|
|
162
182
|
session.getActiveThemeOptions?.(themeName),
|
|
163
183
|
session.highlightsVisible ? view.highlights : false,
|
|
164
184
|
session.highlightLabelsVisible,
|
|
@@ -1,23 +1,24 @@
|
|
|
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;
|
|
9
|
-
|
|
10
|
-
}[];
|
|
12
|
+
} & SidebarDisplay)[];
|
|
11
13
|
}
|
|
12
14
|
export interface SvgDisplayResult {
|
|
13
15
|
track: {
|
|
14
16
|
configuration: AnyConfigurationModel;
|
|
15
|
-
displays: {
|
|
17
|
+
displays: ({
|
|
16
18
|
height: number;
|
|
17
19
|
regionTooLarge?: boolean;
|
|
18
20
|
drawsWhenTooLarge?: boolean;
|
|
19
|
-
|
|
20
|
-
}[];
|
|
21
|
+
} & SidebarDisplay)[];
|
|
21
22
|
};
|
|
22
23
|
result: ReactNode;
|
|
23
24
|
}
|
|
@@ -83,14 +84,15 @@ export declare function getRulerLayout(rulerHeight: number): {
|
|
|
83
84
|
};
|
|
84
85
|
export declare const refNameLabelBoxHeight: number;
|
|
85
86
|
export declare const refNameLabelBaselineY: number;
|
|
86
|
-
export declare function trackLabelMode(track:
|
|
87
|
-
|
|
87
|
+
export declare function trackLabelMode(track: {
|
|
88
|
+
displays: ({
|
|
89
|
+
prefersOffset?: boolean;
|
|
90
|
+
} & SidebarDisplay)[];
|
|
91
|
+
}, trackLabels: TrackLabelMode): TrackLabelMode;
|
|
88
92
|
export declare function labelOffset(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
|
|
89
93
|
interface SidebarTrack {
|
|
90
94
|
configuration: AnyConfigurationModel;
|
|
91
|
-
displays:
|
|
92
|
-
svgSidebarWidth?: () => number;
|
|
93
|
-
}[];
|
|
95
|
+
displays: SidebarDisplay[];
|
|
94
96
|
}
|
|
95
97
|
export declare const TRACK_LABEL_GAP = 40;
|
|
96
98
|
export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }: {
|
|
@@ -100,7 +102,7 @@ export declare function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fo
|
|
|
100
102
|
fontFamily?: string;
|
|
101
103
|
session: TrackCatalog;
|
|
102
104
|
}): number;
|
|
103
|
-
export declare function trackSidebarWidth(track: Pick<SidebarTrack, 'displays'
|
|
105
|
+
export declare function trackSidebarWidth(track: Pick<SidebarTrack, 'displays'>, text?: ExportTextStyle): number;
|
|
104
106
|
export declare function trackBoxHeight(track: TrackHeights, trackLabels: TrackLabelMode, textHeight: number): number;
|
|
105
107
|
export declare function trackBoxOffsets(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number[];
|
|
106
108
|
export declare function totalHeight(tracks: TrackHeights[], trackLabels: TrackLabelMode, textHeight: number): number;
|
|
@@ -179,24 +179,17 @@ export const refNameLabelBaselineY = labelBaselineFromTop(0, REF_NAME_LABEL_FONT
|
|
|
179
179
|
// The mode one track's label is drawn in. 'overlapping' yields to 'offset' for a
|
|
180
180
|
// display that `prefersOffset`, as TrackContainer does on screen: its left edge
|
|
181
181
|
// carries content — an axis, a sample's genotypes — the label would print over.
|
|
182
|
+
// 'left' yields to 'offset' for a track whose sidebar holds the gutter beside
|
|
183
|
+
// its rows.
|
|
182
184
|
export function trackLabelMode(track, trackLabels) {
|
|
183
|
-
return trackLabels === 'overlapping' && track.displays[0]?.prefersOffset
|
|
185
|
+
return (trackLabels === 'overlapping' && track.displays[0]?.prefersOffset) ||
|
|
186
|
+
(trackLabels === 'left' && trackSidebarWidth(track) > 0)
|
|
184
187
|
? 'offset'
|
|
185
188
|
: trackLabels;
|
|
186
189
|
}
|
|
187
|
-
//
|
|
188
|
-
// beside the first of them: the gutter beside the rows holds the track's own
|
|
189
|
-
// sidebar, so the name heads it instead of standing off to its left.
|
|
190
|
-
export function leftLabelRaised(track, trackLabels) {
|
|
191
|
-
return trackLabels === 'left' && trackSidebarWidth(track) > 0;
|
|
192
|
-
}
|
|
193
|
-
// space the label pushes a track's body down by: an 'offset' label, or a raised
|
|
194
|
-
// 'left' one
|
|
190
|
+
// space an 'offset' label pushes a track's body down by
|
|
195
191
|
export function labelOffset(track, trackLabels, textHeight) {
|
|
196
|
-
return trackLabelMode(track, trackLabels) === 'offset'
|
|
197
|
-
leftLabelRaised(track, trackLabels)
|
|
198
|
-
? textHeight
|
|
199
|
-
: 0;
|
|
192
|
+
return trackLabelMode(track, trackLabels) === 'offset' ? textHeight : 0;
|
|
200
193
|
}
|
|
201
194
|
// Gap between a 'left' track label's right edge and the track body.
|
|
202
195
|
// SVGTrackLabel right-aligns its text at `trackLabelOffset - TRACK_LABEL_GAP`,
|
|
@@ -204,9 +197,7 @@ export function labelOffset(track, trackLabels, textHeight) {
|
|
|
204
197
|
// gutter it was measured for.
|
|
205
198
|
export const TRACK_LABEL_GAP = 40;
|
|
206
199
|
// Horizontal gutter left of the track bodies: the widest of each track's
|
|
207
|
-
// sidebar and
|
|
208
|
-
// name share the column because the name rises above the sidebar
|
|
209
|
-
// (leftLabelRaised). Takes an
|
|
200
|
+
// sidebar and of each name drawn 'left', plus TRACK_LABEL_GAP. Takes an
|
|
210
201
|
// already-minimized-filtered track list, so the reserved width matches the
|
|
211
202
|
// labels that actually get drawn.
|
|
212
203
|
//
|
|
@@ -225,14 +216,14 @@ export const TRACK_LABEL_GAP = 40;
|
|
|
225
216
|
// `getScalebarRefNameLabels`, an on-screen model getter, so making them
|
|
226
217
|
// family-aware means threading an export option through screen state.
|
|
227
218
|
export function trackLabelLeftOffset({ tracks, trackLabels, fontSize, fontFamily, session, }) {
|
|
228
|
-
return max(tracks.map(t => Math.max(trackSidebarWidth(t), trackLabels === 'left'
|
|
219
|
+
return max(tracks.map(t => Math.max(trackSidebarWidth(t, { fontSize, fontFamily }), trackLabelMode(t, trackLabels) === 'left'
|
|
229
220
|
? measureText(svgTrackName(t, session), fontSize, fontFamily) +
|
|
230
221
|
TRACK_LABEL_GAP
|
|
231
222
|
: 0)), 0);
|
|
232
223
|
}
|
|
233
224
|
// Px of tree and row labels a track's display draws left of its body.
|
|
234
|
-
export function trackSidebarWidth(track) {
|
|
235
|
-
return track.displays[0]?.svgSidebarWidth?.() ?? 0;
|
|
225
|
+
export function trackSidebarWidth(track, text) {
|
|
226
|
+
return track.displays[0]?.svgSidebarWidth?.(text) ?? 0;
|
|
236
227
|
}
|
|
237
228
|
// vertical box a single track occupies. Shared by totalHeight (sum) and
|
|
238
229
|
// trackBoxOffsets (prefix-sum) so the two can't drift.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-linear-genome-view",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 linear genome view",
|
|
6
6
|
"keywords": [
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"@jbrowse/mobx-state-tree": "^6.7.0",
|
|
25
25
|
"@mui/icons-material": "^9.4.0",
|
|
26
26
|
"@mui/material": "^9.4.0",
|
|
27
|
-
"mobx": "^7.0.
|
|
27
|
+
"mobx": "^7.0.6",
|
|
28
28
|
"mobx-react": "^10.0.2",
|
|
29
|
-
"@jbrowse/
|
|
30
|
-
"@jbrowse/core": "^5.0.0-beta.
|
|
31
|
-
"@jbrowse/
|
|
32
|
-
"@jbrowse/display-ui": "^5.0.0-beta.
|
|
29
|
+
"@jbrowse/core": "^5.0.0-beta.13",
|
|
30
|
+
"@jbrowse/render-core": "^5.0.0-beta.13",
|
|
31
|
+
"@jbrowse/display-kit": "^5.0.0-beta.13",
|
|
32
|
+
"@jbrowse/display-ui": "^5.0.0-beta.13"
|
|
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.
|
|
43
|
+
"@jbrowse/display-test-utils": "^5.0.0-beta.13"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"prebuild": "pnpm clean",
|