jbrowse-plugin-protein3d 0.4.13 → 0.5.0
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/dist/LaunchProteinView/components/FoldseekActionMenu.js +15 -14
- package/dist/LaunchProteinView/components/ProteinViewActions.js +27 -15
- package/dist/LaunchProteinView/components/UserProvidedStructure.js +1 -2
- package/dist/LaunchProteinView/hooks/useSafeLaunch.d.ts +9 -0
- package/dist/LaunchProteinView/hooks/useSafeLaunch.js +15 -0
- package/dist/LaunchProteinView/utils/launchViewUtils.d.ts +9 -11
- package/dist/LaunchProteinView/utils/launchViewUtils.js +6 -8
- package/dist/LaunchProteinView/utils/sideBySide.d.ts +5 -0
- package/dist/LaunchProteinView/utils/sideBySide.js +9 -0
- package/dist/LaunchProteinViewExtensionPoint/index.js +7 -4
- package/dist/ProteinView/applyLociInteractivity.d.ts +23 -17
- package/dist/ProteinView/applyLociInteractivity.js +33 -61
- package/dist/ProteinView/components/FeatureBar.d.ts +1 -1
- package/dist/ProteinView/components/FeatureBar.js +36 -34
- package/dist/ProteinView/components/FeatureTypeLabel.js +5 -9
- package/dist/ProteinView/components/ProteinFeatureTrack.js +7 -15
- package/dist/ProteinView/components/ProteinViewHeader.js +9 -1
- package/dist/ProteinView/components/ResidueValueTrack.js +26 -15
- package/dist/ProteinView/hooks/useProteinFeatureTrackData.d.ts +1 -0
- package/dist/ProteinView/hooks/useProteinFeatureTrackData.js +3 -2
- package/dist/ProteinView/model.d.ts +12 -0
- package/dist/ProteinView/structureModel.d.ts +14 -5
- package/dist/ProteinView/structureModel.js +69 -92
- package/dist/ProteinView/subscribeMolstarInteraction.d.ts +8 -0
- package/dist/ProteinView/subscribeMolstarInteraction.js +1 -1
- package/dist/ProteinView/util.d.ts +0 -5
- package/dist/ProteinView/util.js +0 -11
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js +15 -15
- package/dist/jbrowse-plugin-protein3d.umd.production.min.js.map +4 -4
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/src/LaunchProteinView/components/FoldseekActionMenu.tsx +22 -17
- package/src/LaunchProteinView/components/ProteinViewActions.tsx +32 -17
- package/src/LaunchProteinView/components/UserProvidedStructure.tsx +1 -6
- package/src/LaunchProteinView/hooks/useSafeLaunch.ts +17 -0
- package/src/LaunchProteinView/utils/launchViewUtils.ts +30 -29
- package/src/LaunchProteinView/utils/sideBySide.ts +14 -0
- package/src/LaunchProteinViewExtensionPoint/index.ts +8 -9
- package/src/ProteinView/applyLociInteractivity.ts +62 -114
- package/src/ProteinView/components/FeatureBar.tsx +40 -44
- package/src/ProteinView/components/FeatureTypeLabel.tsx +6 -11
- package/src/ProteinView/components/ProteinFeatureTrack.tsx +5 -17
- package/src/ProteinView/components/ProteinViewHeader.tsx +15 -0
- package/src/ProteinView/components/ResidueValueTrack.tsx +40 -23
- package/src/ProteinView/hooks/useProteinFeatureTrackData.ts +6 -2
- package/src/ProteinView/structureModel.ts +90 -108
- package/src/ProteinView/subscribeMolstarInteraction.ts +9 -1
- package/src/ProteinView/util.ts +0 -25
- package/src/version.ts +1 -1
- package/dist/ProteinView/highlightResidueRange.d.ts +0 -14
- package/dist/ProteinView/highlightResidueRange.js +0 -19
- package/src/ProteinView/highlightResidueRange.ts +0 -44
|
@@ -4,35 +4,27 @@ import { CHAR_WIDTH } from '../constants';
|
|
|
4
4
|
import FeatureBar from './FeatureBar';
|
|
5
5
|
import FeatureTypeLabel from './FeatureTypeLabel';
|
|
6
6
|
import HoverMarker from './HoverMarker';
|
|
7
|
-
function getVisibleTypes(featureTypes, hiddenFeatureTypes) {
|
|
8
|
-
return featureTypes.filter(type => !hiddenFeatureTypes.has(type));
|
|
9
|
-
}
|
|
10
7
|
const FeatureTypeTrackContent = observer(function FeatureTypeTrackContent({ features, model, sequenceLength, }) {
|
|
11
8
|
return (React.createElement("div", { style: {
|
|
12
9
|
position: 'relative',
|
|
13
10
|
height: model.trackHeight,
|
|
14
11
|
width: sequenceLength * CHAR_WIDTH,
|
|
15
12
|
marginBottom: model.trackGap,
|
|
16
|
-
} },
|
|
17
|
-
features.map(feature => (React.createElement(FeatureBar, { key: feature.uniqueId, feature: feature, model: model }))),
|
|
18
|
-
React.createElement(HoverMarker, { model: model })));
|
|
13
|
+
} }, features.map(feature => (React.createElement(FeatureBar, { key: feature.uniqueId, feature: feature, model: model })))));
|
|
19
14
|
});
|
|
20
15
|
export const ProteinFeatureTrackLabels = observer(function ProteinFeatureTrackLabels({ data, labelWidth, model, }) {
|
|
21
|
-
|
|
22
|
-
const visibleTypes = getVisibleTypes(data.featureTypes, hiddenFeatureTypes);
|
|
23
|
-
return (React.createElement(React.Fragment, null, visibleTypes.map(type => (React.createElement(FeatureTypeLabel, { key: type, type: type, labelWidth: labelWidth, model: model })))));
|
|
16
|
+
return (React.createElement(React.Fragment, null, data.visibleTypes.map(type => (React.createElement(FeatureTypeLabel, { key: type, type: type, labelWidth: labelWidth, model: model })))));
|
|
24
17
|
});
|
|
25
18
|
export const ProteinFeatureTrackContent = observer(function ProteinFeatureTrackContent({ data, model, }) {
|
|
26
|
-
|
|
27
|
-
const visibleTypes = getVisibleTypes(data.featureTypes, hiddenFeatureTypes);
|
|
28
|
-
return (React.createElement("div", { onMouseMove: (e) => {
|
|
19
|
+
return (React.createElement("div", { style: { position: 'relative' }, onMouseMove: (e) => {
|
|
29
20
|
const rect = e.currentTarget.getBoundingClientRect();
|
|
30
|
-
const
|
|
31
|
-
const alignmentPos = Math.floor(x / CHAR_WIDTH);
|
|
21
|
+
const alignmentPos = Math.floor((e.clientX - rect.left) / CHAR_WIDTH);
|
|
32
22
|
if (alignmentPos >= 0 && alignmentPos < data.sequenceLength) {
|
|
33
23
|
model.hoverAlignmentPosition(alignmentPos);
|
|
34
24
|
}
|
|
35
25
|
}, onMouseLeave: () => {
|
|
36
26
|
model.setHoveredPosition(undefined);
|
|
37
|
-
} },
|
|
27
|
+
} },
|
|
28
|
+
data.visibleTypes.map(type => (React.createElement(FeatureTypeTrackContent, { key: type, features: data.groupedFeatures[type], model: model, sequenceLength: data.sequenceLength }))),
|
|
29
|
+
React.createElement(HoverMarker, { model: model })));
|
|
38
30
|
});
|
|
@@ -64,6 +64,7 @@ function getDisplayToggles(model) {
|
|
|
64
64
|
}
|
|
65
65
|
const DisplaySettingsMenu = observer(function DisplaySettingsMenu({ model, }) {
|
|
66
66
|
const [anchorEl, setAnchorEl] = useState(null);
|
|
67
|
+
const hasHiddenTracks = model.structures.some(s => s.hiddenFeatureTypes.size > 0);
|
|
67
68
|
return (React.createElement(React.Fragment, null,
|
|
68
69
|
React.createElement(Tooltip, { title: "Display settings" },
|
|
69
70
|
React.createElement(IconButton, { size: "small", onClick: event => {
|
|
@@ -72,7 +73,14 @@ const DisplaySettingsMenu = observer(function DisplaySettingsMenu({ model, }) {
|
|
|
72
73
|
React.createElement(TuneIcon, { fontSize: "small" }))),
|
|
73
74
|
React.createElement(Menu, { anchorEl: anchorEl, open: Boolean(anchorEl), onClose: () => {
|
|
74
75
|
setAnchorEl(null);
|
|
75
|
-
} },
|
|
76
|
+
} },
|
|
77
|
+
getDisplayToggles(model).map(toggle => (React.createElement(ToggleMenuItem, { key: toggle.label, checked: toggle.checked, label: toggle.label, onToggle: toggle.onToggle }))),
|
|
78
|
+
hasHiddenTracks ? (React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
79
|
+
for (const structure of model.structures) {
|
|
80
|
+
structure.showAllFeatureTypes();
|
|
81
|
+
}
|
|
82
|
+
} },
|
|
83
|
+
React.createElement(ListItemText, { inset: true }, "Restore hidden feature tracks"))) : null)));
|
|
76
84
|
});
|
|
77
85
|
const ProteinViewHeader = observer(function ProteinViewHeader({ model, }) {
|
|
78
86
|
const { structures, showAlignment } = model;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
2
|
import { Tooltip } from '@mui/material';
|
|
3
3
|
import { observer } from 'mobx-react';
|
|
4
4
|
import { CHAR_WIDTH } from '../constants';
|
|
@@ -8,21 +8,32 @@ import { CHAR_WIDTH } from '../constants';
|
|
|
8
8
|
* tracks. Hovering drives the same structure hover as the feature tracks.
|
|
9
9
|
*/
|
|
10
10
|
const ResidueValueTrack = observer(function ResidueValueTrack({ cells, colorFor, formatValue, sequenceLength, model, }) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
}
|
|
22
|
-
}, onMouseLeave: () => {
|
|
23
|
-
model.setHoveredPosition(undefined);
|
|
24
|
-
} }, cells.map(cell => (React.createElement(Tooltip, { key: cell.col, title: formatValue(cell.value), followCursor: true },
|
|
11
|
+
const [hoveredCol, setHoveredCol] = useState(undefined);
|
|
12
|
+
const valueByCol = useMemo(() => {
|
|
13
|
+
const map = new Map();
|
|
14
|
+
for (const cell of cells) {
|
|
15
|
+
map.set(cell.col, cell.value);
|
|
16
|
+
}
|
|
17
|
+
return map;
|
|
18
|
+
}, [cells]);
|
|
19
|
+
const hoveredValue = hoveredCol === undefined ? undefined : valueByCol.get(hoveredCol);
|
|
20
|
+
return (React.createElement(Tooltip, { title: hoveredValue === undefined ? '' : formatValue(hoveredValue), followCursor: true },
|
|
25
21
|
React.createElement("div", { style: {
|
|
22
|
+
position: 'relative',
|
|
23
|
+
height: model.trackHeight,
|
|
24
|
+
width: sequenceLength * CHAR_WIDTH,
|
|
25
|
+
marginBottom: model.trackGap,
|
|
26
|
+
}, onMouseMove: (e) => {
|
|
27
|
+
const rect = e.currentTarget.getBoundingClientRect();
|
|
28
|
+
const alignmentPos = Math.floor((e.clientX - rect.left) / CHAR_WIDTH);
|
|
29
|
+
setHoveredCol(alignmentPos);
|
|
30
|
+
if (alignmentPos >= 0 && alignmentPos < sequenceLength) {
|
|
31
|
+
model.hoverAlignmentPosition(alignmentPos);
|
|
32
|
+
}
|
|
33
|
+
}, onMouseLeave: () => {
|
|
34
|
+
setHoveredCol(undefined);
|
|
35
|
+
model.setHoveredPosition(undefined);
|
|
36
|
+
} }, cells.map(cell => (React.createElement("div", { key: cell.col, style: {
|
|
26
37
|
position: 'absolute',
|
|
27
38
|
left: cell.col * CHAR_WIDTH,
|
|
28
39
|
top: 0,
|
|
@@ -3,6 +3,7 @@ import type { JBrowsePluginProteinStructureModel } from '../model';
|
|
|
3
3
|
type FeaturesByType = Record<string, UniProtFeature[]>;
|
|
4
4
|
export interface FeatureTrackData {
|
|
5
5
|
featureTypes: string[];
|
|
6
|
+
visibleTypes: string[];
|
|
6
7
|
groupedFeatures: FeaturesByType;
|
|
7
8
|
sequenceLength: number;
|
|
8
9
|
}
|
|
@@ -9,15 +9,16 @@ function groupFeaturesByType(features) {
|
|
|
9
9
|
}
|
|
10
10
|
export default function useProteinFeatureTrackData(model, uniprotId) {
|
|
11
11
|
const { features, isLoading, error } = useUniProtFeatures(uniprotId);
|
|
12
|
-
const { pairwiseAlignment } = model;
|
|
12
|
+
const { pairwiseAlignment, hiddenFeatureTypes } = model;
|
|
13
13
|
if (!uniprotId || isLoading || error || !features || !pairwiseAlignment) {
|
|
14
14
|
return { data: undefined, isLoading, error };
|
|
15
15
|
}
|
|
16
16
|
const sequenceLength = pairwiseAlignment.alns[0].seq.length;
|
|
17
17
|
const groupedFeatures = groupFeaturesByType(features);
|
|
18
18
|
const featureTypes = Object.keys(groupedFeatures);
|
|
19
|
+
const visibleTypes = featureTypes.filter(type => !hiddenFeatureTypes.has(type));
|
|
19
20
|
return {
|
|
20
|
-
data: { featureTypes, groupedFeatures, sequenceLength },
|
|
21
|
+
data: { featureTypes, visibleTypes, groupedFeatures, sequenceLength },
|
|
21
22
|
isLoading: false,
|
|
22
23
|
error: undefined,
|
|
23
24
|
};
|
|
@@ -603,6 +603,10 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
603
603
|
start: number;
|
|
604
604
|
end: number;
|
|
605
605
|
} | undefined;
|
|
606
|
+
readonly hoverHighlightRange: {
|
|
607
|
+
start: number;
|
|
608
|
+
end: number;
|
|
609
|
+
} | undefined;
|
|
606
610
|
readonly clickAlignmentRange: {
|
|
607
611
|
start: number;
|
|
608
612
|
end: number;
|
|
@@ -1337,6 +1341,10 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
1337
1341
|
start: number;
|
|
1338
1342
|
end: number;
|
|
1339
1343
|
} | undefined;
|
|
1344
|
+
readonly hoverHighlightRange: {
|
|
1345
|
+
start: number;
|
|
1346
|
+
end: number;
|
|
1347
|
+
} | undefined;
|
|
1340
1348
|
readonly clickAlignmentRange: {
|
|
1341
1349
|
start: number;
|
|
1342
1350
|
end: number;
|
|
@@ -1950,6 +1958,10 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
1950
1958
|
start: number;
|
|
1951
1959
|
end: number;
|
|
1952
1960
|
} | undefined;
|
|
1961
|
+
readonly hoverHighlightRange: {
|
|
1962
|
+
start: number;
|
|
1963
|
+
end: number;
|
|
1964
|
+
} | undefined;
|
|
1953
1965
|
readonly clickAlignmentRange: {
|
|
1954
1966
|
start: number;
|
|
1955
1967
|
end: number;
|
|
@@ -262,6 +262,17 @@ declare const Structure: import("@jbrowse/mobx-state-tree").IModelType<{
|
|
|
262
262
|
start: number;
|
|
263
263
|
end: number;
|
|
264
264
|
} | undefined;
|
|
265
|
+
/**
|
|
266
|
+
* #getter
|
|
267
|
+
* The current hover as a 0-based half-open structure range. A feature-range
|
|
268
|
+
* hover (hoverStructureRange) takes priority over a single-residue hover
|
|
269
|
+
* (structureSeqHoverPos). Drives both the molstar 3D highlight and the
|
|
270
|
+
* genome highlight.
|
|
271
|
+
*/
|
|
272
|
+
readonly hoverHighlightRange: {
|
|
273
|
+
start: number;
|
|
274
|
+
end: number;
|
|
275
|
+
} | undefined;
|
|
265
276
|
/**
|
|
266
277
|
* #getter
|
|
267
278
|
* Persistent click selection in alignment coordinates, derived from
|
|
@@ -282,11 +293,9 @@ declare const Structure: import("@jbrowse/mobx-state-tree").IModelType<{
|
|
|
282
293
|
} | undefined): IRegion[];
|
|
283
294
|
/**
|
|
284
295
|
* #getter
|
|
285
|
-
* Genome regions to highlight in the LGV
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
* originated from the genome view itself, so hovering the LGV doesn't
|
|
289
|
-
* echo a codon-width highlight back onto that same view.
|
|
296
|
+
* Genome regions to highlight in the LGV from the current hover. Excludes
|
|
297
|
+
* hovers that originated from the genome view itself, so hovering the LGV
|
|
298
|
+
* doesn't echo a codon-width highlight back onto that same view.
|
|
290
299
|
*/
|
|
291
300
|
readonly hoverGenomeHighlights: IRegion[];
|
|
292
301
|
/**
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { SimpleFeature, getSession } from '@jbrowse/core/util';
|
|
2
2
|
import { addDisposer, getParent, types, } from '@jbrowse/mobx-state-tree';
|
|
3
3
|
import { autorun } from 'mobx';
|
|
4
|
-
import {
|
|
4
|
+
import { setMolstarLoci } from './applyLociInteractivity';
|
|
5
5
|
import { COMPACT_TRACK_GAP, COMPACT_TRACK_HEIGHT, NORMAL_TRACK_GAP, NORMAL_TRACK_HEIGHT, } from './constants';
|
|
6
6
|
import { alignmentCol, makeCoordinateMapper, structurePos, } from './coordinates';
|
|
7
7
|
import { looksLikePlddt } from './extractPerResidueConfidence';
|
|
8
|
-
import highlightResidueRange from './highlightResidueRange';
|
|
9
8
|
import { runLocalAlignment } from './pairwiseAlignment';
|
|
10
9
|
import { proteinAbbreviationMapping } from './proteinAbbreviationMapping';
|
|
11
10
|
import { clickProteinToGenome, proteinRangeToGenomeMapping, proteinToGenomeMapping, } from './proteinToGenomeMapping';
|
|
@@ -330,6 +329,18 @@ const Structure = types
|
|
|
330
329
|
? undefined
|
|
331
330
|
: { start, end: end + 1 };
|
|
332
331
|
},
|
|
332
|
+
/**
|
|
333
|
+
* #getter
|
|
334
|
+
* The current hover as a 0-based half-open structure range. A feature-range
|
|
335
|
+
* hover (hoverStructureRange) takes priority over a single-residue hover
|
|
336
|
+
* (structureSeqHoverPos). Drives both the molstar 3D highlight and the
|
|
337
|
+
* genome highlight.
|
|
338
|
+
*/
|
|
339
|
+
get hoverHighlightRange() {
|
|
340
|
+
const pos = this.structureSeqHoverPos;
|
|
341
|
+
return (this.hoverStructureRange ??
|
|
342
|
+
(pos === undefined ? undefined : { start: pos, end: pos + 1 }));
|
|
343
|
+
},
|
|
333
344
|
/**
|
|
334
345
|
* #getter
|
|
335
346
|
* Persistent click selection in alignment coordinates, derived from
|
|
@@ -378,27 +389,14 @@ const Structure = types
|
|
|
378
389
|
},
|
|
379
390
|
/**
|
|
380
391
|
* #getter
|
|
381
|
-
* Genome regions to highlight in the LGV
|
|
382
|
-
*
|
|
383
|
-
*
|
|
384
|
-
* originated from the genome view itself, so hovering the LGV doesn't
|
|
385
|
-
* echo a codon-width highlight back onto that same view.
|
|
392
|
+
* Genome regions to highlight in the LGV from the current hover. Excludes
|
|
393
|
+
* hovers that originated from the genome view itself, so hovering the LGV
|
|
394
|
+
* doesn't echo a codon-width highlight back onto that same view.
|
|
386
395
|
*/
|
|
387
396
|
get hoverGenomeHighlights() {
|
|
388
|
-
|
|
389
|
-
return [];
|
|
390
|
-
}
|
|
391
|
-
const range = this.hoverStructureRange;
|
|
392
|
-
if (range) {
|
|
393
|
-
return this.structureRangeToGenomeHighlight(range);
|
|
394
|
-
}
|
|
395
|
-
const structureSeqPos = this.structureSeqHoverPos;
|
|
396
|
-
return structureSeqPos === undefined
|
|
397
|
+
return self.hoverPosition?.source === 'genome'
|
|
397
398
|
? []
|
|
398
|
-
: this.structureRangeToGenomeHighlight(
|
|
399
|
-
start: structureSeqPos,
|
|
400
|
-
end: structureSeqPos + 1,
|
|
401
|
-
});
|
|
399
|
+
: this.structureRangeToGenomeHighlight(this.hoverHighlightRange);
|
|
402
400
|
},
|
|
403
401
|
/**
|
|
404
402
|
* #getter
|
|
@@ -564,6 +562,20 @@ const Structure = types
|
|
|
564
562
|
}))
|
|
565
563
|
.actions(self => ({
|
|
566
564
|
afterAttach() {
|
|
565
|
+
// Re-subscribe to a molstar click/hover behavior whenever the plugin
|
|
566
|
+
// becomes available; the subscription is disposed with the model.
|
|
567
|
+
const addInteractionListener = (kind, onUpdate) => {
|
|
568
|
+
addDisposer(self, autorun(async () => {
|
|
569
|
+
const { molstarPluginContext } = self;
|
|
570
|
+
if (molstarPluginContext) {
|
|
571
|
+
addDisposer(self, await subscribeMolstarInteraction({
|
|
572
|
+
plugin: molstarPluginContext,
|
|
573
|
+
kind,
|
|
574
|
+
onUpdate,
|
|
575
|
+
}));
|
|
576
|
+
}
|
|
577
|
+
}));
|
|
578
|
+
};
|
|
567
579
|
addDisposer(self, autorun(async () => {
|
|
568
580
|
try {
|
|
569
581
|
const { userProvidedTranscriptSequence, structureSequences, exactMatch, alignmentAlgorithm, } = self;
|
|
@@ -611,89 +623,54 @@ const Structure = types
|
|
|
611
623
|
self.setGenomeHoveredPosition(undefined);
|
|
612
624
|
}
|
|
613
625
|
}));
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
self.setHoveredPosition(info);
|
|
627
|
-
self.setSelectedFeatureId(undefined);
|
|
628
|
-
clickProteinToGenome({
|
|
629
|
-
model: self,
|
|
630
|
-
structureSeqPos: info.structureSeqPos,
|
|
631
|
-
}).catch((e) => {
|
|
632
|
-
console.error(e);
|
|
633
|
-
self.parentView.setError(e);
|
|
634
|
-
});
|
|
635
|
-
},
|
|
626
|
+
// Click only acts on positive matches; clicks that didn't land on a
|
|
627
|
+
// structure element are ignored.
|
|
628
|
+
addInteractionListener('click', info => {
|
|
629
|
+
if (info) {
|
|
630
|
+
self.setHoveredPosition(info);
|
|
631
|
+
self.setSelectedFeatureId(undefined);
|
|
632
|
+
clickProteinToGenome({
|
|
633
|
+
model: self,
|
|
634
|
+
structureSeqPos: info.structureSeqPos,
|
|
635
|
+
}).catch((e) => {
|
|
636
|
+
console.error(e);
|
|
637
|
+
self.parentView.setError(e);
|
|
636
638
|
});
|
|
637
|
-
addDisposer(self, dispose);
|
|
638
639
|
}
|
|
639
|
-
})
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const dispose = await subscribeMolstarInteraction({
|
|
644
|
-
plugin: molstarPluginContext,
|
|
645
|
-
kind: 'hover',
|
|
646
|
-
onUpdate: info => {
|
|
647
|
-
self.setHoveredPosition(info);
|
|
648
|
-
},
|
|
649
|
-
});
|
|
650
|
-
addDisposer(self, dispose);
|
|
651
|
-
}
|
|
652
|
-
}));
|
|
640
|
+
});
|
|
641
|
+
addInteractionListener('hover', info => {
|
|
642
|
+
self.setHoveredPosition(info);
|
|
643
|
+
});
|
|
653
644
|
addDisposer(self, autorun(async () => {
|
|
654
645
|
const { showHighlight, structureSeqToTranscriptSeqPosition, molstarPluginContext, molstarStructure, } = self;
|
|
655
646
|
if (molstarStructure &&
|
|
656
647
|
molstarPluginContext &&
|
|
657
648
|
structureSeqToTranscriptSeqPosition) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
}
|
|
649
|
+
await setMolstarLoci({
|
|
650
|
+
structure: molstarStructure,
|
|
651
|
+
plugin: molstarPluginContext,
|
|
652
|
+
channel: 'select',
|
|
653
|
+
spec: showHighlight
|
|
654
|
+
? {
|
|
655
|
+
kind: 'list',
|
|
656
|
+
residues: Object.keys(structureSeqToTranscriptSeqPosition).map(coord => +coord),
|
|
657
|
+
}
|
|
658
|
+
: undefined,
|
|
659
|
+
});
|
|
670
660
|
}
|
|
671
661
|
}));
|
|
672
|
-
// Drive molstar hover-highlight
|
|
673
|
-
// hover (hoverStructureRange) takes priority over a single-residue
|
|
674
|
-
// hover (structureSeqHoverPos); otherwise clear.
|
|
662
|
+
// Drive molstar hover-highlight from the model's hoverHighlightRange.
|
|
675
663
|
addDisposer(self, autorun(async () => {
|
|
676
|
-
const { molstarStructure, molstarPluginContext,
|
|
664
|
+
const { molstarStructure, molstarPluginContext, hoverHighlightRange } = self;
|
|
677
665
|
if (molstarStructure && molstarPluginContext) {
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
}
|
|
686
|
-
else if (structureSeqHoverPos !== undefined) {
|
|
687
|
-
await applyLociInteractivitySingle({
|
|
688
|
-
structure: molstarStructure,
|
|
689
|
-
plugin: molstarPluginContext,
|
|
690
|
-
selectedResidue: structureSeqHoverPos,
|
|
691
|
-
mode: 'highlight',
|
|
692
|
-
});
|
|
693
|
-
}
|
|
694
|
-
else {
|
|
695
|
-
molstarPluginContext.managers.interactivity.lociHighlights.clearHighlights();
|
|
696
|
-
}
|
|
666
|
+
await setMolstarLoci({
|
|
667
|
+
structure: molstarStructure,
|
|
668
|
+
plugin: molstarPluginContext,
|
|
669
|
+
channel: 'highlight',
|
|
670
|
+
spec: hoverHighlightRange
|
|
671
|
+
? { kind: 'range', ...hoverHighlightRange }
|
|
672
|
+
: undefined,
|
|
673
|
+
});
|
|
697
674
|
}
|
|
698
675
|
}));
|
|
699
676
|
},
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { PluginContext } from 'molstar/lib/mol-plugin/context';
|
|
2
2
|
export interface MolstarLocationInfo {
|
|
3
|
+
/**
|
|
4
|
+
* 0-based label position (label_seq_id - 1). This is the plugin's canonical
|
|
5
|
+
* structure coordinate: structureSequences, the coordinate maps, and the
|
|
6
|
+
* outbound highlight in setMolstarLoci are all label-based, so the inbound
|
|
7
|
+
* read must be too. For AlphaFold structures label_seq_id == auth_seq_id, but
|
|
8
|
+
* for PDB structures whose author numbering is offset or gapped they diverge,
|
|
9
|
+
* and reading auth_seq_id here would mis-map every hover/click.
|
|
10
|
+
*/
|
|
3
11
|
structureSeqPos: number;
|
|
4
12
|
code: string;
|
|
5
13
|
chain: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import loadMolstar from './loadMolstar';
|
|
2
2
|
function extractLocationInfo(molstar, location) {
|
|
3
3
|
return {
|
|
4
|
-
structureSeqPos: molstar.StructureProperties.residue.
|
|
4
|
+
structureSeqPos: molstar.StructureProperties.residue.label_seq_id(location) - 1,
|
|
5
5
|
code: molstar.StructureProperties.atom.label_comp_id(location),
|
|
6
6
|
chain: molstar.StructureProperties.chain.auth_asym_id(location),
|
|
7
7
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { Structure } from 'molstar/lib/mol-model/structure';
|
|
2
1
|
interface HoveredState {
|
|
3
2
|
hoverPosition: {
|
|
4
3
|
coord: number;
|
|
@@ -6,9 +5,5 @@ interface HoveredState {
|
|
|
6
5
|
};
|
|
7
6
|
}
|
|
8
7
|
export declare function checkHovered(hovered: unknown): hovered is HoveredState;
|
|
9
|
-
export declare function getMolstarStructureSelection({ structure, selectedResidue, }: {
|
|
10
|
-
structure: Structure;
|
|
11
|
-
selectedResidue: number;
|
|
12
|
-
}): Promise<import("molstar/lib/mol-model/structure").StructureSelection>;
|
|
13
8
|
export declare function invertMap(arg: Record<number, number>): Record<number, number>;
|
|
14
9
|
export {};
|
package/dist/ProteinView/util.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import loadMolstar from './loadMolstar';
|
|
2
1
|
export function checkHovered(hovered) {
|
|
3
2
|
return (!!hovered &&
|
|
4
3
|
typeof hovered === 'object' &&
|
|
@@ -8,16 +7,6 @@ export function checkHovered(hovered) {
|
|
|
8
7
|
'coord' in hovered.hoverPosition &&
|
|
9
8
|
'refName' in hovered.hoverPosition);
|
|
10
9
|
}
|
|
11
|
-
export async function getMolstarStructureSelection({ structure, selectedResidue, }) {
|
|
12
|
-
const { Script } = await loadMolstar();
|
|
13
|
-
return Script.getStructureSelection(Q => Q.struct.generator.atomGroups({
|
|
14
|
-
'residue-test': Q.core.rel.eq([
|
|
15
|
-
Q.struct.atomProperty.macromolecular.label_seq_id(),
|
|
16
|
-
selectedResidue,
|
|
17
|
-
]),
|
|
18
|
-
'group-by': Q.struct.atomProperty.macromolecular.residueKey(),
|
|
19
|
-
}), structure);
|
|
20
|
-
}
|
|
21
10
|
export function invertMap(arg) {
|
|
22
11
|
return Object.fromEntries(Object.entries(arg).map(([a, b]) => [b, +a]));
|
|
23
12
|
}
|