@jbrowse/plugin-linear-genome-view 5.0.0-beta.1 → 5.0.0-beta.3
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/LaunchLinearGenomeView/index.js +2 -13
- package/esm/LinearGenomeView/afterAttach.js +16 -18
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +1 -1
- package/esm/LinearGenomeView/components/PaddingBlocks.d.ts +1 -1
- package/esm/LinearGenomeView/components/PaddingBlocks.js +11 -1
- package/esm/LinearGenomeView/components/ScalebarRefNameLabels.js +37 -3
- package/esm/LinearGenomeView/components/SequenceSearchDialog.d.ts +1 -1
- package/esm/LinearGenomeView/components/TrackContainer.js +46 -4
- package/esm/LinearGenomeView/components/TrackLabelButtons.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelDragHandle.js +2 -2
- package/esm/LinearGenomeView/components/TrackLabelMenu.js +3 -2
- package/esm/LinearGenomeView/components/TrackRenderingContainer.d.ts +2 -1
- package/esm/LinearGenomeView/components/TrackRenderingContainer.js +5 -15
- package/esm/LinearGenomeView/components/ZoomButton.js +6 -1
- package/esm/LinearGenomeView/components/ZoomTransform.js +4 -0
- package/esm/LinearGenomeView/components/searchModes.d.ts +1 -1
- package/esm/LinearGenomeView/components/searchModes.js +1 -1
- package/esm/LinearGenomeView/consts.js +1 -1
- package/esm/LinearGenomeView/containingLgv.d.ts +15 -0
- package/esm/LinearGenomeView/containingLgv.js +16 -0
- package/esm/LinearGenomeView/index.d.ts +1 -0
- package/esm/LinearGenomeView/index.js +8 -1
- package/esm/LinearGenomeView/launchKeys.d.ts +2 -0
- package/esm/LinearGenomeView/launchKeys.js +23 -0
- package/esm/LinearGenomeView/lazyDialogs.d.ts +1 -1
- package/esm/LinearGenomeView/linkedViewSync.d.ts +1 -1
- package/esm/LinearGenomeView/linkedViewSync.js +6 -0
- package/esm/LinearGenomeView/model.d.ts +1779 -41
- package/esm/LinearGenomeView/model.js +192 -96
- package/esm/LinearGenomeView/svgcomponents/figureContract.js +14 -14
- package/esm/LinearGenomeView/svgcomponents/useViewSvgFigure.js +2 -2
- package/esm/LinearGenomeView/types.d.ts +1 -1
- package/esm/LinearGenomeView/util.d.ts +31 -0
- package/esm/LinearGenomeView/util.js +48 -0
- package/esm/displayKitTests/perRegionTestEnv.d.ts +145 -55
- package/esm/displayKitTests/perRegionTestEnv.js +26 -25
- package/esm/index.d.ts +2 -9
- package/esm/index.js +2 -3
- package/esm/searchUtils.d.ts +6 -3
- package/esm/searchUtils.js +37 -11
- package/package.json +8 -8
- package/esm/LinearGenomeView/FloatingSvgOverlay.d.ts +0 -5
- package/esm/LinearGenomeView/FloatingSvgOverlay.js +0 -25
- package/esm/LinearGenomeView/initKeys.d.ts +0 -13
- package/esm/LinearGenomeView/initKeys.js +0 -104
|
@@ -28,47 +28,49 @@ function makeStateModel(control, gate, configSchema) {
|
|
|
28
28
|
.volatile(() => ({
|
|
29
29
|
/** every `fetchNeeded` call, as the region list it was handed */
|
|
30
30
|
fetchLog: [],
|
|
31
|
-
loadedData: new Map(),
|
|
32
31
|
/**
|
|
33
|
-
* What `
|
|
32
|
+
* What `zoomFetchKey` answers. A volatile, not a `control` knob, and
|
|
34
33
|
* that is the point: a real display's key reads view state, so the
|
|
35
34
|
* autorun re-runs when it moves. A plain closure value would be memoized
|
|
36
35
|
* by the computed and never invalidate.
|
|
37
36
|
*/
|
|
38
37
|
fetchKey: '',
|
|
39
38
|
}))
|
|
39
|
+
.views(self => {
|
|
40
|
+
// chained, not replaced: `staleAnswers` forces a false answer for a
|
|
41
|
+
// bounded number of calls, and everything else is the foundation's own
|
|
42
|
+
// store-derived default
|
|
43
|
+
const superRegionHasData = self.regionHasData;
|
|
44
|
+
return {
|
|
45
|
+
regionHasData(displayedRegionIndex) {
|
|
46
|
+
control.cacheValidCalls += 1;
|
|
47
|
+
if (control.staleAnswers > 0) {
|
|
48
|
+
control.staleAnswers -= 1;
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return superRegionHasData.call(self, displayedRegionIndex);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
})
|
|
40
55
|
.views(self => ({
|
|
56
|
+
/** the fetched payloads, off the foundation's store */
|
|
57
|
+
get loadedData() {
|
|
58
|
+
return self.regionPayloads;
|
|
59
|
+
},
|
|
41
60
|
get gateEnabled() {
|
|
42
61
|
return gate.gateEnabled ?? false;
|
|
43
62
|
},
|
|
44
|
-
get densityGateEnabled() {
|
|
45
|
-
return gate.densityGateEnabled ?? false;
|
|
46
|
-
},
|
|
47
63
|
get densityTooLarge() {
|
|
48
64
|
return control.densityTooLarge;
|
|
49
65
|
},
|
|
50
|
-
get
|
|
66
|
+
get zoomFetchKey() {
|
|
51
67
|
return self.fetchKey;
|
|
52
68
|
},
|
|
53
|
-
regionHasData(_displayedRegionIndex) {
|
|
54
|
-
control.cacheValidCalls += 1;
|
|
55
|
-
if (control.staleAnswers > 0) {
|
|
56
|
-
control.staleAnswers -= 1;
|
|
57
|
-
return false;
|
|
58
|
-
}
|
|
59
|
-
return true;
|
|
60
|
-
},
|
|
61
69
|
}))
|
|
62
70
|
.actions(self => ({
|
|
63
71
|
setFetchKey(key) {
|
|
64
72
|
self.fetchKey = key;
|
|
65
73
|
},
|
|
66
|
-
setLoaded(displayedRegionIndex, value) {
|
|
67
|
-
self.loadedData.set(displayedRegionIndex, value);
|
|
68
|
-
},
|
|
69
|
-
clearDisplaySpecificData() {
|
|
70
|
-
self.loadedData.clear();
|
|
71
|
-
},
|
|
72
74
|
}))
|
|
73
75
|
.actions(self => ({
|
|
74
76
|
fetchNeeded(needed) {
|
|
@@ -93,17 +95,15 @@ function makeStateModel(control, gate, configSchema) {
|
|
|
93
95
|
// budget means no measurement at all, which is why `estimateCalls`
|
|
94
96
|
// stays at zero for an ungated display.
|
|
95
97
|
if (byteLimit === undefined) {
|
|
96
|
-
return { value:
|
|
98
|
+
return { value: control.payloadTag };
|
|
97
99
|
}
|
|
98
100
|
control.estimateCalls += 1;
|
|
99
101
|
const bytes = control.estimateBytes;
|
|
100
102
|
return bytes > byteLimit
|
|
101
103
|
? { regionTooLarge: true, bytes }
|
|
102
|
-
: { value:
|
|
103
|
-
},
|
|
104
|
-
onResult: (idx, result) => {
|
|
105
|
-
self.setLoaded(idx, result.value);
|
|
104
|
+
: { value: control.payloadTag, bytes };
|
|
106
105
|
},
|
|
106
|
+
onResult: (_idx, result) => result.value,
|
|
107
107
|
});
|
|
108
108
|
},
|
|
109
109
|
}));
|
|
@@ -121,6 +121,7 @@ export function createPerRegionTestEnvironment({ measuresBytes = false, gate, es
|
|
|
121
121
|
estimateBytes,
|
|
122
122
|
estimateCalls: 0,
|
|
123
123
|
densityTooLarge: false,
|
|
124
|
+
payloadTag: 'data',
|
|
124
125
|
};
|
|
125
126
|
const optIns = gate ?? { gateEnabled: measuresBytes };
|
|
126
127
|
const env = createDisplayTestEnvironment({
|
package/esm/index.d.ts
CHANGED
|
@@ -16,12 +16,6 @@ export default class LinearGenomeViewPlugin extends Plugin {
|
|
|
16
16
|
readonly description: 'Declarative equivalent of the "Force load" button on the "too much data" banner: when true the display always renders, however large the region or dense the features. Off by default (the gate guards against huge downloads). Set it on a view no one can interact with — an embedded / notebook view, or a screenshot — where the region is known and you want it drawn without a click.';
|
|
17
17
|
readonly advanced: true;
|
|
18
18
|
};
|
|
19
|
-
readonly maxFeatureScreenDensity: {
|
|
20
|
-
readonly type: "number";
|
|
21
|
-
readonly description: "maximum features per pixel before showing a \"too many features\" message";
|
|
22
|
-
readonly defaultValue: 1;
|
|
23
|
-
readonly advanced: true;
|
|
24
|
-
};
|
|
25
19
|
readonly height: {
|
|
26
20
|
readonly type: "number";
|
|
27
21
|
readonly defaultValue: 100;
|
|
@@ -92,7 +86,6 @@ export { default as HeaderSearchBoxRow } from './LinearGenomeView/components/Hea
|
|
|
92
86
|
export { searchBoxMenuItems, useSearchBoxPrefs, } from './LinearGenomeView/components/useSearchBoxPrefs.ts';
|
|
93
87
|
export type { SearchBoxPrefs } from './LinearGenomeView/components/useSearchBoxPrefs.ts';
|
|
94
88
|
export { normalizeTrackInit } from '@jbrowse/core/util/tracks';
|
|
95
|
-
export { linearGenomeViewPropKeys, partitionLaunchKeys, } from './LinearGenomeView/initKeys.ts';
|
|
96
89
|
export { applyInitHighlights } from './LinearGenomeView/afterAttach.ts';
|
|
97
90
|
export { MultiLevelRubberband } from './MultiLevelRubberband/index.ts';
|
|
98
91
|
export { fetchResults, SearchResultsNotFoundError } from './searchUtils.ts';
|
|
@@ -102,6 +95,7 @@ export type { ScalebarRefNameLabel } from './LinearGenomeView/util.ts';
|
|
|
102
95
|
export type { RegionsOrientation } from './LinearGenomeView/util.ts';
|
|
103
96
|
export { makeTicks } from './LinearGenomeView/util.ts';
|
|
104
97
|
export type { Tick } from './LinearGenomeView/util.ts';
|
|
98
|
+
export { containingLgv } from './LinearGenomeView/containingLgv.ts';
|
|
105
99
|
export { showRegionsWithUndo } from './LinearGenomeView/showRegionsWithUndo.ts';
|
|
106
100
|
export type { SharedFit } from './LinearGenomeView/sharedScaleContainer.ts';
|
|
107
101
|
export { fitAllRegionsWindow } from './LinearGenomeView/util.ts';
|
|
@@ -117,8 +111,7 @@ export { default as ExportSvgDialog } from './LinearGenomeView/components/Export
|
|
|
117
111
|
export { GetSequenceDialog } from './LinearGenomeView/lazyDialogs.ts';
|
|
118
112
|
export { default as ConnectedHoverHighlight } from './LinearGenomeView/components/ConnectedHoverHighlight.tsx';
|
|
119
113
|
export { default as HoverPositionHighlight } from './LinearGenomeView/components/HoverPositionHighlight.tsx';
|
|
120
|
-
export { TrackOverlayContext, TrackOverlayPortal, TrackOverlaySlot, } from '@jbrowse/display-ui';
|
|
121
|
-
export { FloatingSvgOverlay } from './LinearGenomeView/FloatingSvgOverlay.tsx';
|
|
114
|
+
export { FloatingSvgOverlay, TrackOverlayContext, TrackOverlayPortal, TrackOverlaySlot, } from '@jbrowse/display-ui';
|
|
122
115
|
export type { HoverHighlightPosition } from './LinearGenomeView/components/HoverPositionHighlight.tsx';
|
|
123
116
|
export { SvgChrome, SvgClipRect } from '@jbrowse/core/svg/SvgExport';
|
|
124
117
|
export { svgSafeId } from '@jbrowse/core/svg/svgId';
|
package/esm/index.js
CHANGED
|
@@ -85,7 +85,6 @@ export { default as HeaderSearchBoxes } from './LinearGenomeView/components/Head
|
|
|
85
85
|
export { default as HeaderSearchBoxRow } from './LinearGenomeView/components/HeaderSearchBoxRow.js';
|
|
86
86
|
export { searchBoxMenuItems, useSearchBoxPrefs, } from './LinearGenomeView/components/useSearchBoxPrefs.js';
|
|
87
87
|
export { normalizeTrackInit } from '@jbrowse/core/util/tracks';
|
|
88
|
-
export { linearGenomeViewPropKeys, partitionLaunchKeys, } from './LinearGenomeView/initKeys.js';
|
|
89
88
|
export { applyInitHighlights } from './LinearGenomeView/afterAttach.js';
|
|
90
89
|
export { MultiLevelRubberband } from './MultiLevelRubberband/index.js';
|
|
91
90
|
export { fetchResults, SearchResultsNotFoundError } from './searchUtils.js';
|
|
@@ -99,6 +98,7 @@ export { makeTicks } from './LinearGenomeView/util.js';
|
|
|
99
98
|
// The two halves of "show these regions instead": navigate the view you are
|
|
100
99
|
// looking at, or seed a snapshot for a new one. A caller deriving either itself
|
|
101
100
|
// lands on a viewport property the model no longer reads — see each for how.
|
|
101
|
+
export { containingLgv } from './LinearGenomeView/containingLgv.js';
|
|
102
102
|
export { showRegionsWithUndo } from './LinearGenomeView/showRegionsWithUndo.js';
|
|
103
103
|
export { fitAllRegionsWindow } from './LinearGenomeView/util.js';
|
|
104
104
|
export { renderToSvg } from './LinearGenomeView/svgcomponents/SVGLinearGenomeView.js';
|
|
@@ -125,8 +125,7 @@ export { default as HoverPositionHighlight } from './LinearGenomeView/components
|
|
|
125
125
|
// mounts it, and so does an embedder mounting `RenderingComponent` directly —
|
|
126
126
|
// who otherwise supplies no node at all and gets display chrome buried under
|
|
127
127
|
// their own region masks.
|
|
128
|
-
export { TrackOverlayContext, TrackOverlayPortal, TrackOverlaySlot, } from '@jbrowse/display-ui';
|
|
129
|
-
export { FloatingSvgOverlay } from './LinearGenomeView/FloatingSvgOverlay.js';
|
|
128
|
+
export { FloatingSvgOverlay, TrackOverlayContext, TrackOverlayPortal, TrackOverlaySlot, } from '@jbrowse/display-ui';
|
|
130
129
|
export { SvgChrome, SvgClipRect } from '@jbrowse/core/svg/SvgExport';
|
|
131
130
|
// for a display that hand-rolls a <clipPath> instead of using SvgClipRect (an
|
|
132
131
|
// inset or non-rect clip); ids built from a trackId/refName need it
|
package/esm/searchUtils.d.ts
CHANGED
|
@@ -32,28 +32,31 @@ export declare function unanimousResult({ results, model, session, assembly, }:
|
|
|
32
32
|
session: TrackCatalog;
|
|
33
33
|
assembly?: Assembly;
|
|
34
34
|
}): BaseResult | undefined;
|
|
35
|
-
export declare function showSearchResults({ results, query, model, assemblyName, grow, }: {
|
|
35
|
+
export declare function showSearchResults({ results, query, model, assemblyName, grow, showHitTrack, }: {
|
|
36
36
|
results: BaseResult[];
|
|
37
37
|
query: string;
|
|
38
38
|
model: LinearGenomeViewModel;
|
|
39
39
|
assemblyName: string;
|
|
40
40
|
grow?: number;
|
|
41
|
+
showHitTrack?: boolean;
|
|
41
42
|
}): Promise<boolean>;
|
|
42
|
-
export declare function navToOption({ option, model, assemblyName, grow, }: {
|
|
43
|
+
export declare function navToOption({ option, model, assemblyName, grow, showHitTrack, }: {
|
|
43
44
|
model: LinearGenomeViewModel;
|
|
44
45
|
option: BaseResult;
|
|
45
46
|
assemblyName: string;
|
|
46
47
|
grow?: number;
|
|
48
|
+
showHitTrack?: boolean;
|
|
47
49
|
}): Promise<void>;
|
|
48
50
|
export declare class SearchResultsNotFoundError extends Error {
|
|
49
51
|
name: string;
|
|
50
52
|
}
|
|
51
53
|
export declare function notifySearchFailure(session: NotificationSink, e: unknown): void;
|
|
52
|
-
export declare function handleSelectedRegion({ input, model, assemblyName, grow, }: {
|
|
54
|
+
export declare function handleSelectedRegion({ input, model, assemblyName, grow, showHitTrack, }: {
|
|
53
55
|
input: string;
|
|
54
56
|
model: LinearGenomeViewModel;
|
|
55
57
|
assemblyName: string;
|
|
56
58
|
grow?: number;
|
|
59
|
+
showHitTrack?: boolean;
|
|
57
60
|
}): Promise<boolean>;
|
|
58
61
|
export declare function checkRef(str: string, isRef: (name: string) => boolean): boolean;
|
|
59
62
|
export declare function fetchResults({ queryString, searchType, assemblyName, textSearchManager, assembly, stopToken, }: {
|
package/esm/searchUtils.js
CHANGED
|
@@ -86,6 +86,24 @@ function trackRank(result, model, session) {
|
|
|
86
86
|
return session.getTrackById(trackId) ? 1 : 3;
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
// The pick is a stable minimum, so a linear scan rather than a sort: only the
|
|
90
|
+
// best rung is taken, and keeping the first strictly-lowest one is what leaves
|
|
91
|
+
// an agreeing group with nothing to choose between in the order the ranking
|
|
92
|
+
// handed it. Ranked once per hit for the reason `destinations` above it is:
|
|
93
|
+
// `trackRank` reaches `session.getTrackById`, and a comparator asks O(n log n)
|
|
94
|
+
// times for an answer that does not vary.
|
|
95
|
+
function bestRanked(results, model, session) {
|
|
96
|
+
let best = results[0];
|
|
97
|
+
let bestRank = trackRank(best, model, session);
|
|
98
|
+
for (let i = 1; i < results.length; i++) {
|
|
99
|
+
const rank = trackRank(results[i], model, session);
|
|
100
|
+
if (rank < bestRank) {
|
|
101
|
+
best = results[i];
|
|
102
|
+
bestRank = rank;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return best;
|
|
106
|
+
}
|
|
89
107
|
// The picker exists to disambiguate, and hits that name one feature at one
|
|
90
108
|
// place are not ambiguous — they are several indexes having found it. An
|
|
91
109
|
// instance carrying a handful of gene tracks turns every gene search into a
|
|
@@ -97,16 +115,12 @@ export function unanimousResult({ results, model, session, assembly, }) {
|
|
|
97
115
|
const destinations = results.map(r => destination(r, assembly));
|
|
98
116
|
const agree = destinations[0] !== undefined &&
|
|
99
117
|
destinations.every(d => d === destinations[0]);
|
|
100
|
-
|
|
101
|
-
// order the ranking handed it
|
|
102
|
-
return agree
|
|
103
|
-
? [...results].sort((a, b) => trackRank(a, model, session) - trackRank(b, model, session))[0]
|
|
104
|
-
: undefined;
|
|
118
|
+
return agree ? bestRanked(results, model, session) : undefined;
|
|
105
119
|
}
|
|
106
120
|
// Every multi-hit result set reaches the picker through here, so the two
|
|
107
121
|
// search surfaces cannot disagree about when one is worth raising. Returns
|
|
108
122
|
// whether the view moved.
|
|
109
|
-
export async function showSearchResults({ results, query, model, assemblyName, grow, }) {
|
|
123
|
+
export async function showSearchResults({ results, query, model, assemblyName, grow, showHitTrack, }) {
|
|
110
124
|
const session = getSession(model);
|
|
111
125
|
const unanimous = unanimousResult({
|
|
112
126
|
results,
|
|
@@ -115,7 +129,13 @@ export async function showSearchResults({ results, query, model, assemblyName, g
|
|
|
115
129
|
assembly: session.assemblyManager.get(assemblyName),
|
|
116
130
|
});
|
|
117
131
|
if (unanimous) {
|
|
118
|
-
await navToOption({
|
|
132
|
+
await navToOption({
|
|
133
|
+
option: unanimous,
|
|
134
|
+
model,
|
|
135
|
+
assemblyName,
|
|
136
|
+
grow,
|
|
137
|
+
showHitTrack,
|
|
138
|
+
});
|
|
119
139
|
return true;
|
|
120
140
|
}
|
|
121
141
|
else {
|
|
@@ -127,7 +147,11 @@ export async function showSearchResults({ results, query, model, assemblyName, g
|
|
|
127
147
|
// own edges, which is what this default is; a caller that asked for a specific
|
|
128
148
|
// padding gets that instead.
|
|
129
149
|
const SEARCH_HIT_GROW = 0.2;
|
|
130
|
-
|
|
150
|
+
// A hit lands with the track its index came from shown, which is what a name
|
|
151
|
+
// typed into the search box wants. A session spec that named its own tracks
|
|
152
|
+
// passes false: it asked for those tracks, and a hosted config's full RefSeq
|
|
153
|
+
// appearing beside the curated one it listed read as a bug.
|
|
154
|
+
export async function navToOption({ option, model, assemblyName, grow, showHitTrack = true, }) {
|
|
131
155
|
// getLocation() can be an empty string when a result reports hasLocation()
|
|
132
156
|
// but carries no coordinates; treat that as "no location" and fall back to
|
|
133
157
|
// the label rather than forwarding '' into an empty, view-blanking parse
|
|
@@ -136,8 +160,8 @@ export async function navToOption({ option, model, assemblyName, grow, }) {
|
|
|
136
160
|
const session = getSession(model);
|
|
137
161
|
const { assemblyManager } = session;
|
|
138
162
|
await model.navToLocations(parseLocStrings(location, assemblyName, (ref, asm) => assemblyManager.isValidRefName(ref, asm)), assemblyName, grow ?? SEARCH_HIT_GROW);
|
|
139
|
-
if (trackId && isAlive(model)) {
|
|
140
|
-
model.
|
|
163
|
+
if (showHitTrack && trackId && isAlive(model)) {
|
|
164
|
+
await model.launchTrack(trackId);
|
|
141
165
|
}
|
|
142
166
|
// same detach hazard as showTrack above: navToLocations awaits, and handlers
|
|
143
167
|
// read off the view (the canvas one calls getSession(model) and model.tracks),
|
|
@@ -174,7 +198,7 @@ export function notifySearchFailure(session, e) {
|
|
|
174
198
|
// about where to go and so raise the picker, and a view detached while the
|
|
175
199
|
// search RPC ran — and each of them resolves, so a caller awaiting this cannot
|
|
176
200
|
// otherwise tell "showing it" from "asked you which one".
|
|
177
|
-
export async function handleSelectedRegion({ input, model, assemblyName, grow, }) {
|
|
201
|
+
export async function handleSelectedRegion({ input, model, assemblyName, grow, showHitTrack, }) {
|
|
178
202
|
const { assemblyManager, textSearchManager } = getSession(model);
|
|
179
203
|
// resolves only once regions/aliases are loaded, which isValidRefName needs
|
|
180
204
|
// (it throws otherwise). A load failure is not this function's to report:
|
|
@@ -260,6 +284,7 @@ export async function handleSelectedRegion({ input, model, assemblyName, grow, }
|
|
|
260
284
|
model,
|
|
261
285
|
assemblyName,
|
|
262
286
|
grow,
|
|
287
|
+
showHitTrack,
|
|
263
288
|
});
|
|
264
289
|
}
|
|
265
290
|
else if (results.length === 1) {
|
|
@@ -272,6 +297,7 @@ export async function handleSelectedRegion({ input, model, assemblyName, grow, }
|
|
|
272
297
|
model,
|
|
273
298
|
assemblyName,
|
|
274
299
|
grow,
|
|
300
|
+
showHitTrack,
|
|
275
301
|
});
|
|
276
302
|
return true;
|
|
277
303
|
}
|
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.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "JBrowse 2 linear genome view",
|
|
6
6
|
"keywords": [
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
],
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"@jbrowse/mobx-state-tree": "^6.5.1",
|
|
25
|
-
"@mui/icons-material": "^9.
|
|
26
|
-
"@mui/material": "^9.
|
|
25
|
+
"@mui/icons-material": "^9.4.0",
|
|
26
|
+
"@mui/material": "^9.4.0",
|
|
27
27
|
"mobx": "^7.0.3",
|
|
28
28
|
"mobx-react": "^10.0.2",
|
|
29
|
-
"@jbrowse/core": "^5.0.0-beta.
|
|
30
|
-
"@jbrowse/
|
|
31
|
-
"@jbrowse/display-ui": "^5.0.0-beta.
|
|
32
|
-
"@jbrowse/
|
|
29
|
+
"@jbrowse/core": "^5.0.0-beta.3",
|
|
30
|
+
"@jbrowse/display-kit": "^5.0.0-beta.3",
|
|
31
|
+
"@jbrowse/display-ui": "^5.0.0-beta.3",
|
|
32
|
+
"@jbrowse/render-core": "^5.0.0-beta.3"
|
|
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.3"
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"prebuild": "pnpm clean",
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { TrackOverlayPortal } from '@jbrowse/display-ui';
|
|
3
|
-
import { observer } from 'mobx-react';
|
|
4
|
-
// Lifts an SVG legend / chrome above the inter-region padding masks: a
|
|
5
|
-
// full-track, pointer-events:none <svg> portaled into the TrackContainer overlay
|
|
6
|
-
// node (see TrackOverlayPortal). The SVG counterpart to the HTML overlays
|
|
7
|
-
// (FloatingLegend, HicOverlayPanel) — used where the same legend
|
|
8
|
-
// markup is also drawn by an SVG-export path, so it must stay <svg>.
|
|
9
|
-
//
|
|
10
|
-
// Children draw in <svg> user space; the wrapping <svg> stays pointer-events:none
|
|
11
|
-
// so it doesn't eat canvas events, so any interactive sub-content (a dismiss
|
|
12
|
-
// "×", clickable swatches) must set pointer-events:auto on its own element.
|
|
13
|
-
// fallbackInline={false}: outside a TrackContainer it renders nothing, matching
|
|
14
|
-
// callers whose export path draws its own inline legend.
|
|
15
|
-
export const FloatingSvgOverlay = observer(function FloatingSvgOverlay({ width, height, children, }) {
|
|
16
|
-
return (_jsx(TrackOverlayPortal, { fallbackInline: false, children: _jsx("svg", { style: {
|
|
17
|
-
position: 'absolute',
|
|
18
|
-
top: 0,
|
|
19
|
-
left: 0,
|
|
20
|
-
width,
|
|
21
|
-
height,
|
|
22
|
-
pointerEvents: 'none',
|
|
23
|
-
overflow: 'hidden',
|
|
24
|
-
}, children: children }) }));
|
|
25
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function partitionLaunchKeys(spec: object, viewPropKeys: ReadonlySet<string>): {
|
|
2
|
-
init: Record<string, unknown>;
|
|
3
|
-
viewProps: Record<string, unknown>;
|
|
4
|
-
unknown: Record<string, unknown>;
|
|
5
|
-
};
|
|
6
|
-
export declare function linearGenomeViewPropKeys(pluginManager: {
|
|
7
|
-
getViewType: (name: string) => {
|
|
8
|
-
stateModel: {
|
|
9
|
-
properties: object;
|
|
10
|
-
};
|
|
11
|
-
};
|
|
12
|
-
}): ReadonlySet<string>;
|
|
13
|
-
export declare function warnUnknownLaunchKeys(surface: string, unknown: object): void;
|
|
@@ -1,104 +0,0 @@
|
|
|
1
|
-
// The init keys are derived from their interface so they can't drift: the
|
|
2
|
-
// Record requires exactly one entry per key, so adding a field without listing
|
|
3
|
-
// it here is a compile error rather than a key that silently warns as "unknown".
|
|
4
|
-
//
|
|
5
|
-
// There is no matching list for the plain view props, and there must not be:
|
|
6
|
-
// they are whatever the state model declares, read off it by the caller and
|
|
7
|
-
// passed in as `viewPropKeys`. A hand-written eight is what left `hideHeader`,
|
|
8
|
-
// `showGridlines`, `showCytobands` and five others declared, menu-settable and
|
|
9
|
-
// silently unreachable from any spec — the same failure LinearSyntenyView's
|
|
10
|
-
// `drawLocationMarkers` had.
|
|
11
|
-
//
|
|
12
|
-
// #launchKeys LinearGenomeView — the URL parameters page renders this list
|
|
13
|
-
// rather than restating it; each of these keys has its own `¶m=` section
|
|
14
|
-
// there, which is why no description is attached here.
|
|
15
|
-
const knownInitKeyMap = {
|
|
16
|
-
loc: true,
|
|
17
|
-
grow: true,
|
|
18
|
-
assembly: true,
|
|
19
|
-
displayedRegionNames: true,
|
|
20
|
-
tracks: true,
|
|
21
|
-
tracklist: true,
|
|
22
|
-
nav: true,
|
|
23
|
-
highlight: true,
|
|
24
|
-
};
|
|
25
|
-
const knownInitKeys = new Set(Object.keys(knownInitKeyMap));
|
|
26
|
-
// Never settable from a spec, whatever the model declares: `type` picks the
|
|
27
|
-
// view and `id` is passed top-level so MST's optional identifier honors it.
|
|
28
|
-
const RESERVED = new Set(['id', 'type', 'init']);
|
|
29
|
-
// The viewport keys from before it was stored as a window. They are no longer
|
|
30
|
-
// declared properties, so the model's own property list does not contain them
|
|
31
|
-
// and they would partition as typos — reported as unknown and dropped. They are
|
|
32
|
-
// not typos: `preProcessSnapshot` still converts them, so they belong in the
|
|
33
|
-
// snapshot bucket, and a URL or saved spec that names them goes on working.
|
|
34
|
-
//
|
|
35
|
-
// Deletable with `legacyBpPerPx` in the model, and for the same reason.
|
|
36
|
-
const LEGACY_VIEWPORT_PROPS = new Set(['bpPerPx', 'offsetPx']);
|
|
37
|
-
// Partition launch keys three ways, once, for every caller that needs to know
|
|
38
|
-
// which is which:
|
|
39
|
-
//
|
|
40
|
-
// - `init`: resolution keys (loc, tracks, highlight, …) with no direct MST
|
|
41
|
-
// representation, which afterAttach applies on attach and then discards
|
|
42
|
-
// - `viewProps`: plain persisted props MST restores natively, so they belong on
|
|
43
|
-
// the view snapshot rather than in the blob
|
|
44
|
-
// - `unknown`: neither, i.e. a typo. MST silently drops unknown snapshot keys and
|
|
45
|
-
// `init` is a frozen blob, so nothing else would notice
|
|
46
|
-
//
|
|
47
|
-
// The two callers differ only in what they do with each bucket: the launcher
|
|
48
|
-
// spreads a flat spec across the new view's snapshot and warns about the typos,
|
|
49
|
-
// while afterAttach — which only ever sees an already-built blob — warns about
|
|
50
|
-
// both a typo and a view prop that ended up inside it.
|
|
51
|
-
export function partitionLaunchKeys(spec,
|
|
52
|
-
// The view's declared property names. Callers with a live node read it off
|
|
53
|
-
// `getPropertyMembers(self).properties`; callers building a snapshot read it
|
|
54
|
-
// off the registered view type's `stateModel.properties` — see
|
|
55
|
-
// `linearGenomeViewPropKeys`.
|
|
56
|
-
viewPropKeys) {
|
|
57
|
-
const init = {};
|
|
58
|
-
const viewProps = {};
|
|
59
|
-
const unknown = {};
|
|
60
|
-
for (const [key, value] of Object.entries(spec)) {
|
|
61
|
-
const bucket = knownInitKeys.has(key)
|
|
62
|
-
? init
|
|
63
|
-
: (viewPropKeys.has(key) || LEGACY_VIEWPORT_PROPS.has(key)) &&
|
|
64
|
-
!RESERVED.has(key)
|
|
65
|
-
? viewProps
|
|
66
|
-
: unknown;
|
|
67
|
-
bucket[key] = value;
|
|
68
|
-
}
|
|
69
|
-
return { init, viewProps, unknown };
|
|
70
|
-
}
|
|
71
|
-
// The registered LinearGenomeView's declared property names, for a caller that
|
|
72
|
-
// has a PluginManager but no view yet (a launcher, or a synteny row being built).
|
|
73
|
-
// A caller holding a live node reads the same thing off
|
|
74
|
-
// `getPropertyMembers(self).properties` instead.
|
|
75
|
-
//
|
|
76
|
-
// `getViewType` THROWS on an unregistered name, and that is left alone: this is
|
|
77
|
-
// only ever called from code that is about to add a LinearGenomeView, so an
|
|
78
|
-
// absent view type is a broken plugin manager rather than a case to degrade
|
|
79
|
-
// through — and degrading would mean silently dropping every property the
|
|
80
|
-
// caller asked for, which is the failure this whole mechanism exists to end.
|
|
81
|
-
//
|
|
82
|
-
// Cached: the set is fixed for the life of the manager, and a launch that opens
|
|
83
|
-
// a stack of rows would otherwise rebuild it per row.
|
|
84
|
-
const propKeyCache = new WeakMap();
|
|
85
|
-
export function linearGenomeViewPropKeys(pluginManager) {
|
|
86
|
-
const cached = propKeyCache.get(pluginManager);
|
|
87
|
-
if (cached) {
|
|
88
|
-
return cached;
|
|
89
|
-
}
|
|
90
|
-
const { stateModel } = pluginManager.getViewType('LinearGenomeView');
|
|
91
|
-
const keys = new Set(Object.keys(stateModel.properties));
|
|
92
|
-
propKeyCache.set(pluginManager, keys);
|
|
93
|
-
return keys;
|
|
94
|
-
}
|
|
95
|
-
// Report the `unknown` bucket. Both callers say the same thing about the same
|
|
96
|
-
// mistake and differ only in which surface they name, so the wording lives next
|
|
97
|
-
// to the partition that produces the bucket rather than in two hand-written
|
|
98
|
-
// copies that drift.
|
|
99
|
-
export function warnUnknownLaunchKeys(surface, unknown) {
|
|
100
|
-
const keys = Object.keys(unknown);
|
|
101
|
-
if (keys.length) {
|
|
102
|
-
console.warn(`${surface} ignored unknown key(s): ${keys.join(', ')}`);
|
|
103
|
-
}
|
|
104
|
-
}
|