react-msaview 3.1.5 → 3.1.7

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.
Files changed (40) hide show
  1. package/bundle/index.js +30 -39
  2. package/dist/DataModel.d.ts +34 -0
  3. package/dist/DataModel.js +46 -0
  4. package/dist/DataModel.js.map +1 -0
  5. package/dist/SelectedStructuresMixin.d.ts +46 -0
  6. package/dist/SelectedStructuresMixin.js +52 -0
  7. package/dist/SelectedStructuresMixin.js.map +1 -0
  8. package/dist/components/MSAPanel/MSABlock.js +32 -16
  9. package/dist/components/MSAPanel/MSABlock.js.map +1 -1
  10. package/dist/components/MSAPanel/renderMSAMouseover.js +14 -4
  11. package/dist/components/MSAPanel/renderMSAMouseover.js.map +1 -1
  12. package/dist/components/TreePanel/TreeNodeMenu.js +65 -55
  13. package/dist/components/TreePanel/TreeNodeMenu.js.map +1 -1
  14. package/dist/components/TreePanel/renderTreeCanvas.js +4 -3
  15. package/dist/components/TreePanel/renderTreeCanvas.js.map +1 -1
  16. package/dist/components/dialogs/SettingsDialog.js +41 -31
  17. package/dist/components/dialogs/SettingsDialog.js.map +1 -1
  18. package/dist/measureTextCanvas.d.ts +1 -1
  19. package/dist/measureTextCanvas.js +1 -1
  20. package/dist/measureTextCanvas.js.map +1 -1
  21. package/dist/model.d.ts +113 -108
  22. package/dist/model.js +61 -93
  23. package/dist/model.js.map +1 -1
  24. package/dist/util.d.ts +0 -1
  25. package/dist/util.js +0 -7
  26. package/dist/util.js.map +1 -1
  27. package/dist/version.d.ts +1 -1
  28. package/dist/version.js +1 -1
  29. package/package.json +1 -2
  30. package/src/DataModel.ts +46 -0
  31. package/src/SelectedStructuresMixin.ts +59 -0
  32. package/src/components/MSAPanel/MSABlock.tsx +33 -18
  33. package/src/components/MSAPanel/renderMSAMouseover.ts +16 -3
  34. package/src/components/TreePanel/TreeNodeMenu.tsx +93 -84
  35. package/src/components/TreePanel/renderTreeCanvas.ts +3 -2
  36. package/src/components/dialogs/SettingsDialog.tsx +128 -116
  37. package/src/measureTextCanvas.ts +1 -1
  38. package/src/model.ts +72 -109
  39. package/src/util.ts +0 -11
  40. package/src/version.ts +1 -1
package/src/model.ts CHANGED
@@ -1,10 +1,12 @@
1
1
  import React from 'react'
2
2
  import { autorun } from 'mobx'
3
- import { Instance, cast, types, addDisposer, SnapshotIn } from 'mobx-state-tree'
3
+ import { Instance, cast, types, addDisposer } from 'mobx-state-tree'
4
4
  import { hierarchy, cluster, HierarchyNode } from 'd3-hierarchy'
5
5
  import { ascending } from 'd3-array'
6
6
  import Stockholm from 'stockholm-js'
7
7
  import { saveAs } from 'file-saver'
8
+ import { Theme } from '@mui/material'
9
+
8
10
  // jbrowse
9
11
  import { FileLocation, ElementId } from '@jbrowse/core/util/types/mst'
10
12
  import { FileLocation as FileLocationType } from '@jbrowse/core/util/types'
@@ -16,7 +18,6 @@ import BaseViewModel from '@jbrowse/core/pluggableElementTypes/models/BaseViewMo
16
18
  import {
17
19
  clamp,
18
20
  collapse,
19
- filterHiddenLeafNodes,
20
21
  generateNodeIds,
21
22
  maxLength,
22
23
  setBrLength,
@@ -24,20 +25,26 @@ import {
24
25
  NodeWithIds,
25
26
  NodeWithIdsAndLength,
26
27
  } from './util'
28
+
29
+ import { blocksX, blocksY } from './calculateBlocks'
30
+ import { measureTextCanvas } from './measureTextCanvas'
31
+
32
+ // components
27
33
  import TextTrack from './components/TextTrack'
28
34
  import BoxTrack from './components/BoxTrack'
35
+
36
+ // parsers
29
37
  import ClustalMSA from './parsers/ClustalMSA'
30
38
  import StockholmMSA from './parsers/StockholmMSA'
31
39
  import FastaMSA from './parsers/FastaMSA'
32
40
  import parseNewick from './parseNewick'
33
41
  import colorSchemes from './colorSchemes'
42
+
43
+ // models
34
44
  import { UniprotTrack } from './UniprotTrack'
35
- import { StructureModel } from './StructureModel'
45
+ import { DataModelF } from './DataModel'
36
46
  import { DialogQueueSessionMixin } from './DialogQueue'
37
- import { renderToSvg } from './renderToSvg'
38
- import { Theme } from '@mui/material'
39
- import { blocksX, blocksY } from './calculateBlocks'
40
- import measureTextCanvas from './measureTextCanvas'
47
+ import { SelectedStructuresMixin } from './SelectedStructuresMixin'
41
48
 
42
49
  export interface RowDetails {
43
50
  [key: string]: unknown
@@ -82,16 +89,30 @@ export interface IBoxTrack {
82
89
 
83
90
  export type BasicTrack = IBoxTrack | ITextTrack
84
91
 
85
- export type StructureSnap = SnapshotIn<typeof StructureModel>
86
-
87
92
  /**
88
93
  * #stateModel MsaView
89
94
  * extends
90
95
  * - BaseViewModel
91
96
  * - DialogQueueSessionMixin
97
+ * - SelectedStructuresMixin
92
98
  */
93
99
  function x() {} // eslint-disable-line @typescript-eslint/no-unused-vars
94
100
 
101
+ function reparseTree(tree: NodeWithIds): NodeWithIds {
102
+ return {
103
+ ...tree,
104
+ branchset: tree.branchset.map(r =>
105
+ r.branchset.length
106
+ ? reparseTree(r)
107
+ : {
108
+ branchset: [r],
109
+ id: `${r.id}-leafnode`,
110
+ name: `${r.name}-hidden`,
111
+ },
112
+ ),
113
+ }
114
+ }
115
+
95
116
  export type DialogComponentType =
96
117
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
97
118
  | React.LazyExoticComponent<React.FC<any>>
@@ -102,6 +123,7 @@ const model = types
102
123
  .compose(
103
124
  BaseViewModel,
104
125
  DialogQueueSessionMixin(),
126
+ SelectedStructuresMixin(),
105
127
  types.model('MsaView', {
106
128
  /**
107
129
  * #property
@@ -157,12 +179,6 @@ const model = types
157
179
  */
158
180
  scrollX: 0,
159
181
 
160
- /**
161
- * #property
162
- * currently "selected" structures, generally PDB 3-D protein structures
163
- */
164
- selectedStructures: types.array(StructureModel),
165
-
166
182
  /**
167
183
  * #property
168
184
  * right-align the labels
@@ -244,12 +260,7 @@ const model = types
244
260
  */
245
261
  collapsed: types.array(types.string),
246
262
 
247
- /**
248
- * #property
249
- * array of leaf nodes that are 'hidden', similar to collapsed but for leaf nodes
250
- */
251
- hidden: types.array(types.string),
252
-
263
+ collapsed2: types.array(types.string),
253
264
  /**
254
265
  * #property
255
266
  * focus on particular subtree
@@ -274,26 +285,7 @@ const model = types
274
285
  * data from the loaded tree/msa/treeMetadata, generally loaded by
275
286
  * autorun
276
287
  */
277
- data: types.optional(
278
- types
279
- .model({
280
- tree: types.maybe(types.string),
281
- msa: types.maybe(types.string),
282
- treeMetadata: types.maybe(types.string),
283
- })
284
- .actions(self => ({
285
- setTree(tree?: string) {
286
- self.tree = tree
287
- },
288
- setMSA(msa?: string) {
289
- self.msa = msa
290
- },
291
- setTreeMetadata(treeMetadata?: string) {
292
- self.treeMetadata = treeMetadata
293
- },
294
- })),
295
- { tree: '', msa: '' },
296
- ),
288
+ data: types.optional(DataModelF(), { tree: '', msa: '' }),
297
289
  }),
298
290
  )
299
291
  .volatile(() => ({
@@ -321,6 +313,18 @@ const model = types
321
313
  */
322
314
  mouseCol: undefined as number | undefined,
323
315
 
316
+ /**
317
+ * #volatile
318
+ * the currently mouse-click row
319
+ */
320
+ mouseClickRow: undefined as number | undefined,
321
+
322
+ /**
323
+ * #volatile
324
+ * the currently mouse-click column
325
+ */
326
+ mouseClickCol: undefined as number | undefined,
327
+
324
328
  /**
325
329
  * #volatile
326
330
  * a dummy variable that is incremented when ref changes so autorun for
@@ -357,49 +361,6 @@ const model = types
357
361
  self.height = height
358
362
  },
359
363
 
360
- /**
361
- * #action
362
- * add to the selected structures
363
- */
364
- addStructureToSelection(elt: StructureSnap) {
365
- self.selectedStructures.push(elt)
366
- },
367
-
368
- /**
369
- * #action
370
- * remove from the selected structures
371
- */
372
- removeStructureFromSelection(elt: StructureSnap) {
373
- const r = self.selectedStructures.find(node => node.id === elt.id)
374
- if (r) {
375
- self.selectedStructures.remove(r)
376
- }
377
- },
378
-
379
- /**
380
- * #action
381
- * toggle a structure from the selected structures list
382
- */
383
- toggleStructureSelection(elt: {
384
- id: string
385
- structure: { startPos: number; endPos: number; pdb: string }
386
- }) {
387
- const r = self.selectedStructures.find(node => node.id === elt.id)
388
- if (r) {
389
- self.selectedStructures.remove(r)
390
- } else {
391
- self.selectedStructures.push(elt)
392
- }
393
- },
394
-
395
- /**
396
- * #action
397
- * clear all selected structures
398
- */
399
- clearSelectedStructures() {
400
- self.selectedStructures = cast([])
401
- },
402
-
403
364
  /**
404
365
  * #action
405
366
  * set error state
@@ -417,6 +378,15 @@ const model = types
417
378
  self.mouseRow = row
418
379
  },
419
380
 
381
+ /**
382
+ * #action
383
+ * set mouse click position (row, column) in the MSA
384
+ */
385
+ setMouseClickPos(col?: number, row?: number) {
386
+ self.mouseClickCol = col
387
+ self.mouseClickRow = row
388
+ },
389
+
420
390
  /**
421
391
  * #action
422
392
  * set row height (px)
@@ -493,20 +463,6 @@ const model = types
493
463
  self.drawTree = arg
494
464
  },
495
465
 
496
- /**
497
- * #action
498
- */
499
- hideNode(arg: string) {
500
- self.hidden.push(arg)
501
- },
502
-
503
- /**
504
- * #action
505
- */
506
- clearHidden() {
507
- self.hidden.clear()
508
- },
509
-
510
466
  /**
511
467
  * #action
512
468
  */
@@ -518,6 +474,16 @@ const model = types
518
474
  }
519
475
  },
520
476
 
477
+ /**
478
+ * #action
479
+ */
480
+ toggleCollapsed2(node: string) {
481
+ if (self.collapsed2.includes(node)) {
482
+ self.collapsed2.remove(node)
483
+ } else {
484
+ self.collapsed2.push(node)
485
+ }
486
+ },
521
487
  /**
522
488
  * #action
523
489
  */
@@ -680,7 +646,7 @@ const model = types
680
646
  * #getter
681
647
  */
682
648
  get _tree(): NodeWithIds {
683
- return self.data.tree
649
+ const ret = self.data.tree
684
650
  ? generateNodeIds(parseNewick(self.data.tree))
685
651
  : this.MSA?.getTree() || {
686
652
  noTree: true,
@@ -688,6 +654,7 @@ const model = types
688
654
  id: 'empty',
689
655
  name: 'empty',
690
656
  }
657
+ return reparseTree(ret)
691
658
  },
692
659
  /**
693
660
  * #getter
@@ -726,18 +693,13 @@ const model = types
726
693
  }
727
694
  }
728
695
 
729
- if (self.collapsed.length) {
730
- self.collapsed
696
+ if (self.collapsed.length || self.collapsed2.length) {
697
+ ;[...self.collapsed, ...self.collapsed2]
731
698
  .map(collapsedId => hier.find(node => node.data.id === collapsedId))
732
699
  .filter(notEmpty)
733
700
  .map(node => collapse(node))
734
701
  }
735
- if (self.hidden.length) {
736
- self.hidden
737
- .map(hiddenId => hier.find(node => node.data.id === hiddenId))
738
- .filter(notEmpty)
739
- .map(node => filterHiddenLeafNodes(node.parent, node.id))
740
- }
702
+
741
703
  return hier
742
704
  },
743
705
  /**
@@ -1160,7 +1122,7 @@ const model = types
1160
1122
  relativePxToBp(rowName: string, position: number) {
1161
1123
  const { rowNames, rows } = self
1162
1124
  const index = rowNames.indexOf(rowName)
1163
- if (index !== -1) {
1125
+ if (index !== -1 && rows[index]) {
1164
1126
  const row = rows[index][1]
1165
1127
 
1166
1128
  let k = 0
@@ -1182,7 +1144,7 @@ const model = types
1182
1144
  relativePxToBp2(rowName: string, position: number) {
1183
1145
  const { rowNames, rows } = self
1184
1146
  const index = rowNames.indexOf(rowName)
1185
- if (index !== -1) {
1147
+ if (index !== -1 && rows[index]) {
1186
1148
  const row = rows[index][1]
1187
1149
 
1188
1150
  let k = 0
@@ -1231,6 +1193,7 @@ const model = types
1231
1193
  includeMinimap?: boolean
1232
1194
  exportType: string
1233
1195
  }) {
1196
+ const { renderToSvg } = await import('./renderToSvg')
1234
1197
  const html = await renderToSvg(self as MsaViewModel, opts)
1235
1198
  const blob = new Blob([html], { type: 'image/svg+xml' })
1236
1199
  saveAs(blob, 'image.svg')
package/src/util.ts CHANGED
@@ -145,17 +145,6 @@ export function collapse(d: HierarchyNode<NodeWithIds>) {
145
145
  }
146
146
  }
147
147
 
148
- // Collapse the node and all it's children, from
149
- // https://bl.ocks.org/d3noob/43a860bc0024792f8803bba8ca0d5ecd
150
- export function filterHiddenLeafNodes(
151
- d: HierarchyNode<NodeWithIds> | null,
152
- hiddenId?: string,
153
- ) {
154
- if (d?.children) {
155
- d.children = d.children.filter(f => f.id !== hiddenId)
156
- }
157
- }
158
-
159
148
  export function clamp(min: number, num: number, max: number) {
160
149
  return Math.min(Math.max(num, min), max)
161
150
  }
package/src/version.ts CHANGED
@@ -1 +1 @@
1
- export const version = '3.1.5'
1
+ export const version = '3.1.7'