react-msaview 5.4.0 → 5.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/LICENSE +21 -0
- package/bundle/index.js +465 -138
- package/bundle/index.js.map +7 -1
- package/dist/colorSchemes.js +11 -7
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/Checkbox2.js +3 -1
- package/dist/components/Checkbox2.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +7 -1
- package/dist/components/MSAViewer.js +11 -10
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/Track.js +8 -5
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +27 -23
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/dialogs/InterProScanDialog.js +2 -1
- package/dist/components/dialogs/InterProScanDialog.js.map +1 -1
- package/dist/components/header/MultiAlignmentSelector.js +0 -0
- package/dist/components/header/MultiAlignmentSelector.js.map +1 -1
- package/dist/components/msa/DomainLegend.d.ts +6 -0
- package/dist/components/msa/DomainLegend.js +41 -0
- package/dist/components/msa/DomainLegend.js.map +1 -0
- package/dist/components/msa/MSACanvasBlock.js +17 -5
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/MSAPanel.js +3 -1
- package/dist/components/msa/MSAPanel.js.map +1 -1
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js +58 -14
- package/dist/components/msa/renderBoxFeatureCanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +7 -9
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/msa/renderMSAMouseover.js +32 -4
- package/dist/components/msa/renderMSAMouseover.js.map +1 -1
- package/dist/components/renderCtx.d.ts +1 -1
- package/dist/components/tracks/renderTracksSvg.js +4 -4
- package/dist/components/tracks/renderTracksSvg.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +3 -0
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -1
- package/dist/createPaletteMap.d.ts +5 -2
- package/dist/createPaletteMap.js +15 -5
- package/dist/createPaletteMap.js.map +1 -1
- package/dist/hierarchy.js +4 -1
- package/dist/hierarchy.js.map +1 -1
- package/dist/launchInterProScan.d.ts +2 -0
- package/dist/launchInterProScan.js.map +1 -1
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model.d.ts +100 -3
- package/dist/model.js +121 -19
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.js +44 -30
- package/dist/neighborJoining.js.map +1 -1
- package/dist/renderToSvg.js +104 -74
- package/dist/renderToSvg.js.map +1 -1
- package/dist/{webpack.js → umd.js} +1 -1
- package/dist/umd.js.map +1 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -7
- package/src/colorSchemes.ts +12 -7
- package/src/components/Checkbox2.tsx +7 -1
- package/src/components/MSAViewer.tsx +31 -21
- package/src/components/Track.tsx +8 -5
- package/src/components/dialogs/FeatureDialog.tsx +62 -48
- package/src/components/dialogs/InterProScanDialog.tsx +2 -1
- package/src/components/header/MultiAlignmentSelector.tsx +0 -0
- package/src/components/msa/DomainLegend.tsx +74 -0
- package/src/components/msa/MSACanvasBlock.tsx +22 -4
- package/src/components/msa/MSAPanel.tsx +2 -0
- package/src/components/msa/renderBoxFeatureCanvasBlock.ts +73 -17
- package/src/components/msa/renderMSABlock.ts +5 -11
- package/src/components/msa/renderMSAMouseover.ts +32 -4
- package/src/components/renderCtx.ts +1 -0
- package/src/components/tracks/renderTracksSvg.ts +4 -4
- package/src/components/tree/renderTreeCanvas.ts +5 -1
- package/src/constants.ts +18 -0
- package/src/createPaletteMap.ts +18 -5
- package/src/hierarchy.ts +4 -1
- package/src/launchInterProScan.ts +3 -1
- package/src/model/msaModel.ts +3 -1
- package/src/model.ts +137 -36
- package/src/neighborJoining.ts +44 -31
- package/src/renderDomainLegendSvg.test.tsx +134 -0
- package/src/renderToSvg.tsx +210 -147
- package/src/segmentOverlay.test.ts +70 -0
- package/src/version.ts +1 -1
- package/bundle/index.js.LICENSE.txt +0 -100
- package/dist/components/util.d.ts +0 -1
- package/dist/components/util.js +0 -7
- package/dist/components/util.js.map +0 -1
- package/dist/webpack.js.map +0 -1
- package/src/components/util.ts +0 -9
- /package/dist/{webpack.d.ts → umd.d.ts} +0 -0
- /package/src/{webpack.ts → umd.ts} +0 -0
package/dist/model.d.ts
CHANGED
|
@@ -6,6 +6,14 @@ import type { Instance } from '@jbrowse/mobx-state-tree';
|
|
|
6
6
|
import type { Theme } from '@mui/material';
|
|
7
7
|
/**
|
|
8
8
|
* #stateModel MsaView
|
|
9
|
+
*
|
|
10
|
+
* The main MSAView state model. Holds the loaded alignment, tree, and optional
|
|
11
|
+
* InterProScan domain annotations, plus all display state (color scheme, zoom,
|
|
12
|
+
* scroll, collapsed clades). It composes in members from `DialogQueueSessionMixin`,
|
|
13
|
+
* `Tree`, and `MSAModel` (see Inherited members below). Data is loaded reactively
|
|
14
|
+
* from the `msaFilehandle` / `treeFilehandle` / `gffFilehandle` properties, or set
|
|
15
|
+
* directly with `setData`. Most state is persisted into the shareable URL.
|
|
16
|
+
*
|
|
9
17
|
* #example
|
|
10
18
|
* ```js
|
|
11
19
|
* import { MSAModelF } from 'react-msaview'
|
|
@@ -28,7 +36,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
28
36
|
bgColor: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
29
37
|
colorSchemeName: import("@jbrowse/mobx-state-tree").IType<string | undefined, string, string>;
|
|
30
38
|
msaFormat: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<import("msa-parsers").MSAFormat>>;
|
|
31
|
-
}, "type" | "id" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "currentAlignment" | "height" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo"> & {
|
|
39
|
+
}, "type" | "id" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "currentAlignment" | "height" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo" | "highlightColumns"> & {
|
|
32
40
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
33
41
|
showDomains: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
34
42
|
hideGaps: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
@@ -144,6 +152,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
144
152
|
}>, [undefined]>;
|
|
145
153
|
featureFilters: import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>>;
|
|
146
154
|
relativeTo: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
155
|
+
highlightColumns: import("@jbrowse/mobx-state-tree").IType<number[] | undefined, number[] | undefined, number[] | undefined>;
|
|
147
156
|
}, {
|
|
148
157
|
queueOfDialogs: [import("@jbrowse/core/util").DialogComponentType, any][];
|
|
149
158
|
} & {
|
|
@@ -262,10 +271,13 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
262
271
|
} & {
|
|
263
272
|
/**
|
|
264
273
|
* #action
|
|
274
|
+
* draw the alignment with positions numbered relative to the given row's
|
|
275
|
+
* sequence (its node id), instead of in raw MSA-column coordinates
|
|
265
276
|
*/
|
|
266
277
|
drawRelativeTo(id: string | undefined): void;
|
|
267
278
|
/**
|
|
268
279
|
* #action
|
|
280
|
+
* hide columns that are entirely (or mostly, see allowedGappyness) gaps
|
|
269
281
|
*/
|
|
270
282
|
setHideGaps(arg: boolean): void;
|
|
271
283
|
/**
|
|
@@ -320,6 +332,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
320
332
|
setHighlightedColumns(columns?: number[]): void;
|
|
321
333
|
/**
|
|
322
334
|
* #action
|
|
335
|
+
* toggle the InterProScan protein-domain overlay on the alignment
|
|
323
336
|
*/
|
|
324
337
|
setShowDomains(arg: boolean): void;
|
|
325
338
|
/**
|
|
@@ -353,14 +366,19 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
353
366
|
setCurrentAlignment(n: number): void;
|
|
354
367
|
/**
|
|
355
368
|
* #action
|
|
369
|
+
* collapse or un-collapse the subtree rooted at the given tree node id
|
|
356
370
|
*/
|
|
357
371
|
toggleCollapsed(node: string): void;
|
|
358
372
|
/**
|
|
359
373
|
* #action
|
|
374
|
+
* show only the subtree rooted at the given node id (pass undefined to
|
|
375
|
+
* show the whole tree again)
|
|
360
376
|
*/
|
|
361
377
|
setShowOnly(node?: string): void;
|
|
362
378
|
/**
|
|
363
379
|
* #action
|
|
380
|
+
* set the alignment/tree/metadata/domain data directly from strings,
|
|
381
|
+
* bypassing the filehandle loaders
|
|
364
382
|
*/
|
|
365
383
|
setData(data: {
|
|
366
384
|
msa?: string;
|
|
@@ -674,6 +692,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
674
692
|
calculateNeighborJoiningTreeFromMSA(): void;
|
|
675
693
|
/**
|
|
676
694
|
* #action
|
|
695
|
+
* restore the default column width and row height
|
|
677
696
|
*/
|
|
678
697
|
resetZoom(): void;
|
|
679
698
|
/**
|
|
@@ -852,32 +871,40 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
852
871
|
name: string;
|
|
853
872
|
accession: string;
|
|
854
873
|
description: string;
|
|
874
|
+
featureType: string | undefined;
|
|
855
875
|
start: number;
|
|
856
876
|
end: number;
|
|
877
|
+
strand: number | undefined;
|
|
857
878
|
}>;
|
|
858
879
|
readonly tidyInterProAnnotations: {
|
|
859
880
|
id: string;
|
|
860
881
|
name: string;
|
|
861
882
|
accession: string;
|
|
862
883
|
description: string;
|
|
884
|
+
featureType: string | undefined;
|
|
863
885
|
start: number;
|
|
864
886
|
end: number;
|
|
887
|
+
strand: number | undefined;
|
|
865
888
|
}[];
|
|
866
889
|
readonly tidyFilteredInterProAnnotations: {
|
|
867
890
|
id: string;
|
|
868
891
|
name: string;
|
|
869
892
|
accession: string;
|
|
870
893
|
description: string;
|
|
894
|
+
featureType: string | undefined;
|
|
871
895
|
start: number;
|
|
872
896
|
end: number;
|
|
897
|
+
strand: number | undefined;
|
|
873
898
|
}[];
|
|
874
899
|
readonly tidyFilteredGatheredInterProAnnotations: Record<string, {
|
|
875
900
|
id: string;
|
|
876
901
|
name: string;
|
|
877
902
|
accession: string;
|
|
878
903
|
description: string;
|
|
904
|
+
featureType: string | undefined;
|
|
879
905
|
start: number;
|
|
880
906
|
end: number;
|
|
907
|
+
strand: number | undefined;
|
|
881
908
|
}[]>;
|
|
882
909
|
} & {
|
|
883
910
|
/**
|
|
@@ -889,12 +916,81 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
889
916
|
* #getter
|
|
890
917
|
*/
|
|
891
918
|
readonly verticalScrollbarWidth: 0 | 20;
|
|
919
|
+
/**
|
|
920
|
+
* #getter
|
|
921
|
+
* ordinal segment types (exons etc.), ordered by sequence position so
|
|
922
|
+
* exon-1..exon-14 read left-to-right; colored by alternating shade and
|
|
923
|
+
* labeled by number rather than each getting a distinct hue + legend row
|
|
924
|
+
*/
|
|
925
|
+
readonly segmentDomainTypes: {
|
|
926
|
+
id: string;
|
|
927
|
+
name: string;
|
|
928
|
+
accession: string;
|
|
929
|
+
description: string;
|
|
930
|
+
featureType: string | undefined;
|
|
931
|
+
start: number;
|
|
932
|
+
end: number;
|
|
933
|
+
strand: number | undefined;
|
|
934
|
+
}[];
|
|
935
|
+
/**
|
|
936
|
+
* #getter
|
|
937
|
+
* categorical feature types (InterPro domains and the like) that each get
|
|
938
|
+
* their own color and a legend entry
|
|
939
|
+
*/
|
|
940
|
+
readonly categoricalDomainTypes: {
|
|
941
|
+
id: string;
|
|
942
|
+
name: string;
|
|
943
|
+
accession: string;
|
|
944
|
+
description: string;
|
|
945
|
+
featureType: string | undefined;
|
|
946
|
+
start: number;
|
|
947
|
+
end: number;
|
|
948
|
+
strand: number | undefined;
|
|
949
|
+
}[];
|
|
892
950
|
readonly fillPalette: {
|
|
893
|
-
[
|
|
951
|
+
[x: string]: string;
|
|
894
952
|
};
|
|
895
953
|
readonly strokePalette: {
|
|
896
954
|
[k: string]: string;
|
|
897
955
|
};
|
|
956
|
+
/**
|
|
957
|
+
* #getter
|
|
958
|
+
* accession -> number drawn on each segment band: the trailing number of
|
|
959
|
+
* the feature name ("exon-3" -> "3"), else its 1-based position
|
|
960
|
+
*/
|
|
961
|
+
readonly segmentLabels: Map<string, string>;
|
|
962
|
+
/**
|
|
963
|
+
* #getter
|
|
964
|
+
* the domain types currently drawn on the alignment (filtered-on), shared
|
|
965
|
+
* by the on-screen legend and the SVG export legend. Ordinal segments
|
|
966
|
+
* (exons) are excluded — they read as a numbered gene model, not a color
|
|
967
|
+
* key — so this is the categorical types ordered by sequence position
|
|
968
|
+
*/
|
|
969
|
+
readonly visibleDomainTypes: {
|
|
970
|
+
id: string;
|
|
971
|
+
name: string;
|
|
972
|
+
accession: string;
|
|
973
|
+
description: string;
|
|
974
|
+
featureType: string | undefined;
|
|
975
|
+
start: number;
|
|
976
|
+
end: number;
|
|
977
|
+
strand: number | undefined;
|
|
978
|
+
}[];
|
|
979
|
+
/**
|
|
980
|
+
* #getter
|
|
981
|
+
* domain annotations under the mouse, hit-tested against the exact visible
|
|
982
|
+
* column span each box is drawn at (so it matches the overlay across gaps)
|
|
983
|
+
*/
|
|
984
|
+
readonly mouseOverDomains: {
|
|
985
|
+
id: string;
|
|
986
|
+
name: string;
|
|
987
|
+
accession: string;
|
|
988
|
+
description: string;
|
|
989
|
+
featureType: string | undefined;
|
|
990
|
+
start: number;
|
|
991
|
+
end: number;
|
|
992
|
+
strand: number | undefined;
|
|
993
|
+
}[];
|
|
898
994
|
/**
|
|
899
995
|
* #method
|
|
900
996
|
*/
|
|
@@ -955,7 +1051,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
955
1051
|
bgColor: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
956
1052
|
colorSchemeName: import("@jbrowse/mobx-state-tree").IType<string | undefined, string, string>;
|
|
957
1053
|
msaFormat: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<import("msa-parsers").MSAFormat>>;
|
|
958
|
-
}, "type" | "id" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "currentAlignment" | "height" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo"> & {
|
|
1054
|
+
}, "type" | "id" | "data" | "showDomains" | "hideGaps" | "allowedGappyness" | "subFeatureRows" | "drawMsaLetters" | "scrollZoom" | "rowHeight" | "scrollY" | "scrollX" | "colWidth" | "currentAlignment" | "height" | "treeFilehandle" | "msaFilehandle" | "treeMetadataFilehandle" | "gffFilehandle" | "collapsed" | "showOnly" | "turnedOffTracks" | "featureFilters" | "relativeTo" | "highlightColumns"> & {
|
|
959
1055
|
id: import("@jbrowse/mobx-state-tree").IOptionalIType<import("@jbrowse/mobx-state-tree").ISimpleType<string>, [undefined]>;
|
|
960
1056
|
showDomains: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
961
1057
|
hideGaps: import("@jbrowse/mobx-state-tree").IType<boolean | undefined, boolean, boolean>;
|
|
@@ -1071,6 +1167,7 @@ declare function stateModelFactory(): import("@jbrowse/mobx-state-tree").IModelT
|
|
|
1071
1167
|
}>, [undefined]>;
|
|
1072
1168
|
featureFilters: import("@jbrowse/mobx-state-tree").IMapType<import("@jbrowse/mobx-state-tree").ISimpleType<boolean>>;
|
|
1073
1169
|
relativeTo: import("@jbrowse/mobx-state-tree").IMaybe<import("@jbrowse/mobx-state-tree").ISimpleType<string>>;
|
|
1170
|
+
highlightColumns: import("@jbrowse/mobx-state-tree").IType<number[] | undefined, number[] | undefined, number[] | undefined>;
|
|
1074
1171
|
}>, symbol>>;
|
|
1075
1172
|
export default stateModelFactory;
|
|
1076
1173
|
export type MsaViewStateModel = ReturnType<typeof stateModelFactory>;
|
package/dist/model.js
CHANGED
|
@@ -10,7 +10,7 @@ import { clustalXColumnColors } from "./clustalX.js";
|
|
|
10
10
|
import colorSchemes from "./colorSchemes.js";
|
|
11
11
|
import ConservationTrack from "./components/ConservationTrack.js";
|
|
12
12
|
import TextTrack from "./components/TextTrack.js";
|
|
13
|
-
import { defaultAllowedGappyness, defaultBgColor, defaultColWidth, defaultColorSchemeName, defaultCurrentAlignment, defaultDrawLabels, defaultDrawMsaLetters, defaultDrawNodeBubbles, defaultDrawTree, defaultHeight, defaultHideGaps, defaultLabelsAlignRight, defaultRowHeight, defaultScrollX, defaultScrollY, defaultScrollZoom, defaultShowBranchLen, defaultShowDomains, defaultSubFeatureRows, defaultTreeAreaWidth, defaultTreeWidth, maxCellSize, minColWidth, minRowHeight, } from "./constants.js";
|
|
13
|
+
import { defaultAllowedGappyness, defaultBgColor, defaultColWidth, defaultColorSchemeName, defaultCurrentAlignment, defaultDrawLabels, defaultDrawMsaLetters, defaultDrawNodeBubbles, defaultDrawTree, defaultHeight, defaultHideGaps, defaultLabelsAlignRight, defaultRowHeight, defaultScrollX, defaultScrollY, defaultScrollZoom, defaultShowBranchLen, defaultShowDomains, defaultSubFeatureRows, defaultTreeAreaWidth, defaultTreeWidth, maxCellSize, minColWidth, minRowHeight, segmentFeatureTypes, segmentShades, } from "./constants.js";
|
|
14
14
|
import { createPaletteMap } from "./createPaletteMap.js";
|
|
15
15
|
import { fetchTextWithProgress, isAbortError } from "./fetchUtils.js";
|
|
16
16
|
import { flatToTree } from "./flatToTree.js";
|
|
@@ -34,6 +34,14 @@ function parseTreeText(text) {
|
|
|
34
34
|
}
|
|
35
35
|
/**
|
|
36
36
|
* #stateModel MsaView
|
|
37
|
+
*
|
|
38
|
+
* The main MSAView state model. Holds the loaded alignment, tree, and optional
|
|
39
|
+
* InterProScan domain annotations, plus all display state (color scheme, zoom,
|
|
40
|
+
* scroll, collapsed clades). It composes in members from `DialogQueueSessionMixin`,
|
|
41
|
+
* `Tree`, and `MSAModel` (see Inherited members below). Data is loaded reactively
|
|
42
|
+
* from the `msaFilehandle` / `treeFilehandle` / `gffFilehandle` properties, or set
|
|
43
|
+
* directly with `setData`. Most state is persisted into the shareable URL.
|
|
44
|
+
*
|
|
37
45
|
* #example
|
|
38
46
|
* ```js
|
|
39
47
|
* import { MSAModelF } from 'react-msaview'
|
|
@@ -166,6 +174,15 @@ function stateModelFactory() {
|
|
|
166
174
|
* #property
|
|
167
175
|
*/
|
|
168
176
|
relativeTo: types.maybe(types.string),
|
|
177
|
+
/**
|
|
178
|
+
* #property
|
|
179
|
+
* declarative seed for the highlighted-columns overlay (visible column
|
|
180
|
+
* indices). Unlike the volatile `highlightedColumns` (driven by
|
|
181
|
+
* transient genome-hover sync), this persists in the snapshot/URL so a
|
|
182
|
+
* shared link can open with specific columns highlighted. Applied once
|
|
183
|
+
* in afterCreate.
|
|
184
|
+
*/
|
|
185
|
+
highlightColumns: types.frozen(),
|
|
169
186
|
}))
|
|
170
187
|
.volatile(() => ({
|
|
171
188
|
/**
|
|
@@ -260,12 +277,15 @@ function stateModelFactory() {
|
|
|
260
277
|
.actions(self => ({
|
|
261
278
|
/**
|
|
262
279
|
* #action
|
|
280
|
+
* draw the alignment with positions numbered relative to the given row's
|
|
281
|
+
* sequence (its node id), instead of in raw MSA-column coordinates
|
|
263
282
|
*/
|
|
264
283
|
drawRelativeTo(id) {
|
|
265
284
|
self.relativeTo = id;
|
|
266
285
|
},
|
|
267
286
|
/**
|
|
268
287
|
* #action
|
|
288
|
+
* hide columns that are entirely (or mostly, see allowedGappyness) gaps
|
|
269
289
|
*/
|
|
270
290
|
setHideGaps(arg) {
|
|
271
291
|
self.hideGaps = arg;
|
|
@@ -341,6 +361,7 @@ function stateModelFactory() {
|
|
|
341
361
|
},
|
|
342
362
|
/**
|
|
343
363
|
* #action
|
|
364
|
+
* toggle the InterProScan protein-domain overlay on the alignment
|
|
344
365
|
*/
|
|
345
366
|
setShowDomains(arg) {
|
|
346
367
|
self.showDomains = arg;
|
|
@@ -389,6 +410,7 @@ function stateModelFactory() {
|
|
|
389
410
|
},
|
|
390
411
|
/**
|
|
391
412
|
* #action
|
|
413
|
+
* collapse or un-collapse the subtree rooted at the given tree node id
|
|
392
414
|
*/
|
|
393
415
|
toggleCollapsed(node) {
|
|
394
416
|
if (self.collapsed.includes(node)) {
|
|
@@ -400,12 +422,16 @@ function stateModelFactory() {
|
|
|
400
422
|
},
|
|
401
423
|
/**
|
|
402
424
|
* #action
|
|
425
|
+
* show only the subtree rooted at the given node id (pass undefined to
|
|
426
|
+
* show the whole tree again)
|
|
403
427
|
*/
|
|
404
428
|
setShowOnly(node) {
|
|
405
429
|
self.showOnly = node;
|
|
406
430
|
},
|
|
407
431
|
/**
|
|
408
432
|
* #action
|
|
433
|
+
* set the alignment/tree/metadata/domain data directly from strings,
|
|
434
|
+
* bypassing the filehandle loaders
|
|
409
435
|
*/
|
|
410
436
|
setData(data) {
|
|
411
437
|
self.data = cast(data);
|
|
@@ -794,6 +820,9 @@ function stateModelFactory() {
|
|
|
794
820
|
const { colStats, colStatsSums } = this;
|
|
795
821
|
return colStats.map((stats, i) => {
|
|
796
822
|
const total = colStatsSums[i];
|
|
823
|
+
if (!total) {
|
|
824
|
+
return { letter: '', color: undefined };
|
|
825
|
+
}
|
|
797
826
|
let maxCount = 0;
|
|
798
827
|
let letter = '';
|
|
799
828
|
for (const [key, val] of Object.entries(stats)) {
|
|
@@ -1044,6 +1073,7 @@ function stateModelFactory() {
|
|
|
1044
1073
|
},
|
|
1045
1074
|
/**
|
|
1046
1075
|
* #action
|
|
1076
|
+
* restore the default column width and row height
|
|
1047
1077
|
*/
|
|
1048
1078
|
resetZoom() {
|
|
1049
1079
|
self.setColWidth(defaultColWidth);
|
|
@@ -1080,9 +1110,8 @@ function stateModelFactory() {
|
|
|
1080
1110
|
*/
|
|
1081
1111
|
zoomIn() {
|
|
1082
1112
|
transaction(() => {
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
self.scrollX = clamp(self.scrollX, self.maxScrollX, 0);
|
|
1113
|
+
this.zoomInHorizontal();
|
|
1114
|
+
this.zoomInVertical();
|
|
1086
1115
|
});
|
|
1087
1116
|
},
|
|
1088
1117
|
/**
|
|
@@ -1090,9 +1119,8 @@ function stateModelFactory() {
|
|
|
1090
1119
|
*/
|
|
1091
1120
|
zoomOut() {
|
|
1092
1121
|
transaction(() => {
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
self.scrollX = clamp(self.scrollX, self.maxScrollX, 0);
|
|
1122
|
+
this.zoomOutHorizontal();
|
|
1123
|
+
this.zoomOutVertical();
|
|
1096
1124
|
});
|
|
1097
1125
|
},
|
|
1098
1126
|
/**
|
|
@@ -1113,8 +1141,12 @@ function stateModelFactory() {
|
|
|
1113
1141
|
self.rowHeight = clamp(self.rowHeight * scaleFactor, minRowHeight, maxCellSize);
|
|
1114
1142
|
self.scrollX = clamp(offsetX - colInView * self.colWidth, self.maxScrollX, 0);
|
|
1115
1143
|
const anchoredScrollY = offsetY - rowInView * self.rowHeight;
|
|
1116
|
-
|
|
1117
|
-
|
|
1144
|
+
// maxScrollY is -(totalHeight - visibleMsaHeight) when the alignment
|
|
1145
|
+
// overflows, so -maxScrollY is exactly that overflow past the
|
|
1146
|
+
// scrollable MSA viewport (0 when it fits)
|
|
1147
|
+
const overflow = Math.max(0, -self.maxScrollY);
|
|
1148
|
+
const visibleHeight = self.totalHeight - overflow;
|
|
1149
|
+
const topBias = visibleHeight > 0 ? clamp(1 - overflow / visibleHeight, 0, 1) : 1;
|
|
1118
1150
|
self.scrollY = clamp(anchoredScrollY * (1 - topBias), self.maxScrollY, 0);
|
|
1119
1151
|
});
|
|
1120
1152
|
},
|
|
@@ -1356,13 +1388,15 @@ function stateModelFactory() {
|
|
|
1356
1388
|
.flatMap(([id, val]) => val.matches.flatMap(({ signature, locations }) => {
|
|
1357
1389
|
const { entry } = signature;
|
|
1358
1390
|
return entry
|
|
1359
|
-
? locations.map(({ start, end }) => ({
|
|
1391
|
+
? locations.map(({ start, end, strand }) => ({
|
|
1360
1392
|
id,
|
|
1361
1393
|
name: entry.name,
|
|
1362
1394
|
accession: entry.accession,
|
|
1363
1395
|
description: entry.description,
|
|
1396
|
+
featureType: entry.featureType,
|
|
1364
1397
|
start,
|
|
1365
1398
|
end,
|
|
1399
|
+
strand,
|
|
1366
1400
|
}))
|
|
1367
1401
|
: [];
|
|
1368
1402
|
}))
|
|
@@ -1391,8 +1425,32 @@ function stateModelFactory() {
|
|
|
1391
1425
|
get verticalScrollbarWidth() {
|
|
1392
1426
|
return self.showVerticalScrollbar ? 20 : 0;
|
|
1393
1427
|
},
|
|
1428
|
+
/**
|
|
1429
|
+
* #getter
|
|
1430
|
+
* ordinal segment types (exons etc.), ordered by sequence position so
|
|
1431
|
+
* exon-1..exon-14 read left-to-right; colored by alternating shade and
|
|
1432
|
+
* labeled by number rather than each getting a distinct hue + legend row
|
|
1433
|
+
*/
|
|
1434
|
+
get segmentDomainTypes() {
|
|
1435
|
+
return [...self.tidyInterProAnnotationTypes.values()]
|
|
1436
|
+
.filter(d => segmentFeatureTypes.has(d.featureType ?? ''))
|
|
1437
|
+
.toSorted((a, b) => a.start - b.start);
|
|
1438
|
+
},
|
|
1439
|
+
/**
|
|
1440
|
+
* #getter
|
|
1441
|
+
* categorical feature types (InterPro domains and the like) that each get
|
|
1442
|
+
* their own color and a legend entry
|
|
1443
|
+
*/
|
|
1444
|
+
get categoricalDomainTypes() {
|
|
1445
|
+
return [...self.tidyInterProAnnotationTypes.values()].filter(d => !segmentFeatureTypes.has(d.featureType ?? ''));
|
|
1446
|
+
},
|
|
1394
1447
|
get fillPalette() {
|
|
1395
|
-
|
|
1448
|
+
const segments = Object.fromEntries(this.segmentDomainTypes.map((d, i) => [
|
|
1449
|
+
d.accession,
|
|
1450
|
+
segmentShades[i % segmentShades.length],
|
|
1451
|
+
]));
|
|
1452
|
+
const categorical = createPaletteMap(this.categoricalDomainTypes.map(d => d.accession));
|
|
1453
|
+
return { ...segments, ...categorical };
|
|
1396
1454
|
},
|
|
1397
1455
|
get strokePalette() {
|
|
1398
1456
|
return transform(this.fillPalette, ([key, val]) => [
|
|
@@ -1400,6 +1458,50 @@ function stateModelFactory() {
|
|
|
1400
1458
|
colord(val).darken(0.1).toHex(),
|
|
1401
1459
|
]);
|
|
1402
1460
|
},
|
|
1461
|
+
/**
|
|
1462
|
+
* #getter
|
|
1463
|
+
* accession -> number drawn on each segment band: the trailing number of
|
|
1464
|
+
* the feature name ("exon-3" -> "3"), else its 1-based position
|
|
1465
|
+
*/
|
|
1466
|
+
get segmentLabels() {
|
|
1467
|
+
return new Map(this.segmentDomainTypes.map((d, i) => {
|
|
1468
|
+
const m = /(\d+)\s*$/.exec(d.name);
|
|
1469
|
+
return [d.accession, m ? m[1] : `${i + 1}`];
|
|
1470
|
+
}));
|
|
1471
|
+
},
|
|
1472
|
+
/**
|
|
1473
|
+
* #getter
|
|
1474
|
+
* the domain types currently drawn on the alignment (filtered-on), shared
|
|
1475
|
+
* by the on-screen legend and the SVG export legend. Ordinal segments
|
|
1476
|
+
* (exons) are excluded — they read as a numbered gene model, not a color
|
|
1477
|
+
* key — so this is the categorical types ordered by sequence position
|
|
1478
|
+
*/
|
|
1479
|
+
get visibleDomainTypes() {
|
|
1480
|
+
return this.categoricalDomainTypes
|
|
1481
|
+
.filter(d => self.featureFilters.get(d.accession))
|
|
1482
|
+
.toSorted((a, b) => a.start - b.start);
|
|
1483
|
+
},
|
|
1484
|
+
/**
|
|
1485
|
+
* #getter
|
|
1486
|
+
* domain annotations under the mouse, hit-tested against the exact visible
|
|
1487
|
+
* column span each box is drawn at (so it matches the overlay across gaps)
|
|
1488
|
+
*/
|
|
1489
|
+
get mouseOverDomains() {
|
|
1490
|
+
const { mouseCol } = self;
|
|
1491
|
+
const name = self.mouseOverRowName;
|
|
1492
|
+
if (name !== undefined && mouseCol !== undefined) {
|
|
1493
|
+
const entry = self.tidyFilteredGatheredInterProAnnotations[name] ?? [];
|
|
1494
|
+
return entry.filter(d => {
|
|
1495
|
+
const m1 = self.seqPosToVisibleCol(name, d.start - 1);
|
|
1496
|
+
const m2 = self.seqPosToVisibleCol(name, d.end);
|
|
1497
|
+
return (m1 !== undefined &&
|
|
1498
|
+
m2 !== undefined &&
|
|
1499
|
+
mouseCol >= m1 &&
|
|
1500
|
+
mouseCol < m2);
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1503
|
+
return [];
|
|
1504
|
+
},
|
|
1403
1505
|
/**
|
|
1404
1506
|
* #method
|
|
1405
1507
|
*/
|
|
@@ -1462,14 +1564,8 @@ function stateModelFactory() {
|
|
|
1462
1564
|
* #action
|
|
1463
1565
|
*/
|
|
1464
1566
|
fit() {
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
}
|
|
1468
|
-
if (self.numColumns > 0) {
|
|
1469
|
-
self.colWidth = clamp(self.msaAreaWidth / self.numColumns, minColWidth, maxCellSize);
|
|
1470
|
-
}
|
|
1471
|
-
self.scrollX = 0;
|
|
1472
|
-
self.scrollY = 0;
|
|
1567
|
+
this.fitVertically();
|
|
1568
|
+
this.fitHorizontally();
|
|
1473
1569
|
},
|
|
1474
1570
|
/**
|
|
1475
1571
|
* #action
|
|
@@ -1490,6 +1586,12 @@ function stateModelFactory() {
|
|
|
1490
1586
|
self.scrollX = 0;
|
|
1491
1587
|
},
|
|
1492
1588
|
afterCreate() {
|
|
1589
|
+
// seed the highlighted-columns overlay from the declarative property so
|
|
1590
|
+
// a shared snapshot/URL opens with those columns highlighted (the
|
|
1591
|
+
// volatile highlightedColumns can later be driven by genome-hover sync)
|
|
1592
|
+
if (self.highlightColumns?.length) {
|
|
1593
|
+
self.setHighlightedColumns(self.highlightColumns);
|
|
1594
|
+
}
|
|
1493
1595
|
addDisposer(self, autorun(() => {
|
|
1494
1596
|
for (const key of self.tidyInterProAnnotationTypes.keys()) {
|
|
1495
1597
|
this.initFilter(key);
|