@jbrowse/plugin-alignments 4.0.4 → 4.1.1
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/CramAdapter/CramSlightlyLazyFeature.d.ts +1 -1
- package/esm/LinearPileupDisplay/SharedLinearPileupDisplayMixin.js +2 -2
- package/esm/LinearPileupDisplay/components/GroupByDialog.js +127 -93
- package/esm/LinearReadArcsDisplay/model.d.ts +5 -0
- package/esm/LinearReadCloudDisplay/components/LinearReadCloudReactComponent.js +6 -7
- package/esm/LinearReadCloudDisplay/model.d.ts +5 -2
- package/esm/LinearReadCloudDisplay/model.js +4 -11
- package/esm/LinearReadCloudDisplay/renderSvg.js +4 -5
- package/esm/LinearSNPCoverageDisplay/model.js +2 -2
- package/esm/RenderLinearReadCloudDisplayRPC/RenderLinearReadCloudDisplay.d.ts +0 -1
- package/esm/RenderLinearReadCloudDisplayRPC/drawFeatsCloud.d.ts +3 -4
- package/esm/RenderLinearReadCloudDisplayRPC/drawFeatsCloud.js +7 -20
- package/esm/RenderLinearReadCloudDisplayRPC/executeRenderLinearReadCloudDisplay.js +2 -2
- package/esm/shared/LinearReadDisplayBaseMixin.d.ts +5 -0
- package/esm/shared/createRPCRenderingSetup.d.ts +1 -0
- package/esm/shared/createRPCRenderingSetup.js +6 -1
- package/esm/shared/menuItems.js +3 -3
- package/package.json +10 -9
|
@@ -14,7 +14,7 @@ export default class CramSlightlyLazyFeature implements Feature {
|
|
|
14
14
|
get flags(): number;
|
|
15
15
|
get strand(): 1 | -1;
|
|
16
16
|
get qual(): string;
|
|
17
|
-
get qualRaw():
|
|
17
|
+
get qualRaw(): Uint8Array<ArrayBufferLike> | null | undefined;
|
|
18
18
|
get refName(): string;
|
|
19
19
|
get pair_orientation(): string | null | undefined;
|
|
20
20
|
get template_length(): number | undefined;
|
|
@@ -5,7 +5,7 @@ import { SimpleFeature, getContainingTrack, getContainingView, getSession, isSes
|
|
|
5
5
|
import { getRpcSessionId } from '@jbrowse/core/util/tracks';
|
|
6
6
|
import { cast, isAlive, types } from '@jbrowse/mobx-state-tree';
|
|
7
7
|
import { BaseLinearDisplay } from '@jbrowse/plugin-linear-genome-view';
|
|
8
|
-
import
|
|
8
|
+
import ClearAllIcon from '@mui/icons-material/ClearAll';
|
|
9
9
|
import ContentCopyIcon from '@mui/icons-material/ContentCopy';
|
|
10
10
|
import MenuOpenIcon from '@mui/icons-material/MenuOpen';
|
|
11
11
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
|
@@ -459,7 +459,7 @@ export function SharedLinearPileupDisplayMixin(configSchema) {
|
|
|
459
459
|
},
|
|
460
460
|
{
|
|
461
461
|
label: 'Filter by...',
|
|
462
|
-
icon:
|
|
462
|
+
icon: ClearAllIcon,
|
|
463
463
|
onClick: () => {
|
|
464
464
|
getSession(self).queueDialog(handleClose => [
|
|
465
465
|
FilterByTagDialog,
|
|
@@ -1,27 +1,115 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import { Dialog, ErrorMessage, LoadingEllipses } from '@jbrowse/core/ui';
|
|
4
4
|
import { getContainingTrack, getContainingView, getSession, useDebounce, } from '@jbrowse/core/util';
|
|
5
|
-
import { getSnapshot } from '@jbrowse/mobx-state-tree';
|
|
5
|
+
import { getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree';
|
|
6
6
|
import { Button, DialogActions, DialogContent, MenuItem, TextField, Typography, } from '@mui/material';
|
|
7
7
|
import { observer } from 'mobx-react';
|
|
8
8
|
import { getUniqueTags } from "../../shared/getUniqueTags.js";
|
|
9
9
|
import { defaultFilterFlags, negFlags, posFlags } from "../../shared/util.js";
|
|
10
|
+
const TAG_REGEX = /^[A-Za-z][A-Za-z0-9]$/;
|
|
11
|
+
function TagResults({ tag, tagSet }) {
|
|
12
|
+
if (tagSet.length === 0) {
|
|
13
|
+
return (_jsxs(Typography, { color: "warning.main", children: ["No values found for tag ", tag, " in the current region"] }));
|
|
14
|
+
}
|
|
15
|
+
return (_jsxs("div", { children: [_jsxs("div", { children: ["Found unique ", tag, " values:"] }), _jsx("div", { children: tagSet.join(', ') })] }));
|
|
16
|
+
}
|
|
17
|
+
function createTrackId(baseId, suffix) {
|
|
18
|
+
return `${baseId}-${suffix}-${Date.now()}-sessionTrack`;
|
|
19
|
+
}
|
|
20
|
+
function createTagBasedTracks({ trackConf, tag, tagSet, session, view, }) {
|
|
21
|
+
const values = [...tagSet, undefined];
|
|
22
|
+
for (const tagValue of values) {
|
|
23
|
+
const trackId = createTrackId(trackConf.trackId, `${tag}:${tagValue}`);
|
|
24
|
+
session.addTrackConf({
|
|
25
|
+
...trackConf,
|
|
26
|
+
trackId,
|
|
27
|
+
name: `${trackConf.name} (${tag}:${tagValue})`,
|
|
28
|
+
displays: [
|
|
29
|
+
{
|
|
30
|
+
displayId: `${trackId}-LinearAlignmentsDisplay`,
|
|
31
|
+
type: 'LinearAlignmentsDisplay',
|
|
32
|
+
pileupDisplay: {
|
|
33
|
+
displayId: `${trackId}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
34
|
+
type: 'LinearPileupDisplay',
|
|
35
|
+
filterBy: {
|
|
36
|
+
...defaultFilterFlags,
|
|
37
|
+
tagFilter: {
|
|
38
|
+
tag,
|
|
39
|
+
value: tagValue,
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
});
|
|
46
|
+
view.showTrack(trackId);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function createStrandBasedTracks({ trackConf, session, view, }) {
|
|
50
|
+
const negTrackId = createTrackId(trackConf.trackId, 'strand:(-)');
|
|
51
|
+
const posTrackId = createTrackId(trackConf.trackId, 'strand:(+)');
|
|
52
|
+
session.addTrackConf({
|
|
53
|
+
...trackConf,
|
|
54
|
+
trackId: negTrackId,
|
|
55
|
+
name: `${trackConf.name} (-)`,
|
|
56
|
+
displays: [
|
|
57
|
+
{
|
|
58
|
+
displayId: `${negTrackId}-LinearAlignmentsDisplay`,
|
|
59
|
+
type: 'LinearAlignmentsDisplay',
|
|
60
|
+
pileupDisplay: {
|
|
61
|
+
displayId: `${negTrackId}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
62
|
+
type: 'LinearPileupDisplay',
|
|
63
|
+
filterBy: negFlags,
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
displayId: `${negTrackId}-LinearSNPCoverageDisplay`,
|
|
68
|
+
type: 'LinearSNPCoverageDisplay',
|
|
69
|
+
filterBy: negFlags,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
});
|
|
73
|
+
session.addTrackConf({
|
|
74
|
+
...trackConf,
|
|
75
|
+
trackId: posTrackId,
|
|
76
|
+
name: `${trackConf.name} (+)`,
|
|
77
|
+
displays: [
|
|
78
|
+
{
|
|
79
|
+
displayId: `${posTrackId}-LinearAlignmentsDisplay`,
|
|
80
|
+
type: 'LinearAlignmentsDisplay',
|
|
81
|
+
pileupDisplay: {
|
|
82
|
+
displayId: `${posTrackId}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
83
|
+
type: 'LinearPileupDisplay',
|
|
84
|
+
filterBy: posFlags,
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
displayId: `${posTrackId}-LinearSNPCoverageDisplay`,
|
|
89
|
+
type: 'LinearSNPCoverageDisplay',
|
|
90
|
+
filterBy: posFlags,
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
view.showTrack(negTrackId);
|
|
95
|
+
view.showTrack(posTrackId);
|
|
96
|
+
}
|
|
10
97
|
const GroupByTagDialog = observer(function GroupByTagDialog(props) {
|
|
11
98
|
const { model, handleClose } = props;
|
|
12
99
|
const [tag, setGroupByTag] = useState('');
|
|
13
100
|
const [tagSet, setGroupByTagSet] = useState();
|
|
14
101
|
const [loading, setLoading] = useState(false);
|
|
15
102
|
const [error, setError] = useState();
|
|
16
|
-
const validTag =
|
|
103
|
+
const validTag = TAG_REGEX.exec(tag);
|
|
17
104
|
const isInvalid = tag.length === 2 && !validTag;
|
|
18
105
|
const debouncedTag = useDebounce(tag, 1000);
|
|
19
106
|
const [type, setType] = useState('');
|
|
20
107
|
useEffect(() => {
|
|
21
108
|
;
|
|
22
109
|
(async () => {
|
|
23
|
-
|
|
24
|
-
|
|
110
|
+
const isValidTag = TAG_REGEX.test(debouncedTag);
|
|
111
|
+
if (type === 'tag' && isValidTag) {
|
|
112
|
+
try {
|
|
25
113
|
setError(undefined);
|
|
26
114
|
setLoading(true);
|
|
27
115
|
const vals = await getUniqueTags({
|
|
@@ -32,16 +120,23 @@ const GroupByTagDialog = observer(function GroupByTagDialog(props) {
|
|
|
32
120
|
});
|
|
33
121
|
setGroupByTagSet(vals);
|
|
34
122
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
123
|
+
catch (e) {
|
|
124
|
+
console.error(e);
|
|
125
|
+
setError(e);
|
|
126
|
+
}
|
|
127
|
+
finally {
|
|
128
|
+
setLoading(false);
|
|
129
|
+
}
|
|
42
130
|
}
|
|
43
131
|
})();
|
|
44
|
-
}, [model,
|
|
132
|
+
}, [model, type, debouncedTag]);
|
|
133
|
+
useEffect(() => {
|
|
134
|
+
if (type !== 'tag') {
|
|
135
|
+
setGroupByTagSet(undefined);
|
|
136
|
+
setError(undefined);
|
|
137
|
+
setLoading(false);
|
|
138
|
+
}
|
|
139
|
+
}, [type]);
|
|
45
140
|
return (_jsxs(Dialog, { open: true, onClose: handleClose, title: "Group by", children: [_jsxs(DialogContent, { children: [_jsx(Typography, { children: "NOTE: this will create new session tracks with the \"filter by\" set to the values chosen here rather than affecting the current track state" }), _jsxs(TextField, { fullWidth: true, value: type, onChange: event => {
|
|
46
141
|
setType(event.target.value);
|
|
47
142
|
}, label: "Group by...", select: true, children: [_jsx(MenuItem, { value: "strand", children: "Strand" }), _jsx(MenuItem, { value: "tag", children: "Tag" })] }), type === 'tag' ? (_jsxs(_Fragment, { children: [_jsx(Typography, { color: "textSecondary", children: "Examples: HP for haplotype, RG for read group, etc." }), _jsx(TextField, { value: tag, onChange: event => {
|
|
@@ -51,93 +146,32 @@ const GroupByTagDialog = observer(function GroupByTagDialog(props) {
|
|
|
51
146
|
maxLength: 2,
|
|
52
147
|
'data-testid': 'group-tag-name-input',
|
|
53
148
|
},
|
|
54
|
-
} }), error ? (_jsx(ErrorMessage, { error: error })) : loading ? (_jsx(LoadingEllipses, { message: "Loading unique tags" })) : tagSet ? (
|
|
149
|
+
} }), error ? (_jsx(ErrorMessage, { error: error })) : loading ? (_jsx(LoadingEllipses, { message: "Loading unique tags" })) : tagSet ? (_jsx(TagResults, { tag: tag, tagSet: tagSet })) : null] })) : null] }), _jsxs(DialogActions, { children: [_jsx(Button, { variant: "contained", color: "primary", type: "submit", disabled: !type ||
|
|
150
|
+
loading ||
|
|
151
|
+
(type === 'tag' && (!tagSet || tagSet.length === 0)), autoFocus: true, onClick: () => {
|
|
55
152
|
const track = getContainingTrack(model);
|
|
56
|
-
const trackConf =
|
|
153
|
+
const trackConf = isStateTreeNode(track.configuration)
|
|
154
|
+
? structuredClone(getSnapshot(track.configuration))
|
|
155
|
+
: track.configuration;
|
|
57
156
|
const session = getSession(model);
|
|
58
157
|
const view = getContainingView(model);
|
|
59
|
-
if (type === 'tag') {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
name: `${trackConf.name} (${tag}:${tagValue})`,
|
|
68
|
-
displays: [
|
|
69
|
-
{
|
|
70
|
-
displayId: `${t1}-LinearAlignmentsDisplay`,
|
|
71
|
-
type: 'LinearAlignmentsDisplay',
|
|
72
|
-
pileupDisplay: {
|
|
73
|
-
displayId: `${t1}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
74
|
-
type: 'LinearPileupDisplay',
|
|
75
|
-
filterBy: {
|
|
76
|
-
...defaultFilterFlags,
|
|
77
|
-
tagFilter: {
|
|
78
|
-
tag,
|
|
79
|
-
value: tagValue,
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
],
|
|
85
|
-
});
|
|
86
|
-
view.showTrack(t1);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
158
|
+
if (type === 'tag' && tagSet) {
|
|
159
|
+
createTagBasedTracks({
|
|
160
|
+
trackConf,
|
|
161
|
+
tag,
|
|
162
|
+
tagSet,
|
|
163
|
+
session,
|
|
164
|
+
view,
|
|
165
|
+
});
|
|
89
166
|
}
|
|
90
167
|
else if (type === 'strand') {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
trackId: t1,
|
|
96
|
-
name: `${trackConf.name} (-)`,
|
|
97
|
-
displays: [
|
|
98
|
-
{
|
|
99
|
-
displayId: `${t1}-LinearAlignmentsDisplay`,
|
|
100
|
-
type: 'LinearAlignmentsDisplay',
|
|
101
|
-
pileupDisplay: {
|
|
102
|
-
displayId: `${t1}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
103
|
-
type: 'LinearPileupDisplay',
|
|
104
|
-
filterBy: negFlags,
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
{
|
|
108
|
-
displayId: `${t1}-LinearSNPCoverageDisplay`,
|
|
109
|
-
type: 'LinearSNPCoverageDisplay',
|
|
110
|
-
filterBy: negFlags,
|
|
111
|
-
},
|
|
112
|
-
],
|
|
168
|
+
createStrandBasedTracks({
|
|
169
|
+
trackConf,
|
|
170
|
+
session,
|
|
171
|
+
view,
|
|
113
172
|
});
|
|
114
|
-
session.addTrackConf({
|
|
115
|
-
...trackConf,
|
|
116
|
-
trackId: t2,
|
|
117
|
-
name: `${trackConf.name} (+)`,
|
|
118
|
-
displays: [
|
|
119
|
-
{
|
|
120
|
-
displayId: `${t2}-LinearAlignmentsDisplay`,
|
|
121
|
-
type: 'LinearAlignmentsDisplay',
|
|
122
|
-
pileupDisplay: {
|
|
123
|
-
displayId: `${t2}-LinearAlignmentsDisplay-LinearPileupDisplay`,
|
|
124
|
-
type: 'LinearPileupDisplay',
|
|
125
|
-
filterBy: posFlags,
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
displayId: `${t2}-LinearSNPCoverageDisplay`,
|
|
130
|
-
type: 'LinearSNPCoverageDisplay',
|
|
131
|
-
filterBy: posFlags,
|
|
132
|
-
},
|
|
133
|
-
],
|
|
134
|
-
});
|
|
135
|
-
view.showTrack(t1);
|
|
136
|
-
view.showTrack(t2);
|
|
137
173
|
}
|
|
138
174
|
handleClose();
|
|
139
|
-
}, children: "Submit" }), _jsx(Button, { variant: "contained", color: "secondary", onClick:
|
|
140
|
-
handleClose();
|
|
141
|
-
}, children: "Cancel" })] })] }));
|
|
175
|
+
}, children: "Submit" }), _jsx(Button, { variant: "contained", color: "secondary", onClick: handleClose, children: "Cancel" })] })] }));
|
|
142
176
|
});
|
|
143
177
|
export default GroupByTagDialog;
|
|
@@ -233,19 +233,24 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
233
233
|
} & {
|
|
234
234
|
loading: boolean;
|
|
235
235
|
lastDrawnOffsetPx: number | undefined;
|
|
236
|
+
lastDrawnBpPerPx: number | undefined;
|
|
236
237
|
ref: HTMLCanvasElement | null;
|
|
237
238
|
renderingImageData: ImageBitmap | undefined;
|
|
238
239
|
renderingStopToken: import("@jbrowse/core/util").StopToken | undefined;
|
|
239
240
|
statusMessage: string | undefined;
|
|
241
|
+
canvasDrawn: boolean;
|
|
240
242
|
} & {
|
|
241
243
|
readonly drawn: boolean;
|
|
244
|
+
readonly fullyDrawn: boolean;
|
|
242
245
|
} & {
|
|
243
246
|
setLastDrawnOffsetPx(n: number): void;
|
|
247
|
+
setLastDrawnBpPerPx(n: number): void;
|
|
244
248
|
setLoading(f: boolean): void;
|
|
245
249
|
setRef(ref: HTMLCanvasElement | null): void;
|
|
246
250
|
setRenderingImageData(imageData: ImageBitmap | undefined): void;
|
|
247
251
|
setRenderingStopToken(token?: import("@jbrowse/core/util").StopToken): void;
|
|
248
252
|
setStatusMessage(msg?: string): void;
|
|
253
|
+
setCanvasDrawn(drawn: boolean): void;
|
|
249
254
|
} & {
|
|
250
255
|
beforeDestroy(): void;
|
|
251
256
|
} & {
|
|
@@ -236,17 +236,16 @@ const Cloud = observer(function Cloud({ model, }) {
|
|
|
236
236
|
width,
|
|
237
237
|
height,
|
|
238
238
|
cursor: hasHover ? 'pointer' : undefined,
|
|
239
|
-
}, onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, onClick: onClick, children: [_jsx(CloudCanvases, { model: model, width: width, height: height }), _jsx(FeatureHighlights, { selectedFeatureBounds: selectedFeatureBounds, hoveredFeature: hoveredFeature }),
|
|
239
|
+
}, onMouseMove: onMouseMove, onMouseLeave: onMouseLeave, onClick: onClick, children: [_jsx(CloudCanvases, { model: model, width: width, height: height }), _jsx(FeatureHighlights, { selectedFeatureBounds: selectedFeatureBounds, hoveredFeature: hoveredFeature }), hoveredMismatchData && mousePosition ? (_jsx(MismatchTooltip, { mismatchData: hoveredMismatchData, mousePosition: mousePosition })) : hoveredFeatureData && mousePosition ? (_jsx(FeatureTooltip, { hoveredFeatureData: hoveredFeatureData, hasSupplementary: hoveredHasSupplementary, mousePosition: mousePosition })) : null] }));
|
|
240
|
+
});
|
|
241
|
+
const LinearReadCloudReactComponent = observer(function LinearReadCloudReactComponent({ model, }) {
|
|
242
|
+
return (_jsxs("div", { children: [_jsx(BaseDisplayComponent, { model: model, children: _jsx(Cloud, { model: model }) }), model.drawCloud && model.cloudTicks ? (_jsx("svg", { style: {
|
|
240
243
|
position: 'absolute',
|
|
241
244
|
top: 0,
|
|
242
245
|
left: 50,
|
|
243
246
|
pointerEvents: 'none',
|
|
244
247
|
height: model.cloudTicks.height,
|
|
245
|
-
width:
|
|
246
|
-
|
|
247
|
-
}, children: _jsx("g", { transform: "translate(55, 0)", children: _jsx(CloudYScaleBar, { model: model, orientation: "left" }) }) })) : null, hoveredMismatchData && mousePosition ? (_jsx(MismatchTooltip, { mismatchData: hoveredMismatchData, mousePosition: mousePosition })) : hoveredFeatureData && mousePosition ? (_jsx(FeatureTooltip, { hoveredFeatureData: hoveredFeatureData, hasSupplementary: hoveredHasSupplementary, mousePosition: mousePosition })) : null] }));
|
|
248
|
-
});
|
|
249
|
-
const LinearReadCloudReactComponent = observer(function LinearReadCloudReactComponent({ model, }) {
|
|
250
|
-
return (_jsx(BaseDisplayComponent, { model: model, children: _jsx(Cloud, { model: model }) }));
|
|
248
|
+
width: 50,
|
|
249
|
+
}, children: _jsx("g", { transform: "translate(45, 0)", children: _jsx(CloudYScaleBar, { model: model, orientation: "left" }) }) })) : null] }));
|
|
251
250
|
});
|
|
252
251
|
export default LinearReadCloudReactComponent;
|
|
@@ -242,19 +242,24 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
242
242
|
} & {
|
|
243
243
|
loading: boolean;
|
|
244
244
|
lastDrawnOffsetPx: number | undefined;
|
|
245
|
+
lastDrawnBpPerPx: number | undefined;
|
|
245
246
|
ref: HTMLCanvasElement | null;
|
|
246
247
|
renderingImageData: ImageBitmap | undefined;
|
|
247
248
|
renderingStopToken: import("@jbrowse/core/util").StopToken | undefined;
|
|
248
249
|
statusMessage: string | undefined;
|
|
250
|
+
canvasDrawn: boolean;
|
|
249
251
|
} & {
|
|
250
252
|
readonly drawn: boolean;
|
|
253
|
+
readonly fullyDrawn: boolean;
|
|
251
254
|
} & {
|
|
252
255
|
setLastDrawnOffsetPx(n: number): void;
|
|
256
|
+
setLastDrawnBpPerPx(n: number): void;
|
|
253
257
|
setLoading(f: boolean): void;
|
|
254
258
|
setRef(ref: HTMLCanvasElement | null): void;
|
|
255
259
|
setRenderingImageData(imageData: ImageBitmap | undefined): void;
|
|
256
260
|
setRenderingStopToken(token?: import("@jbrowse/core/util").StopToken): void;
|
|
257
261
|
setStatusMessage(msg?: string): void;
|
|
262
|
+
setCanvasDrawn(drawn: boolean): void;
|
|
258
263
|
} & {
|
|
259
264
|
beforeDestroy(): void;
|
|
260
265
|
} & {
|
|
@@ -311,8 +316,6 @@ declare function stateModelFactory(configSchema: AnyConfigurationSchemaType): im
|
|
|
311
316
|
readonly hideLargeIndels: any;
|
|
312
317
|
} & {
|
|
313
318
|
readonly modificationThreshold: any;
|
|
314
|
-
readonly cloudDomain: [number, number] | undefined;
|
|
315
|
-
} & {
|
|
316
319
|
readonly cloudTicks: import("../RenderLinearReadCloudDisplayRPC/drawFeatsCloud.ts").CloudTicks | undefined;
|
|
317
320
|
} & {
|
|
318
321
|
setNoSpacing(flag?: boolean): void;
|
|
@@ -68,19 +68,13 @@ function stateModelFactory(configSchema) {
|
|
|
68
68
|
get modificationThreshold() {
|
|
69
69
|
return self.colorBy?.modifications?.threshold ?? 10;
|
|
70
70
|
},
|
|
71
|
-
get cloudDomain() {
|
|
72
|
-
if (self.cloudMaxDistance === undefined) {
|
|
73
|
-
return undefined;
|
|
74
|
-
}
|
|
75
|
-
return [1, self.cloudMaxDistance];
|
|
76
|
-
},
|
|
77
|
-
}))
|
|
78
|
-
.views(self => ({
|
|
79
71
|
get cloudTicks() {
|
|
80
|
-
if (!self.drawCloud ||
|
|
72
|
+
if (!self.drawCloud ||
|
|
73
|
+
self.cloudMaxDistance === undefined ||
|
|
74
|
+
!self.showYScalebar) {
|
|
81
75
|
return undefined;
|
|
82
76
|
}
|
|
83
|
-
return calculateCloudTicks(self.
|
|
77
|
+
return calculateCloudTicks(self.cloudMaxDistance, self.height);
|
|
84
78
|
},
|
|
85
79
|
}))
|
|
86
80
|
.actions(self => ({
|
|
@@ -166,7 +160,6 @@ function stateModelFactory(configSchema) {
|
|
|
166
160
|
hideMismatches: self.hideMismatches,
|
|
167
161
|
hideLargeIndels: self.hideLargeIndels,
|
|
168
162
|
showOutline: self.showOutline,
|
|
169
|
-
cloudDomain: self.cloudDomain,
|
|
170
163
|
visibleModifications: Object.fromEntries(self.visibleModifications.toJSON()),
|
|
171
164
|
};
|
|
172
165
|
},
|
|
@@ -37,11 +37,10 @@ export async function renderSvg(self, opts) {
|
|
|
37
37
|
const visibleWidth = view.width;
|
|
38
38
|
const clipId = `clip-${self.id}-svg`;
|
|
39
39
|
const legendItems = self.showLegend ? self.legendItems() : [];
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
? calculateCloudTicks(cloudDomain, height)
|
|
40
|
+
const cloudTicks = rendering.cloudMaxDistance !== undefined &&
|
|
41
|
+
self.drawCloud &&
|
|
42
|
+
self.showYScalebar
|
|
43
|
+
? calculateCloudTicks(rendering.cloudMaxDistance, height)
|
|
45
44
|
: null;
|
|
46
45
|
return (_jsxs(_Fragment, { children: [_jsx("defs", { children: _jsx("clipPath", { id: clipId, children: _jsx("rect", { x: 0, y: 0, width: visibleWidth, height: height }) }) }), _jsx("g", { clipPath: `url(#${clipId})`, children: _jsx("g", { transform: `translate(${Math.max(0, -view.offsetPx)} 0)`, children: _jsx(ReactRendering, { rendering: finalRendering }) }) }), cloudTicks ? (_jsx("g", { transform: `translate(${Math.max(-view.offsetPx, 0)})`, children: _jsx(CloudYScaleBar, { model: { cloudTicks }, orientation: "left" }) })) : null, legendItems.length > 0 ? (_jsx(SVGLegend, { items: legendItems, width: visibleWidth, legendAreaWidth: opts.legendWidth })) : null] }));
|
|
47
46
|
}
|
|
@@ -4,7 +4,7 @@ import SerializableFilterChain from '@jbrowse/core/pluggableElementTypes/rendere
|
|
|
4
4
|
import { getContainingView, getSession } from '@jbrowse/core/util';
|
|
5
5
|
import { cast, getSnapshot, isAlive, types } from '@jbrowse/mobx-state-tree';
|
|
6
6
|
import { linearWiggleDisplayModelFactory } from '@jbrowse/plugin-wiggle';
|
|
7
|
-
import
|
|
7
|
+
import ClearAllIcon from '@mui/icons-material/ClearAll';
|
|
8
8
|
import VisibilityIcon from '@mui/icons-material/Visibility';
|
|
9
9
|
import { SharedModificationsMixin } from "../shared/SharedModificationsMixin.js";
|
|
10
10
|
import { getUniqueModifications } from "../shared/getUniqueModifications.js";
|
|
@@ -268,7 +268,7 @@ function stateModelFactory(pluginManager, configSchema) {
|
|
|
268
268
|
},
|
|
269
269
|
{
|
|
270
270
|
label: 'Filter arcs by score...',
|
|
271
|
-
icon:
|
|
271
|
+
icon: ClearAllIcon,
|
|
272
272
|
onClick: () => {
|
|
273
273
|
getSession(self).queueDialog(handleClose => [
|
|
274
274
|
FilterArcsByScoreDialog,
|
|
@@ -20,7 +20,6 @@ export interface RenderLinearReadCloudDisplayArgs {
|
|
|
20
20
|
flipStrandLongReadChains: boolean;
|
|
21
21
|
trackMaxHeight?: number;
|
|
22
22
|
cloudModeHeight?: number;
|
|
23
|
-
cloudDomain?: [number, number];
|
|
24
23
|
highResolutionScaling?: number;
|
|
25
24
|
exportSVG?: {
|
|
26
25
|
rasterizeLayers?: boolean;
|
|
@@ -6,12 +6,11 @@ export interface CloudTicks {
|
|
|
6
6
|
y: number;
|
|
7
7
|
}[];
|
|
8
8
|
height: number;
|
|
9
|
-
minDistance: number;
|
|
10
9
|
maxDistance: number;
|
|
11
10
|
}
|
|
12
|
-
export declare function createCloudScale(
|
|
13
|
-
export declare function calculateCloudTicks(
|
|
14
|
-
export declare function calculateCloudYOffsetsUtil(computedChains: ComputedChain[], height: number
|
|
11
|
+
export declare function createCloudScale(maxDistance: number, height: number): import("d3-scale").ScaleLogarithmic<number, number, never>;
|
|
12
|
+
export declare function calculateCloudTicks(maxDistance: number, height: number): CloudTicks;
|
|
13
|
+
export declare function calculateCloudYOffsetsUtil(computedChains: ComputedChain[], height: number): {
|
|
15
14
|
chainYOffsets: Map<string, number>;
|
|
16
15
|
cloudMaxDistance: number;
|
|
17
16
|
};
|
|
@@ -1,37 +1,24 @@
|
|
|
1
1
|
import { scaleLog } from '@mui/x-charts-vendor/d3-scale';
|
|
2
2
|
export const CLOUD_HEIGHT_PADDING = 20;
|
|
3
3
|
const DEFAULT_MAX_DISTANCE = 1000;
|
|
4
|
-
export function createCloudScale(
|
|
4
|
+
export function createCloudScale(maxDistance, height) {
|
|
5
5
|
return scaleLog()
|
|
6
6
|
.base(2)
|
|
7
|
-
.domain([
|
|
7
|
+
.domain([1, Math.max(2, maxDistance)])
|
|
8
8
|
.range([0, height - CLOUD_HEIGHT_PADDING])
|
|
9
9
|
.clamp(true);
|
|
10
10
|
}
|
|
11
|
-
export function calculateCloudTicks(
|
|
12
|
-
const
|
|
13
|
-
const scale = createCloudScale(minDistance, maxDistance, height);
|
|
11
|
+
export function calculateCloudTicks(maxDistance, height) {
|
|
12
|
+
const scale = createCloudScale(maxDistance, height);
|
|
14
13
|
const tickValues = scale.ticks(6);
|
|
15
14
|
const ticks = tickValues.map(value => ({
|
|
16
15
|
value,
|
|
17
16
|
y: scale(value),
|
|
18
17
|
}));
|
|
19
|
-
return { ticks, height,
|
|
18
|
+
return { ticks, height, maxDistance };
|
|
20
19
|
}
|
|
21
|
-
export function calculateCloudYOffsetsUtil(computedChains, height
|
|
20
|
+
export function calculateCloudYOffsetsUtil(computedChains, height) {
|
|
22
21
|
const chainYOffsets = new Map();
|
|
23
|
-
if (cloudDomain) {
|
|
24
|
-
const [, maxDistance] = cloudDomain;
|
|
25
|
-
const scale = createCloudScale(1, maxDistance, height);
|
|
26
|
-
for (const { id, distance } of computedChains) {
|
|
27
|
-
const top = distance > 0 ? scale(distance) : 0;
|
|
28
|
-
chainYOffsets.set(id, top);
|
|
29
|
-
}
|
|
30
|
-
return {
|
|
31
|
-
chainYOffsets,
|
|
32
|
-
cloudMaxDistance: maxDistance,
|
|
33
|
-
};
|
|
34
|
-
}
|
|
35
22
|
let maxDistance = Number.MIN_VALUE;
|
|
36
23
|
for (const { distance } of computedChains) {
|
|
37
24
|
if (distance > 0) {
|
|
@@ -41,7 +28,7 @@ export function calculateCloudYOffsetsUtil(computedChains, height, cloudDomain)
|
|
|
41
28
|
if (maxDistance === Number.MIN_VALUE) {
|
|
42
29
|
maxDistance = DEFAULT_MAX_DISTANCE;
|
|
43
30
|
}
|
|
44
|
-
const scale = createCloudScale(
|
|
31
|
+
const scale = createCloudScale(maxDistance, height);
|
|
45
32
|
for (const { id, distance } of computedChains) {
|
|
46
33
|
const top = distance > 0 ? scale(distance) : 0;
|
|
47
34
|
chainYOffsets.set(id, top);
|
|
@@ -12,7 +12,7 @@ import { computeChainBounds, drawFeatsCore, filterChains, sortComputedChains, }
|
|
|
12
12
|
import { calculateStackYOffsetsUtil } from "./drawFeatsStack.js";
|
|
13
13
|
import { getInsertSizeStats } from "../shared/insertSizeStats.js";
|
|
14
14
|
export async function executeRenderLinearReadCloudDisplay({ pluginManager, args, }) {
|
|
15
|
-
const { sessionId, view: viewSnapshot, adapterConfig, sequenceAdapter, config, theme, featureHeight, noSpacing, drawCloud, colorBy, drawSingletons, drawProperPairs, flipStrandLongReadChains, trackMaxHeight, cloudModeHeight,
|
|
15
|
+
const { sessionId, view: viewSnapshot, adapterConfig, sequenceAdapter, config, theme, featureHeight, noSpacing, drawCloud, colorBy, drawSingletons, drawProperPairs, flipStrandLongReadChains, trackMaxHeight, cloudModeHeight, highResolutionScaling, exportSVG, statusCallback = () => { }, stopToken, visibleModifications, hideSmallIndels, hideMismatches, hideLargeIndels, showOutline, } = args;
|
|
16
16
|
const view = Base1DView.create(viewSnapshot);
|
|
17
17
|
if (viewSnapshot.width) {
|
|
18
18
|
view.setVolatileWidth(viewSnapshot.width);
|
|
@@ -125,7 +125,7 @@ export async function executeRenderLinearReadCloudDisplay({ pluginManager, args,
|
|
|
125
125
|
view: viewSnap,
|
|
126
126
|
calculateYOffsets: (chains) => {
|
|
127
127
|
return drawCloud
|
|
128
|
-
? calculateCloudYOffsetsUtil(chains, actualHeight
|
|
128
|
+
? calculateCloudYOffsetsUtil(chains, actualHeight)
|
|
129
129
|
: calculateStackYOffsetsUtil(chains, featureHeight, noSpacing, trackMaxHeight ?? 1200);
|
|
130
130
|
},
|
|
131
131
|
});
|
|
@@ -5,19 +5,24 @@ export declare function LinearReadDisplayBaseMixin(): import("@jbrowse/mobx-stat
|
|
|
5
5
|
}, {
|
|
6
6
|
loading: boolean;
|
|
7
7
|
lastDrawnOffsetPx: number | undefined;
|
|
8
|
+
lastDrawnBpPerPx: number | undefined;
|
|
8
9
|
ref: HTMLCanvasElement | null;
|
|
9
10
|
renderingImageData: ImageBitmap | undefined;
|
|
10
11
|
renderingStopToken: import("@jbrowse/core/util").StopToken | undefined;
|
|
11
12
|
statusMessage: string | undefined;
|
|
13
|
+
canvasDrawn: boolean;
|
|
12
14
|
} & {
|
|
13
15
|
readonly drawn: boolean;
|
|
16
|
+
readonly fullyDrawn: boolean;
|
|
14
17
|
} & {
|
|
15
18
|
setLastDrawnOffsetPx(n: number): void;
|
|
19
|
+
setLastDrawnBpPerPx(n: number): void;
|
|
16
20
|
setLoading(f: boolean): void;
|
|
17
21
|
setRef(ref: HTMLCanvasElement | null): void;
|
|
18
22
|
setRenderingImageData(imageData: ImageBitmap | undefined): void;
|
|
19
23
|
setRenderingStopToken(token?: import("@jbrowse/core/util").StopToken): void;
|
|
20
24
|
setStatusMessage(msg?: string): void;
|
|
25
|
+
setCanvasDrawn(drawn: boolean): void;
|
|
21
26
|
} & {
|
|
22
27
|
beforeDestroy(): void;
|
|
23
28
|
} & {
|
|
@@ -20,6 +20,7 @@ export interface RPCRenderableModel {
|
|
|
20
20
|
ref: HTMLCanvasElement | null;
|
|
21
21
|
renderingImageData?: ImageBitmap;
|
|
22
22
|
setStatusMessage?: (msg: string) => void;
|
|
23
|
+
setCanvasDrawn?: (drawn: boolean) => void;
|
|
23
24
|
}
|
|
24
25
|
export interface RPCRenderSetupParams<T extends RPCRenderableModel, R = Record<string, unknown>> {
|
|
25
26
|
self: T;
|
|
@@ -33,6 +33,7 @@ export function createRPCRenderFunction({ self, rpcMethodName, getRPCParams, onR
|
|
|
33
33
|
const stopToken = createStopToken();
|
|
34
34
|
self.setRenderingStopToken(stopToken);
|
|
35
35
|
self.setLoading(true);
|
|
36
|
+
self.setCanvasDrawn?.(false);
|
|
36
37
|
const viewSnapshot = {
|
|
37
38
|
displayedRegions: structuredClone(view.displayedRegions),
|
|
38
39
|
bpPerPx: view.bpPerPx,
|
|
@@ -69,6 +70,7 @@ export function createRPCRenderFunction({ self, rpcMethodName, getRPCParams, onR
|
|
|
69
70
|
}
|
|
70
71
|
catch (error) {
|
|
71
72
|
if (!isAbortException(error)) {
|
|
73
|
+
console.error(error);
|
|
72
74
|
self.setError(error);
|
|
73
75
|
}
|
|
74
76
|
}
|
|
@@ -80,7 +82,10 @@ export function createRPCRenderFunction({ self, rpcMethodName, getRPCParams, onR
|
|
|
80
82
|
}
|
|
81
83
|
export function setupCanvasRenderingAutorun(self) {
|
|
82
84
|
createAutorun(self, async () => {
|
|
83
|
-
drawCanvasImageData(self.ref, self.renderingImageData);
|
|
85
|
+
const success = drawCanvasImageData(self.ref, self.renderingImageData);
|
|
86
|
+
if (isAlive(self)) {
|
|
87
|
+
self.setCanvasDrawn?.(success);
|
|
88
|
+
}
|
|
84
89
|
}, {
|
|
85
90
|
name: 'CanvasRenderAutorun',
|
|
86
91
|
});
|
package/esm/shared/menuItems.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { lazy } from 'react';
|
|
2
2
|
import { getSession } from '@jbrowse/core/util';
|
|
3
|
-
import
|
|
3
|
+
import ClearAllIcon from '@mui/icons-material/ClearAll';
|
|
4
4
|
import PaletteIcon from '@mui/icons-material/Palette';
|
|
5
5
|
import { modificationData } from "./modificationData.js";
|
|
6
6
|
const FilterByTagDialog = lazy(() => import("./components/FilterByTagDialog.js"));
|
|
@@ -150,7 +150,7 @@ export function getColorSchemeMenuItem(model) {
|
|
|
150
150
|
export function getFilterByMenuItem(model) {
|
|
151
151
|
return {
|
|
152
152
|
label: 'Filter by',
|
|
153
|
-
icon:
|
|
153
|
+
icon: ClearAllIcon,
|
|
154
154
|
onClick: () => {
|
|
155
155
|
getSession(model).queueDialog((handleClose) => [
|
|
156
156
|
FilterByTagDialog,
|
|
@@ -162,7 +162,7 @@ export function getFilterByMenuItem(model) {
|
|
|
162
162
|
export function getEditFiltersMenuItem(model) {
|
|
163
163
|
return {
|
|
164
164
|
label: 'Edit filters',
|
|
165
|
-
icon:
|
|
165
|
+
icon: ClearAllIcon,
|
|
166
166
|
type: 'subMenu',
|
|
167
167
|
subMenu: [
|
|
168
168
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jbrowse/plugin-alignments",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.1.1",
|
|
4
|
+
"type": "module",
|
|
4
5
|
"description": "JBrowse 2 alignments adapters, tracks, etc.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"jbrowse",
|
|
@@ -21,11 +22,11 @@
|
|
|
21
22
|
],
|
|
22
23
|
"dependencies": {
|
|
23
24
|
"@gmod/bam": "^7.1.15",
|
|
24
|
-
"@gmod/cram": "^
|
|
25
|
+
"@gmod/cram": "^8.0.0",
|
|
25
26
|
"@jbrowse/mobx-state-tree": "^5.5.0",
|
|
26
|
-
"@mui/icons-material": "^7.3.
|
|
27
|
-
"@mui/material": "^7.3.
|
|
28
|
-
"@mui/x-charts-vendor": "^8.
|
|
27
|
+
"@mui/icons-material": "^7.3.7",
|
|
28
|
+
"@mui/material": "^7.3.7",
|
|
29
|
+
"@mui/x-charts-vendor": "^8.26.0",
|
|
29
30
|
"canvas2svg": "^1.0.16",
|
|
30
31
|
"copy-to-clipboard": "^3.3.3",
|
|
31
32
|
"fast-deep-equal": "^3.1.3",
|
|
@@ -33,10 +34,10 @@
|
|
|
33
34
|
"mobx": "^6.15.0",
|
|
34
35
|
"mobx-react": "^9.2.1",
|
|
35
36
|
"rxjs": "^7.8.2",
|
|
36
|
-
"@jbrowse/core": "^4.
|
|
37
|
-
"@jbrowse/plugin-linear-genome-view": "^4.
|
|
38
|
-
"@jbrowse/plugin-wiggle": "^4.
|
|
39
|
-
"@jbrowse/sv-core": "^4.
|
|
37
|
+
"@jbrowse/core": "^4.1.1",
|
|
38
|
+
"@jbrowse/plugin-linear-genome-view": "^4.1.1",
|
|
39
|
+
"@jbrowse/plugin-wiggle": "^4.1.1",
|
|
40
|
+
"@jbrowse/sv-core": "^4.1.1"
|
|
40
41
|
},
|
|
41
42
|
"peerDependencies": {
|
|
42
43
|
"react": ">=18.0.0"
|