react-msaview 6.4.2 → 7.0.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/README.md +6 -5
- package/bundle/index.js +100 -101
- package/bundle/index.js.map +4 -4
- package/dist/components/Loading.js +2 -2
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +10 -2
- package/dist/components/MSAViewer.js +90 -2
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/ResizeHandles.d.ts +3 -3
- package/dist/components/ResizeHandles.js +28 -21
- package/dist/components/ResizeHandles.js.map +1 -1
- package/dist/components/dialogs/{InterProScanDialog.d.ts → AnnotationFileDialog.d.ts} +2 -2
- package/dist/components/dialogs/AnnotationFileDialog.js +92 -0
- package/dist/components/dialogs/AnnotationFileDialog.js.map +1 -0
- package/dist/components/dialogs/FeatureDialog.js +13 -9
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/header/Header.js +4 -0
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderStatusArea.js +0 -2
- package/dist/components/header/HeaderStatusArea.js.map +1 -1
- package/dist/components/header/LoadWarnings.d.ts +6 -0
- package/dist/components/header/LoadWarnings.js +36 -0
- package/dist/components/header/LoadWarnings.js.map +1 -0
- package/dist/components/header/MultiAlignmentSelector.js +0 -0
- package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
- package/dist/components/header/TreeSettingsMenu.js +9 -1
- package/dist/components/header/TreeSettingsMenu.js.map +1 -1
- package/dist/components/header/UnshareableDataWarning.d.ts +6 -0
- package/dist/components/header/UnshareableDataWarning.js +42 -0
- package/dist/components/header/UnshareableDataWarning.js.map +1 -0
- package/dist/components/header/getAnnotationsMenu.js +14 -14
- package/dist/components/header/getAnnotationsMenu.js.map +1 -1
- package/dist/components/import/ImportForm.js +1 -1
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.js +2 -6
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/import/util.js +3 -0
- package/dist/components/import/util.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +4 -5
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/msaRaster.d.ts +13 -3
- package/dist/components/msa/msaRaster.js +173 -61
- package/dist/components/msa/msaRaster.js.map +1 -1
- package/dist/components/msa/renderHighlights.d.ts +39 -1
- package/dist/components/msa/renderHighlights.js +71 -6
- package/dist/components/msa/renderHighlights.js.map +1 -1
- package/dist/components/msa/renderMSABlock.d.ts +1 -2
- package/dist/components/msa/renderMSABlock.js +24 -28
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +9 -30
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/renderCtx.d.ts +1 -1
- package/dist/components/tracks/TrackBlocks.js +10 -11
- package/dist/components/tracks/TrackBlocks.js.map +1 -1
- package/dist/components/tracks/drawTracks.d.ts +26 -8
- package/dist/components/tracks/drawTracks.js +123 -13
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tree/TreeCanvas.js +2 -3
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +4 -2
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeRuler.js +13 -3
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.d.ts +0 -1
- package/dist/components/tree/renderTreeCanvas.js +70 -30
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/scaleBar.d.ts +10 -0
- package/dist/components/tree/scaleBar.js +24 -0
- package/dist/components/tree/scaleBar.js.map +1 -0
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +18 -1
- package/dist/constants.js.map +1 -1
- package/dist/fetchUtils.d.ts +7 -7
- package/dist/fetchUtils.js +4 -32
- package/dist/fetchUtils.js.map +1 -1
- package/dist/hierarchy.d.ts +2 -1
- package/dist/hierarchy.js +16 -10
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +8 -2
- package/dist/index.js.map +1 -1
- package/dist/model/DataModel.js +5 -2
- package/dist/model/DataModel.js.map +1 -1
- package/dist/model.d.ts +454 -177
- package/dist/model.js +1180 -511
- package/dist/model.js.map +1 -1
- package/dist/renderToStaticMarkup.d.ts +11 -0
- package/dist/renderToStaticMarkup.js +30 -7
- package/dist/renderToStaticMarkup.js.map +1 -1
- package/dist/renderToSvg.js +25 -19
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.d.ts +25 -25
- package/dist/rowCoordinateCalculations.js +12 -36
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/seqPosToGlobalCol.js +3 -1
- package/dist/seqPosToGlobalCol.js.map +1 -1
- package/dist/svgTestUtil.d.ts +144 -82
- package/dist/types.d.ts +97 -3
- package/dist/util.d.ts +11 -4
- package/dist/util.js +30 -10
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/wuss.d.ts +14 -0
- package/dist/wuss.js +55 -0
- package/dist/wuss.js.map +1 -0
- package/package.json +10 -8
- package/src/components/Loading.tsx +12 -2
- package/src/components/MSAViewer.tsx +106 -2
- package/src/components/ResizeHandles.tsx +31 -31
- package/src/components/dialogs/AnnotationFileDialog.tsx +162 -0
- package/src/components/dialogs/FeatureDialog.tsx +13 -9
- package/src/components/header/Header.tsx +4 -0
- package/src/components/header/HeaderStatusArea.tsx +0 -5
- package/src/components/header/LoadWarnings.tsx +49 -0
- package/src/components/header/MultiAlignmentSelector.tsx +0 -0
- package/src/components/header/TreeSettingsMenu.tsx +9 -1
- package/src/components/header/UnshareableDataWarning.tsx +58 -0
- package/src/components/header/getAnnotationsMenu.ts +16 -17
- package/src/components/import/ImportForm.tsx +2 -2
- package/src/components/import/ImportFormExamples.tsx +2 -6
- package/src/components/import/util.ts +3 -0
- package/src/components/msa/MSACanvasBlock.tsx +4 -5
- package/src/components/msa/msaRaster.ts +216 -59
- package/src/components/msa/renderHighlights.ts +103 -5
- package/src/components/msa/renderMSABlock.ts +25 -36
- package/src/components/msa/renderMSAMouseover.ts +9 -39
- package/src/components/renderCtx.ts +1 -0
- package/src/components/tracks/TrackBlocks.tsx +10 -13
- package/src/components/tracks/drawTracks.ts +165 -17
- package/src/components/tree/TreeCanvas.tsx +2 -3
- package/src/components/tree/TreeCanvasBlock.tsx +4 -2
- package/src/components/tree/TreeRuler.tsx +38 -3
- package/src/components/tree/renderTreeCanvas.ts +79 -35
- package/src/components/tree/scaleBar.ts +23 -0
- package/src/constants.ts +20 -1
- package/src/fetchUtils.ts +7 -40
- package/src/hierarchy.ts +20 -11
- package/src/index.ts +18 -2
- package/src/model/DataModel.ts +6 -2
- package/src/model.ts +1352 -616
- package/src/rawImports.d.ts +9 -0
- package/src/renderToStaticMarkup.ts +34 -7
- package/src/renderToSvg.tsx +33 -27
- package/src/rowCoordinateCalculations.ts +15 -59
- package/src/seqPosToGlobalCol.ts +3 -1
- package/src/types.ts +131 -4
- package/src/util.ts +31 -14
- package/src/version.ts +1 -1
- package/src/wuss.ts +62 -0
- package/dist/components/dialogs/InterProScanDialog.js +0 -137
- package/dist/components/dialogs/InterProScanDialog.js.map +0 -1
- package/dist/components/dialogs/InterProScanFileDialog.d.ts +0 -7
- package/dist/components/dialogs/InterProScanFileDialog.js +0 -64
- package/dist/components/dialogs/InterProScanFileDialog.js.map +0 -1
- package/dist/launchInterProScan.d.ts +0 -13
- package/dist/launchInterProScan.js +0 -110
- package/dist/launchInterProScan.js.map +0 -1
- package/dist/useColorContrast.d.ts +0 -10
- package/dist/useColorContrast.js +0 -13
- package/dist/useColorContrast.js.map +0 -1
- package/src/clustalX.test.ts +0 -74
- package/src/colSpace.test.ts +0 -67
- package/src/collapseLogic.test.ts +0 -115
- package/src/colorSchemes.docs.test.ts +0 -57
- package/src/columnCounts.test.ts +0 -73
- package/src/columnStats.test.ts +0 -94
- package/src/columnTracks.test.ts +0 -97
- package/src/components/dialogs/InterProScanDialog.tsx +0 -214
- package/src/components/dialogs/InterProScanFileDialog.tsx +0 -138
- package/src/components/minimap/minimapLayout.test.ts +0 -71
- package/src/components/msa/msaRaster.test.ts +0 -145
- package/src/components/msa/renderBoxFeatureCanvasBlock.test.ts +0 -51
- package/src/components/tree/renderTreeCanvas.test.ts +0 -296
- package/src/dataInitialized.test.ts +0 -42
- package/src/domainBands.test.ts +0 -122
- package/src/domainLetterColor.test.ts +0 -80
- package/src/exportFileName.test.ts +0 -40
- package/src/fetchUtils.test.ts +0 -83
- package/src/flatToTree.test.ts +0 -51
- package/src/hierarchy.test.ts +0 -228
- package/src/highlights.test.ts +0 -70
- package/src/impgRender.test.tsx +0 -68
- package/src/largeTree.test.ts +0 -67
- package/src/launchInterProScan.ts +0 -167
- package/src/loadErrorDisplay.test.tsx +0 -102
- package/src/modelFilehandleLoaders.test.ts +0 -137
- package/src/modelReset.test.ts +0 -120
- package/src/neighborJoining.test.ts +0 -164
- package/src/parseAsn1.test.ts +0 -36
- package/src/propertyConservation.test.ts +0 -36
- package/src/renderColumnTracksSvg.test.tsx +0 -108
- package/src/renderDomainsSvg.test.tsx +0 -118
- package/src/renderHighlightsSvg.test.tsx +0 -85
- package/src/renderMinimapSvg.test.tsx +0 -62
- package/src/renderRasterSvg.test.tsx +0 -144
- package/src/renderSequenceLogoSvg.test.tsx +0 -165
- package/src/renderToSvg.test.tsx +0 -65
- package/src/reset.test.ts +0 -61
- package/src/rowCoordinateCalculations.test.ts +0 -211
- package/src/rowSpace.test.ts +0 -46
- package/src/segmentOverlay.test.ts +0 -70
- package/src/seqPosToGlobalCol.test.ts +0 -59
- package/src/sequenceLogo.test.ts +0 -88
- package/src/setFontSize.test.ts +0 -33
- package/src/stripDefault.test.ts +0 -48
- package/src/stripDefaultSnapshot.test.ts +0 -87
- package/src/treeMetadata.test.ts +0 -39
- package/src/useCanvasAutorun.test.tsx +0 -98
- package/src/useColorContrast.ts +0 -18
- package/src/viewChrome.test.tsx +0 -134
- package/src/wheelZoom.test.ts +0 -46
package/dist/types.d.ts
CHANGED
|
@@ -4,13 +4,14 @@ export interface Accession {
|
|
|
4
4
|
name: string;
|
|
5
5
|
description: string;
|
|
6
6
|
}
|
|
7
|
-
export type TrackKind = 'text' | 'bar' | 'logo';
|
|
7
|
+
export type TrackKind = 'text' | 'bar' | 'logo' | 'arc' | 'ruler';
|
|
8
8
|
export interface BasicTrackModel {
|
|
9
9
|
id: string;
|
|
10
10
|
name: string;
|
|
11
11
|
associatedRowName?: string;
|
|
12
12
|
height: number;
|
|
13
13
|
kind: TrackKind;
|
|
14
|
+
defaultOff?: boolean;
|
|
14
15
|
}
|
|
15
16
|
export interface TextTrackModel extends BasicTrackModel {
|
|
16
17
|
customColorScheme?: Record<string, string>;
|
|
@@ -19,22 +20,115 @@ export interface TextTrackModel extends BasicTrackModel {
|
|
|
19
20
|
export interface BarTrackModel extends BasicTrackModel {
|
|
20
21
|
barColor?: string;
|
|
21
22
|
}
|
|
23
|
+
export interface Arc {
|
|
24
|
+
start: number;
|
|
25
|
+
end: number;
|
|
26
|
+
color?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface ArcTrackModel extends BasicTrackModel {
|
|
29
|
+
arcs?: Arc[];
|
|
30
|
+
arcColor?: string;
|
|
31
|
+
}
|
|
22
32
|
export interface BasicTrack {
|
|
23
33
|
ReactComponent: React.FC<any>;
|
|
24
|
-
model: TextTrackModel & BarTrackModel;
|
|
34
|
+
model: TextTrackModel & BarTrackModel & ArcTrackModel;
|
|
35
|
+
}
|
|
36
|
+
export interface ArcSpec {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
color?: string;
|
|
25
40
|
}
|
|
26
41
|
export interface ColumnTrackSpec {
|
|
27
42
|
id: string;
|
|
28
43
|
name: string;
|
|
29
|
-
kind: 'bar' | 'text';
|
|
44
|
+
kind: 'bar' | 'text' | 'arc';
|
|
30
45
|
values?: number[];
|
|
31
46
|
data?: string;
|
|
47
|
+
arcs?: ArcSpec[];
|
|
32
48
|
max?: number;
|
|
33
49
|
color?: string;
|
|
34
50
|
colors?: Record<string, string>;
|
|
35
51
|
row?: string;
|
|
36
52
|
height?: number;
|
|
37
53
|
}
|
|
54
|
+
export interface ResidueSegment {
|
|
55
|
+
rowStart: number;
|
|
56
|
+
rowEnd: number;
|
|
57
|
+
structStart: number;
|
|
58
|
+
structEnd: number;
|
|
59
|
+
}
|
|
60
|
+
export interface MappedStructure {
|
|
61
|
+
id: string;
|
|
62
|
+
kind?: 'experimental' | 'predicted';
|
|
63
|
+
asymId?: string;
|
|
64
|
+
url?: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Which residue of which structure a row's residue is, as data. Computed by
|
|
68
|
+
* whatever knows how -- SIFTS, an AlphaFold model, a curator -- and carried in
|
|
69
|
+
* the snapshot, because the viewer cannot work it out: matching a row to a
|
|
70
|
+
* structure by sequence equality fails for a construct with an expression tag,
|
|
71
|
+
* a truncation, an engineered residue, or a row that is a subsequence of the
|
|
72
|
+
* entry, and it fails in the direction that looks like it worked.
|
|
73
|
+
*
|
|
74
|
+
* Positions are 1-based and inclusive on both sides, as GFF and `highlights`
|
|
75
|
+
* are. Structure positions are `label_seq_id`, the index into the entity's
|
|
76
|
+
* SEQRES; author numbering carries insertion codes and stays out.
|
|
77
|
+
*
|
|
78
|
+
* `unobserved` is in structure positions: present in SEQRES with no
|
|
79
|
+
* coordinates. Worth distinguishing from unmapped, because "the
|
|
80
|
+
* crystallographer could not see it" and "this protein does not have that
|
|
81
|
+
* residue" mean different things to a reader.
|
|
82
|
+
*/
|
|
83
|
+
export interface ResidueMapping {
|
|
84
|
+
row: string;
|
|
85
|
+
accession?: string;
|
|
86
|
+
structure: MappedStructure;
|
|
87
|
+
segments: ResidueSegment[];
|
|
88
|
+
unobserved?: [number, number][];
|
|
89
|
+
/**
|
|
90
|
+
* ungapped length of the row this was computed against. Optional, and worth
|
|
91
|
+
* setting: a mapping outlives the alignment it was made for, and pointing at
|
|
92
|
+
* residue 58 of a sequence that has since been re-aligned, revised or swapped
|
|
93
|
+
* is the failure this whole layer exists to avoid. Declared here, the viewer
|
|
94
|
+
* can notice and refuse instead of answering from stale arithmetic.
|
|
95
|
+
*/
|
|
96
|
+
rowLength?: number;
|
|
97
|
+
generated?: {
|
|
98
|
+
by?: string;
|
|
99
|
+
date?: string;
|
|
100
|
+
sourceSha256?: string;
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
export interface ResidueMappingProblem {
|
|
104
|
+
row: string;
|
|
105
|
+
structureId: string;
|
|
106
|
+
/**
|
|
107
|
+
* `mapping` means the whole mapping is out: the evidence is about the row it
|
|
108
|
+
* claims, so nothing it says can be trusted. `segment` takes only that
|
|
109
|
+
* segment, since the rest of the mapping still describes residues that exist.
|
|
110
|
+
*/
|
|
111
|
+
scope: 'mapping' | 'segment';
|
|
112
|
+
reason: string;
|
|
113
|
+
}
|
|
114
|
+
export interface StructureResidue {
|
|
115
|
+
structure: MappedStructure;
|
|
116
|
+
position: number;
|
|
117
|
+
observed: boolean;
|
|
118
|
+
}
|
|
119
|
+
export interface RowResidue {
|
|
120
|
+
rowName: string;
|
|
121
|
+
seqPos: number;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* One loaded document that the snapshot leaves behind, and how big it is.
|
|
125
|
+
* `what` names it the way the import form does, since that is where the reader
|
|
126
|
+
* would go to load it differently.
|
|
127
|
+
*/
|
|
128
|
+
export interface UnshareableData {
|
|
129
|
+
what: 'alignment' | 'tree' | 'annotations' | 'row metadata' | 'data tracks';
|
|
130
|
+
bytes: number;
|
|
131
|
+
}
|
|
38
132
|
export type { Annotation };
|
|
39
133
|
export type TidyDomainAnnotation = Annotation;
|
|
40
134
|
export interface DomainBand {
|
package/dist/util.d.ts
CHANGED
|
@@ -3,9 +3,17 @@ export declare function adjustColorForContrast(color: string, bg: string): strin
|
|
|
3
3
|
export declare function transform<T>(obj: Record<string, T>, cb: (arg0: [string, T]) => [string, T]): {
|
|
4
4
|
[k: string]: T;
|
|
5
5
|
};
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Readable letter color over a given cell color, memoized per theme.
|
|
8
|
+
*
|
|
9
|
+
* A dynamic scheme colors a cell from its column, so there is no letter->color
|
|
10
|
+
* table to precompute a contrast table from; asking per cell color covers the
|
|
11
|
+
* dynamic schemes, the static ones and a track's own `colors` alike. An
|
|
12
|
+
* uncolored cell sits on the theme's background, where the theme's own text
|
|
13
|
+
* color is what stays readable -- `black` turned every gap and every uncolored
|
|
14
|
+
* cell invisible in the dark theme.
|
|
15
|
+
*/
|
|
16
|
+
export declare function contrastTextFn(theme: Theme): (color: string | undefined) => string;
|
|
9
17
|
export declare function dropBlanks<T>(blanks: number[], arr: T[]): T[];
|
|
10
18
|
export declare function skipBlanks(blanks: number[], str: string): string;
|
|
11
19
|
export declare function computeRowInsertions(blanks: number[], seq: string): {
|
|
@@ -16,4 +24,3 @@ export declare function len(a: {
|
|
|
16
24
|
end: number;
|
|
17
25
|
start: number;
|
|
18
26
|
}): number;
|
|
19
|
-
export declare function isBlank(s?: string): s is "-" | ".";
|
package/dist/util.js
CHANGED
|
@@ -26,11 +26,36 @@ export function adjustColorForContrast(color, bg) {
|
|
|
26
26
|
export function transform(obj, cb) {
|
|
27
27
|
return Object.fromEntries(Object.entries(obj).map(cb));
|
|
28
28
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
const contrastTextCaches = new WeakMap();
|
|
30
|
+
/**
|
|
31
|
+
* Readable letter color over a given cell color, memoized per theme.
|
|
32
|
+
*
|
|
33
|
+
* A dynamic scheme colors a cell from its column, so there is no letter->color
|
|
34
|
+
* table to precompute a contrast table from; asking per cell color covers the
|
|
35
|
+
* dynamic schemes, the static ones and a track's own `colors` alike. An
|
|
36
|
+
* uncolored cell sits on the theme's background, where the theme's own text
|
|
37
|
+
* color is what stays readable -- `black` turned every gap and every uncolored
|
|
38
|
+
* cell invisible in the dark theme.
|
|
39
|
+
*/
|
|
40
|
+
export function contrastTextFn(theme) {
|
|
41
|
+
let cache = contrastTextCaches.get(theme);
|
|
42
|
+
if (!cache) {
|
|
43
|
+
cache = new Map();
|
|
44
|
+
contrastTextCaches.set(theme, cache);
|
|
45
|
+
}
|
|
46
|
+
const fallback = theme.palette.text.primary;
|
|
47
|
+
return (color) => {
|
|
48
|
+
if (!color) {
|
|
49
|
+
return fallback;
|
|
50
|
+
}
|
|
51
|
+
const hit = cache.get(color);
|
|
52
|
+
if (hit !== undefined) {
|
|
53
|
+
return hit;
|
|
54
|
+
}
|
|
55
|
+
const out = theme.palette.getContrastText(colord(color).toHex());
|
|
56
|
+
cache.set(color, out);
|
|
57
|
+
return out;
|
|
58
|
+
};
|
|
34
59
|
}
|
|
35
60
|
export function dropBlanks(blanks, arr) {
|
|
36
61
|
if (blanks.length === 0) {
|
|
@@ -95,9 +120,4 @@ export function computeRowInsertions(blanks, seq) {
|
|
|
95
120
|
export function len(a) {
|
|
96
121
|
return a.end - a.start;
|
|
97
122
|
}
|
|
98
|
-
// https://sonnhammer.sbc.su.se/Stockholm.html
|
|
99
|
-
// gaps can be a . or - in stockholm
|
|
100
|
-
export function isBlank(s) {
|
|
101
|
-
return s === '-' || s === '.';
|
|
102
|
-
}
|
|
103
123
|
//# sourceMappingURL=util.js.map
|
package/dist/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,UAAU,MAAM,qBAAqB,CAAA;AAC5C,OAAO,WAAW,MAAM,sBAAsB,CAAA;AAI9C,MAAM,CAAC,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC,CAAA;AAEjC,MAAM,mBAAmB,GAAG,IAAI,GAAG,EAAkB,CAAA;AAErD,0EAA0E;AAC1E,uEAAuE;AACvE,8DAA8D;AAC9D,MAAM,UAAU,sBAAsB,CAAC,KAAa,EAAE,EAAU;IAC9D,MAAM,QAAQ,GAAG,GAAG,KAAK,IAAI,EAAE,EAAE,CAAA;IACjC,MAAM,MAAM,GAAG,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAChD,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,MAAM,CAAA;IACf,CAAC;IACD,IAAI,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACrB,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC;QACtB,MAAM,QAAQ,GAAG,MAAM,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,GAAG,CAAA;QAC7C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACjD,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QACjD,CAAC;IACH,CAAC;IACD,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,CAAA;IACxB,mBAAmB,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;IACzC,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,GAAsB,EACtB,EAAsC;IAEtC,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;AACxD,CAAC;AAED,MAAM,
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../src/util.ts"],"names":[],"mappings":"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"}
|
package/dist/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const version = "
|
|
1
|
+
export declare const version = "7.0.0";
|
package/dist/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const version = '
|
|
1
|
+
export const version = '7.0.0';
|
|
2
2
|
//# sourceMappingURL=version.js.map
|
package/dist/wuss.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BasePair {
|
|
2
|
+
/** 0-based column */
|
|
3
|
+
start: number;
|
|
4
|
+
/** 0-based column */
|
|
5
|
+
end: number;
|
|
6
|
+
/** the pair crosses a helix rather than nesting inside one */
|
|
7
|
+
pseudoknot: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* The base pairs a WUSS string encodes, as 0-based column indexes. Unmatched
|
|
11
|
+
* brackets are dropped rather than throwing: a hand-edited or truncated
|
|
12
|
+
* alignment should still draw the helices it does close.
|
|
13
|
+
*/
|
|
14
|
+
export declare function parseWuss(ss: string): BasePair[];
|
package/dist/wuss.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// WUSS notation (Rfam's `#=GC SS_cons`) names a consensus secondary structure
|
|
2
|
+
// by pairing columns. Nested helices use bracket pairs -- <>, (), [], {} --
|
|
3
|
+
// each type kept on its own stack, and a pseudoknot, which by definition
|
|
4
|
+
// crosses a helix it cannot nest inside, uses a letter pair instead: `A` opens
|
|
5
|
+
// and `a` closes, `B`/`b` for a second one. Everything else (. , _ - : ~) is
|
|
6
|
+
// unpaired.
|
|
7
|
+
const closeToOpen = {
|
|
8
|
+
'>': '<',
|
|
9
|
+
')': '(',
|
|
10
|
+
']': '[',
|
|
11
|
+
'}': '{',
|
|
12
|
+
};
|
|
13
|
+
const opens = new Set(Object.values(closeToOpen));
|
|
14
|
+
/**
|
|
15
|
+
* The base pairs a WUSS string encodes, as 0-based column indexes. Unmatched
|
|
16
|
+
* brackets are dropped rather than throwing: a hand-edited or truncated
|
|
17
|
+
* alignment should still draw the helices it does close.
|
|
18
|
+
*/
|
|
19
|
+
export function parseWuss(ss) {
|
|
20
|
+
const stacks = new Map();
|
|
21
|
+
const pairs = [];
|
|
22
|
+
const push = (key, col) => {
|
|
23
|
+
const stack = stacks.get(key);
|
|
24
|
+
if (stack) {
|
|
25
|
+
stack.push(col);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
stacks.set(key, [col]);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
const pop = (key, col, pseudoknot) => {
|
|
32
|
+
const start = stacks.get(key)?.pop();
|
|
33
|
+
if (start !== undefined) {
|
|
34
|
+
pairs.push({ start, end: col, pseudoknot });
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
for (let col = 0; col < ss.length; col++) {
|
|
38
|
+
const ch = ss[col];
|
|
39
|
+
const opener = closeToOpen[ch];
|
|
40
|
+
if (opens.has(ch)) {
|
|
41
|
+
push(ch, col);
|
|
42
|
+
}
|
|
43
|
+
else if (opener) {
|
|
44
|
+
pop(opener, col, false);
|
|
45
|
+
}
|
|
46
|
+
else if (ch >= 'A' && ch <= 'Z') {
|
|
47
|
+
push(ch, col);
|
|
48
|
+
}
|
|
49
|
+
else if (ch >= 'a' && ch <= 'z') {
|
|
50
|
+
pop(ch.toUpperCase(), col, true);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return pairs.sort((a, b) => a.start - b.start);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=wuss.js.map
|
package/dist/wuss.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wuss.js","sourceRoot":"","sources":["../src/wuss.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,YAAY;AAEZ,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;IACR,GAAG,EAAE,GAAG;CACT,CAAA;AACD,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,CAAA;AAWjD;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,EAAU;IAClC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAoB,CAAA;IAC1C,MAAM,KAAK,GAAe,EAAE,CAAA;IAC5B,MAAM,IAAI,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,KAAK,EAAE,CAAC;YACV,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QACjB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAA;QACxB,CAAC;IACH,CAAC,CAAA;IACD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAE,GAAW,EAAE,UAAmB,EAAE,EAAE;QAC5D,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,CAAA;QACpC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC,CAAA;QAC7C,CAAC;IACH,CAAC,CAAA;IAED,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE,CAAC;QACzC,MAAM,EAAE,GAAG,EAAE,CAAC,GAAG,CAAE,CAAA;QACnB,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,CAAC,CAAA;QAC9B,IAAI,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;YAClB,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACf,CAAC;aAAM,IAAI,MAAM,EAAE,CAAC;YAClB,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;QACzB,CAAC;aAAM,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;YAClC,IAAI,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;QACf,CAAC;aAAM,IAAI,EAAE,IAAI,GAAG,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC;YAClC,GAAG,CAAC,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;AAChD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-msaview",
|
|
3
3
|
"author": "Colin",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "7.0.0",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -19,17 +19,19 @@
|
|
|
19
19
|
"files": [
|
|
20
20
|
"dist",
|
|
21
21
|
"bundle",
|
|
22
|
-
"src"
|
|
22
|
+
"src",
|
|
23
|
+
"!src/**/*.test.ts",
|
|
24
|
+
"!src/**/*.test.tsx"
|
|
23
25
|
],
|
|
24
26
|
"engines": {
|
|
25
|
-
"node": ">=
|
|
27
|
+
"node": ">=18"
|
|
26
28
|
},
|
|
27
29
|
"peerDependencies": {
|
|
28
30
|
"@jbrowse/core": ">=2.0.0",
|
|
29
|
-
"@jbrowse/mobx-state-tree": "
|
|
31
|
+
"@jbrowse/mobx-state-tree": ">=5.0.0",
|
|
30
32
|
"@mui/icons-material": ">=5.0.0",
|
|
31
33
|
"@mui/material": ">=5.0.0",
|
|
32
|
-
"mobx": ">=
|
|
34
|
+
"mobx": ">=6.0.0",
|
|
33
35
|
"mobx-react": ">=9.0.0",
|
|
34
36
|
"react": ">=16.8.0",
|
|
35
37
|
"react-dom": ">=16.8.0"
|
|
@@ -40,11 +42,11 @@
|
|
|
40
42
|
"esbuild": "^0.28.1"
|
|
41
43
|
},
|
|
42
44
|
"dependencies": {
|
|
43
|
-
"@gmod/newick": "^1.0.
|
|
44
|
-
"@jbrowse/svgcanvas": "
|
|
45
|
+
"@gmod/newick": "^1.0.3",
|
|
46
|
+
"@jbrowse/svgcanvas": "7.0.0",
|
|
45
47
|
"colord": "^2.9.3",
|
|
46
48
|
"flatbush": "^4.6.2",
|
|
47
|
-
"msa-parsers": "
|
|
49
|
+
"msa-parsers": "7.0.0"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
52
|
"clean": "rimraf dist bundle",
|
|
@@ -83,13 +83,23 @@ const Reset = observer(function ({
|
|
|
83
83
|
})
|
|
84
84
|
|
|
85
85
|
const Loading = observer(function ({ model }: { model: MsaViewModel }) {
|
|
86
|
-
const {
|
|
87
|
-
|
|
86
|
+
const {
|
|
87
|
+
isLoading,
|
|
88
|
+
dataInitialized,
|
|
89
|
+
error,
|
|
90
|
+
resetCount,
|
|
91
|
+
msaFilehandle,
|
|
92
|
+
treeFilehandle,
|
|
93
|
+
} = model
|
|
88
94
|
const hasPendingFilehandle = !!(msaFilehandle || treeFilehandle)
|
|
89
95
|
|
|
90
96
|
return (
|
|
91
97
|
<div>
|
|
98
|
+
{/* keyed on the reset counter: the boundary holds the error it caught
|
|
99
|
+
until it is remounted, so without this "Return to import form" put
|
|
100
|
+
the model back and left the error screen up */}
|
|
92
101
|
<ErrorBoundary
|
|
102
|
+
key={resetCount}
|
|
93
103
|
FallbackComponent={e => <Reset model={model} error={e.error} />}
|
|
94
104
|
>
|
|
95
105
|
{dataInitialized ? (
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import React, { useEffect, useState } from 'react'
|
|
1
|
+
import React, { useEffect, useRef, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
import { createJBrowseTheme } from '@jbrowse/core/ui/theme'
|
|
4
4
|
import useMeasure from '@jbrowse/core/util/useMeasure'
|
|
5
|
+
import { destroy, isAlive } from '@jbrowse/mobx-state-tree'
|
|
5
6
|
import { ThemeProvider } from '@mui/material/styles'
|
|
6
7
|
|
|
7
8
|
import MSAModelF from '../model.ts'
|
|
8
9
|
import Loading from './Loading.tsx'
|
|
9
10
|
|
|
10
|
-
import type { ColumnTrackSpec, Highlight } from '../types.ts'
|
|
11
|
+
import type { ColumnTrackSpec, Highlight, ResidueMapping } from '../types.ts'
|
|
11
12
|
import type { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
|
|
12
13
|
|
|
13
14
|
const theme = createJBrowseTheme()
|
|
@@ -25,6 +26,12 @@ interface MSAViewerProps {
|
|
|
25
26
|
colWidth?: number
|
|
26
27
|
/** initial per-row pixel height */
|
|
27
28
|
rowHeight?: number
|
|
29
|
+
/**
|
|
30
|
+
* hide columns at least this percent gaps (default 100, i.e. hide nothing).
|
|
31
|
+
* A deep family's alignment is mostly insertions carried by a few members;
|
|
32
|
+
* dropping those columns is what makes the rest readable
|
|
33
|
+
*/
|
|
34
|
+
allowedGappyness?: number
|
|
28
35
|
/** alignment columns (0-based) to highlight with a persistent overlay */
|
|
29
36
|
highlightColumns?: number[]
|
|
30
37
|
/**
|
|
@@ -37,6 +44,8 @@ interface MSAViewerProps {
|
|
|
37
44
|
relativeTo?: string
|
|
38
45
|
/** tracks supplied as data: per-column bar values or a text row (see docs/layers.md) */
|
|
39
46
|
columnTracks?: ColumnTrackSpec[]
|
|
47
|
+
/** which residue of which structure each row's residues are (see docs/layers.md) */
|
|
48
|
+
residueMappings?: ResidueMapping[]
|
|
40
49
|
/** draw the phylogenetic tree (default true); false leaves a labels-only gutter */
|
|
41
50
|
drawTree?: boolean
|
|
42
51
|
/** fixed width (px) of the tree/label area */
|
|
@@ -56,10 +65,12 @@ export default function MSAViewer({
|
|
|
56
65
|
height,
|
|
57
66
|
colWidth,
|
|
58
67
|
rowHeight,
|
|
68
|
+
allowedGappyness,
|
|
59
69
|
highlightColumns,
|
|
60
70
|
highlights,
|
|
61
71
|
relativeTo,
|
|
62
72
|
columnTracks,
|
|
73
|
+
residueMappings,
|
|
63
74
|
drawTree,
|
|
64
75
|
treeAreaWidth,
|
|
65
76
|
autoTreeAreaWidth,
|
|
@@ -79,16 +90,22 @@ export default function MSAViewer({
|
|
|
79
90
|
...(height ? { height } : {}),
|
|
80
91
|
...(colWidth ? { colWidth } : {}),
|
|
81
92
|
...(rowHeight ? { rowHeight } : {}),
|
|
93
|
+
...(allowedGappyness !== undefined ? { allowedGappyness } : {}),
|
|
82
94
|
...(highlightColumns ? { highlightColumns } : {}),
|
|
83
95
|
...(highlights ? { highlights } : {}),
|
|
84
96
|
...(relativeTo ? { relativeTo } : {}),
|
|
85
97
|
...(columnTracks ? { columnTracks } : {}),
|
|
98
|
+
...(residueMappings ? { residueMappings } : {}),
|
|
86
99
|
...(drawTree !== undefined ? { drawTree } : {}),
|
|
87
100
|
...(treeAreaWidth ? { treeAreaWidth } : {}),
|
|
88
101
|
...(autoTreeAreaWidth ? { autoTreeAreaWidth } : {}),
|
|
89
102
|
}),
|
|
90
103
|
)
|
|
91
104
|
|
|
105
|
+
const destroyTimer = useRef<ReturnType<typeof setTimeout> | undefined>(
|
|
106
|
+
undefined,
|
|
107
|
+
)
|
|
108
|
+
|
|
92
109
|
const [ref, { width }] = useMeasure()
|
|
93
110
|
useEffect(() => {
|
|
94
111
|
if (width) {
|
|
@@ -96,6 +113,93 @@ export default function MSAViewer({
|
|
|
96
113
|
}
|
|
97
114
|
}, [model, width])
|
|
98
115
|
|
|
116
|
+
// The props below stay live after mount: change one and it drives the model,
|
|
117
|
+
// so a host can put a control on the viewer -- an expand button, a diff
|
|
118
|
+
// toggle, a color-scheme picker -- without remounting it and re-fetching its
|
|
119
|
+
// alignment. Each effect depends only on its own prop, so a change the user
|
|
120
|
+
// makes inside the viewer (picking a scheme from the menu, dragging a row
|
|
121
|
+
// taller) survives the host's next render rather than being snapped back.
|
|
122
|
+
// Data props are not among them: new msa/tree/gff is a different alignment,
|
|
123
|
+
// which is a new model, which React spells `key`.
|
|
124
|
+
useEffect(() => {
|
|
125
|
+
if (height !== undefined) {
|
|
126
|
+
model.setHeight(height)
|
|
127
|
+
}
|
|
128
|
+
}, [model, height])
|
|
129
|
+
useEffect(() => {
|
|
130
|
+
if (colorScheme !== undefined) {
|
|
131
|
+
model.setColorSchemeName(colorScheme)
|
|
132
|
+
}
|
|
133
|
+
}, [model, colorScheme])
|
|
134
|
+
useEffect(() => {
|
|
135
|
+
if (colWidth !== undefined) {
|
|
136
|
+
model.setColWidth(colWidth)
|
|
137
|
+
}
|
|
138
|
+
}, [model, colWidth])
|
|
139
|
+
useEffect(() => {
|
|
140
|
+
if (rowHeight !== undefined) {
|
|
141
|
+
model.setRowHeight(rowHeight)
|
|
142
|
+
}
|
|
143
|
+
}, [model, rowHeight])
|
|
144
|
+
useEffect(() => {
|
|
145
|
+
if (allowedGappyness !== undefined) {
|
|
146
|
+
model.setAllowedGappyness(allowedGappyness)
|
|
147
|
+
}
|
|
148
|
+
}, [model, allowedGappyness])
|
|
149
|
+
useEffect(() => {
|
|
150
|
+
if (drawTree !== undefined) {
|
|
151
|
+
model.setDrawTree(drawTree)
|
|
152
|
+
}
|
|
153
|
+
}, [model, drawTree])
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
if (treeAreaWidth !== undefined) {
|
|
156
|
+
model.setTreeAreaWidth(treeAreaWidth)
|
|
157
|
+
}
|
|
158
|
+
}, [model, treeAreaWidth])
|
|
159
|
+
// unguarded: dropping the prop is how a host turns the reference diff back off
|
|
160
|
+
useEffect(() => {
|
|
161
|
+
model.drawRelativeTo(relativeTo)
|
|
162
|
+
}, [model, relativeTo])
|
|
163
|
+
|
|
164
|
+
// the data layers, keyed by content: a host that computes one inline hands a
|
|
165
|
+
// new array on every render, and replacing the model's copy each time would
|
|
166
|
+
// redraw the overlay for nothing
|
|
167
|
+
const highlightsKey = JSON.stringify(highlights ?? [])
|
|
168
|
+
useEffect(() => {
|
|
169
|
+
model.setHighlights(JSON.parse(highlightsKey))
|
|
170
|
+
}, [model, highlightsKey])
|
|
171
|
+
const columnTracksKey = JSON.stringify(columnTracks ?? [])
|
|
172
|
+
useEffect(() => {
|
|
173
|
+
model.setColumnTracks(JSON.parse(columnTracksKey))
|
|
174
|
+
}, [model, columnTracksKey])
|
|
175
|
+
const residueMappingsKey = JSON.stringify(residueMappings ?? [])
|
|
176
|
+
useEffect(() => {
|
|
177
|
+
model.setResidueMappings(JSON.parse(residueMappingsKey))
|
|
178
|
+
}, [model, residueMappingsKey])
|
|
179
|
+
const highlightColumnsKey = JSON.stringify(highlightColumns ?? null)
|
|
180
|
+
useEffect(() => {
|
|
181
|
+
model.setHighlightedColumns(JSON.parse(highlightColumnsKey) ?? undefined)
|
|
182
|
+
}, [model, highlightColumnsKey])
|
|
183
|
+
|
|
184
|
+
// the model owns a matchMedia listener and whatever fetches its filehandles
|
|
185
|
+
// started, so an unmounted viewer that keeps its model keeps those too. The
|
|
186
|
+
// destroy is deferred by a tick because React's StrictMode mounts, unmounts
|
|
187
|
+
// and remounts with the same state: the remount's effect cancels it
|
|
188
|
+
useEffect(() => {
|
|
189
|
+
if (destroyTimer.current !== undefined) {
|
|
190
|
+
clearTimeout(destroyTimer.current)
|
|
191
|
+
destroyTimer.current = undefined
|
|
192
|
+
}
|
|
193
|
+
return () => {
|
|
194
|
+
destroyTimer.current = setTimeout(() => {
|
|
195
|
+
destroyTimer.current = undefined
|
|
196
|
+
if (isAlive(model)) {
|
|
197
|
+
destroy(model)
|
|
198
|
+
}
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
}, [model])
|
|
202
|
+
|
|
99
203
|
return (
|
|
100
204
|
<ThemeProvider theme={theme}>
|
|
101
205
|
<div ref={ref}>
|
|
@@ -5,7 +5,7 @@ import { observer } from 'mobx-react'
|
|
|
5
5
|
import DragHandle from './DragHandle.tsx'
|
|
6
6
|
|
|
7
7
|
import type { MsaViewModel } from '../model.ts'
|
|
8
|
-
import type { TrackKind } from '../types.ts'
|
|
8
|
+
import type { BasicTrack, TrackKind } from '../types.ts'
|
|
9
9
|
|
|
10
10
|
export const VerticalResizeHandle = observer(function ({
|
|
11
11
|
model,
|
|
@@ -51,53 +51,53 @@ export const HorizontalResizeHandle = observer(function ({
|
|
|
51
51
|
)
|
|
52
52
|
})
|
|
53
53
|
|
|
54
|
-
// The
|
|
55
|
-
// so conservation and property conservation stay directly
|
|
56
|
-
// keeps its own, being taller by default. Text tracks are
|
|
57
|
-
// alignment row tall and follow rowHeight, so the zoom
|
|
58
|
-
// them.
|
|
59
|
-
const
|
|
60
|
-
Record<
|
|
61
|
-
TrackKind,
|
|
62
|
-
{
|
|
63
|
-
get: (model: MsaViewModel) => number
|
|
64
|
-
set: (model: MsaViewModel, height: number) => void
|
|
65
|
-
}
|
|
66
|
-
>
|
|
54
|
+
// The volatile behind each resizable kind of computed track. Both bar tracks
|
|
55
|
+
// write one height so conservation and property conservation stay directly
|
|
56
|
+
// comparable; the logo keeps its own, being taller by default. Text tracks are
|
|
57
|
+
// absent: they are one alignment row tall and follow rowHeight, so the zoom
|
|
58
|
+
// controls already size them.
|
|
59
|
+
const setTrackHeight: Partial<
|
|
60
|
+
Record<TrackKind, (model: MsaViewModel, height: number) => void>
|
|
67
61
|
> = {
|
|
68
|
-
bar: {
|
|
69
|
-
|
|
70
|
-
set: (model, height) => {
|
|
71
|
-
model.setConservationTrackHeight(height)
|
|
72
|
-
},
|
|
62
|
+
bar: (model, height) => {
|
|
63
|
+
model.setConservationTrackHeight(height)
|
|
73
64
|
},
|
|
74
|
-
logo: {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
65
|
+
logo: (model, height) => {
|
|
66
|
+
model.setSequenceLogoTrackHeight(height)
|
|
67
|
+
},
|
|
68
|
+
arc: (model, height) => {
|
|
69
|
+
model.setArcTrackHeight(height)
|
|
79
70
|
},
|
|
80
71
|
}
|
|
81
72
|
|
|
82
73
|
export const TrackResizeHandle = observer(function ({
|
|
83
74
|
model,
|
|
84
|
-
|
|
75
|
+
track,
|
|
85
76
|
}: {
|
|
86
77
|
model: MsaViewModel
|
|
87
|
-
|
|
78
|
+
track: BasicTrack
|
|
88
79
|
}) {
|
|
89
|
-
const height =
|
|
80
|
+
const { id, kind, height } = track.model
|
|
81
|
+
const setHeight = setTrackHeight[kind]
|
|
82
|
+
// a data track carries its own height, so its handle resizes that track --
|
|
83
|
+
// dragging one used to resize every track of its kind instead
|
|
84
|
+
const ownHeight = model.columnTracks.some(t => t.id === id)
|
|
90
85
|
const onDrag = useCallback(
|
|
91
86
|
(delta: number, startHeight: number) => {
|
|
92
|
-
|
|
87
|
+
const next = Math.max(10, startHeight + delta)
|
|
88
|
+
if (ownHeight) {
|
|
89
|
+
model.setColumnTrackHeight(id, next)
|
|
90
|
+
} else {
|
|
91
|
+
setTrackHeight[kind]?.(model, next)
|
|
92
|
+
}
|
|
93
93
|
},
|
|
94
|
-
[model,
|
|
94
|
+
[model, id, kind, ownHeight],
|
|
95
95
|
)
|
|
96
|
-
return
|
|
96
|
+
return setHeight ? (
|
|
97
97
|
<DragHandle
|
|
98
98
|
axis="y"
|
|
99
99
|
variant="resizer"
|
|
100
|
-
getStart={() => height
|
|
100
|
+
getStart={() => height}
|
|
101
101
|
onDrag={onDrag}
|
|
102
102
|
style={{
|
|
103
103
|
position: 'absolute',
|