react-msaview 8.1.0 → 8.3.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/bundle/index.js +104 -117
- package/bundle/index.js.map +4 -4
- package/dist/columnCounts.d.ts +4 -3
- package/dist/columnCounts.js +11 -6
- package/dist/columnCounts.js.map +1 -1
- package/dist/components/CopyButton.d.ts +1 -1
- package/dist/components/CopyButton.js +1 -1
- package/dist/components/CopyButton.js.map +1 -1
- package/dist/components/DragHandle.js +14 -2
- package/dist/components/DragHandle.js.map +1 -1
- package/dist/components/Loading.js +10 -11
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAViewer.d.ts +12 -1
- package/dist/components/MSAViewer.js +12 -1
- package/dist/components/MSAViewer.js.map +1 -1
- package/dist/components/SequenceTextArea.d.ts +11 -0
- package/dist/components/SequenceTextArea.js +40 -8
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/StatusMessage.d.ts +12 -0
- package/dist/components/StatusMessage.js +43 -0
- package/dist/components/StatusMessage.js.map +1 -0
- package/dist/components/Track.js +3 -3
- package/dist/components/Track.js.map +1 -1
- package/dist/components/VerticalScrollbar.js +6 -1
- package/dist/components/VerticalScrollbar.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.d.ts +3 -2
- package/dist/components/dialogs/ExportSVGDialog.js +4 -2
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/dialogs/FeatureDialog.js +15 -10
- package/dist/components/dialogs/FeatureDialog.js.map +1 -1
- package/dist/components/getVisibleLeaves.d.ts +1 -1
- package/dist/components/header/FileMenu.js +9 -0
- package/dist/components/header/FileMenu.js.map +1 -1
- package/dist/components/header/GappynessSlider.js +15 -3
- package/dist/components/header/GappynessSlider.js.map +1 -1
- package/dist/components/header/Header.js +6 -7
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/{HeaderStatusArea.d.ts → RowSearch.d.ts} +2 -2
- package/dist/components/header/RowSearch.js +15 -0
- package/dist/components/header/RowSearch.js.map +1 -0
- package/dist/components/header/revealRow.d.ts +3 -0
- package/dist/components/header/revealRow.js +15 -0
- package/dist/components/header/revealRow.js.map +1 -0
- package/dist/components/header/settingsMenuItems.js +57 -1
- package/dist/components/header/settingsMenuItems.js.map +1 -1
- package/dist/components/import/ImportForm.js +10 -4
- package/dist/components/import/ImportForm.js.map +1 -1
- package/dist/components/import/ImportFormExamples.js +19 -27
- package/dist/components/import/ImportFormExamples.js.map +1 -1
- package/dist/components/minimap/Minimap.js +6 -1
- package/dist/components/minimap/Minimap.js.map +1 -1
- package/dist/components/msa/AnnotationLegend.js +11 -5
- package/dist/components/msa/AnnotationLegend.js.map +1 -1
- package/dist/components/msa/MSACanvas.js +6 -1
- package/dist/components/msa/MSACanvas.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +3 -7
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/msaKeys.d.ts +5 -0
- package/dist/components/msa/msaKeys.js +35 -0
- package/dist/components/msa/msaKeys.js.map +1 -0
- package/dist/components/msa/useMsaBlockMouse.d.ts +2 -4
- package/dist/components/msa/useMsaBlockMouse.js +18 -5
- package/dist/components/msa/useMsaBlockMouse.js.map +1 -1
- package/dist/components/rowpanels/RowPanelBlock.js +10 -14
- package/dist/components/rowpanels/RowPanelBlock.js.map +1 -1
- package/dist/components/tracks/drawTracks.d.ts +1 -0
- package/dist/components/tracks/drawTracks.js +14 -2
- package/dist/components/tracks/drawTracks.js.map +1 -1
- package/dist/components/tracks/useTrackHover.d.ts +1 -5
- package/dist/components/tracks/useTrackHover.js +5 -5
- package/dist/components/tracks/useTrackHover.js.map +1 -1
- package/dist/components/tree/ScaleBarSVG.d.ts +14 -0
- package/dist/components/tree/ScaleBarSVG.js +11 -0
- package/dist/components/tree/ScaleBarSVG.js.map +1 -0
- package/dist/components/tree/TreeCanvas.js +8 -26
- package/dist/components/tree/TreeCanvas.js.map +1 -1
- package/dist/components/tree/TreeCanvasBlock.js +11 -20
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/{TreeBranchMenu.d.ts → TreeMenu.d.ts} +5 -4
- package/dist/components/tree/TreeMenu.js +48 -0
- package/dist/components/tree/TreeMenu.js.map +1 -0
- package/dist/components/tree/TreeRuler.js +3 -3
- package/dist/components/tree/TreeRuler.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +19 -9
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/components/tree/renderTreeMouseover.d.ts +5 -0
- package/dist/components/tree/renderTreeMouseover.js +20 -0
- package/dist/components/tree/renderTreeMouseover.js.map +1 -0
- package/dist/components/tree/useTreeHover.d.ts +3 -8
- package/dist/components/tree/useTreeHover.js +8 -10
- package/dist/components/tree/useTreeHover.js.map +1 -1
- package/dist/components/useHoverAnchor.d.ts +19 -0
- package/dist/components/useHoverAnchor.js +18 -0
- package/dist/components/useHoverAnchor.js.map +1 -0
- package/dist/constants.d.ts +4 -1
- package/dist/constants.js +12 -3
- package/dist/constants.js.map +1 -1
- package/dist/expandSpec.d.ts +46 -0
- package/dist/expandSpec.js +127 -0
- package/dist/expandSpec.js.map +1 -0
- package/dist/exportFileName.d.ts +3 -3
- package/dist/exportFileName.js +4 -4
- package/dist/exportFileName.js.map +1 -1
- package/dist/hierarchy.d.ts +51 -0
- package/dist/hierarchy.js +125 -0
- package/dist/hierarchy.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/model/treeModel.d.ts +12 -0
- package/dist/model/treeModel.js +14 -1
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +188 -47
- package/dist/model.js +482 -192
- package/dist/model.js.map +1 -1
- package/dist/renderToSvg.js +2 -4
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rerootTree.d.ts +33 -0
- package/dist/rerootTree.js +144 -0
- package/dist/rerootTree.js.map +1 -0
- package/dist/svgTestUtil.d.ts +114 -20
- package/dist/types.d.ts +25 -12
- package/dist/useMsaSvgFigure.d.ts +2 -1
- package/dist/useMsaSvgFigure.js +11 -4
- package/dist/useMsaSvgFigure.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/writeNewick.d.ts +8 -0
- package/dist/writeNewick.js +34 -0
- package/dist/writeNewick.js.map +1 -0
- package/package.json +3 -3
- package/src/columnCounts.ts +14 -6
- package/src/components/CopyButton.tsx +2 -2
- package/src/components/DragHandle.tsx +21 -1
- package/src/components/Loading.tsx +14 -30
- package/src/components/MSAViewer.tsx +26 -0
- package/src/components/SequenceTextArea.tsx +54 -8
- package/src/components/StatusMessage.tsx +70 -0
- package/src/components/Track.tsx +8 -4
- package/src/components/VerticalScrollbar.tsx +7 -0
- package/src/components/dialogs/ExportSVGDialog.tsx +5 -2
- package/src/components/dialogs/FeatureDialog.tsx +59 -38
- package/src/components/header/FileMenu.tsx +9 -0
- package/src/components/header/GappynessSlider.tsx +17 -4
- package/src/components/header/Header.tsx +7 -8
- package/src/components/header/RowSearch.tsx +34 -0
- package/src/components/header/revealRow.ts +17 -0
- package/src/components/header/settingsMenuItems.ts +66 -0
- package/src/components/import/ImportForm.tsx +14 -7
- package/src/components/import/ImportFormExamples.tsx +20 -28
- package/src/components/minimap/Minimap.tsx +7 -0
- package/src/components/msa/AnnotationLegend.tsx +12 -6
- package/src/components/msa/MSACanvas.tsx +8 -0
- package/src/components/msa/MSACanvasBlock.tsx +5 -11
- package/src/components/msa/msaKeys.ts +39 -0
- package/src/components/msa/useMsaBlockMouse.ts +23 -7
- package/src/components/rowpanels/RowPanelBlock.tsx +16 -23
- package/src/components/tracks/drawTracks.ts +15 -2
- package/src/components/tracks/useTrackHover.ts +5 -5
- package/src/components/tree/ScaleBarSVG.tsx +30 -0
- package/src/components/tree/TreeCanvas.tsx +9 -40
- package/src/components/tree/TreeCanvasBlock.tsx +19 -39
- package/src/components/tree/TreeMenu.tsx +129 -0
- package/src/components/tree/TreeRuler.tsx +7 -13
- package/src/components/tree/renderTreeCanvas.ts +20 -8
- package/src/components/tree/renderTreeMouseover.ts +41 -0
- package/src/components/tree/useTreeHover.ts +8 -17
- package/src/components/useHoverAnchor.ts +31 -0
- package/src/constants.ts +14 -3
- package/src/expandSpec.ts +196 -0
- package/src/exportFileName.ts +4 -3
- package/src/hierarchy.ts +151 -4
- package/src/index.ts +11 -1
- package/src/model/treeModel.ts +22 -0
- package/src/model.ts +588 -221
- package/src/renderToSvg.tsx +6 -9
- package/src/rerootTree.ts +172 -0
- package/src/types.ts +34 -12
- package/src/useMsaSvgFigure.ts +11 -4
- package/src/version.ts +1 -1
- package/src/writeNewick.ts +38 -0
- package/dist/components/PortalTooltip.d.ts +0 -11
- package/dist/components/PortalTooltip.js +0 -29
- package/dist/components/PortalTooltip.js.map +0 -1
- package/dist/components/header/HeaderStatusArea.js +0 -21
- package/dist/components/header/HeaderStatusArea.js.map +0 -1
- package/dist/components/tree/TreeBranchMenu.js +0 -29
- package/dist/components/tree/TreeBranchMenu.js.map +0 -1
- package/dist/components/tree/TreeNodeMenu.d.ts +0 -13
- package/dist/components/tree/TreeNodeMenu.js +0 -41
- package/dist/components/tree/TreeNodeMenu.js.map +0 -1
- package/src/components/PortalTooltip.tsx +0 -47
- package/src/components/header/HeaderStatusArea.tsx +0 -32
- package/src/components/tree/TreeBranchMenu.tsx +0 -68
- package/src/components/tree/TreeNodeMenu.tsx +0 -95
package/src/renderToSvg.tsx
CHANGED
|
@@ -14,6 +14,7 @@ import { visibleColRange } from './components/msa/visibleColRange.ts'
|
|
|
14
14
|
import { headerRunsAcross } from './components/rowpanels/headerLayout.ts'
|
|
15
15
|
import { renderRowPanels } from './components/rowpanels/renderRowPanel.ts'
|
|
16
16
|
import { renderAllTracks } from './components/tracks/drawTracks.ts'
|
|
17
|
+
import ScaleBarSVG from './components/tree/ScaleBarSVG.tsx'
|
|
17
18
|
import {
|
|
18
19
|
bracketGap,
|
|
19
20
|
cladeHeight,
|
|
@@ -323,17 +324,13 @@ function TreeScaleBarSVG({
|
|
|
323
324
|
if (!bar) {
|
|
324
325
|
return null
|
|
325
326
|
}
|
|
326
|
-
const y = treeOverviewHeight + treeScaleBarHeight
|
|
327
|
-
const color = theme.palette.text.primary
|
|
328
327
|
return (
|
|
329
328
|
<g id="tree-scalebar">
|
|
330
|
-
<
|
|
331
|
-
{bar
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
fill="none"
|
|
336
|
-
stroke={color}
|
|
329
|
+
<ScaleBarSVG
|
|
330
|
+
bar={bar}
|
|
331
|
+
marginLeft={marginLeft}
|
|
332
|
+
y={treeOverviewHeight + treeScaleBarHeight}
|
|
333
|
+
color={theme.palette.text.primary}
|
|
337
334
|
/>
|
|
338
335
|
</g>
|
|
339
336
|
)
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rerooting over the plain node `parseNewick` produces, the shape
|
|
3
|
+
* `@gmod/newick` and jbrowse-components' tree sidebar share, so these can move
|
|
4
|
+
* into that package unchanged.
|
|
5
|
+
*
|
|
6
|
+
* Every traversal is iterative, for the reason the ones in `@gmod/newick` are: a
|
|
7
|
+
* caterpillar tree is as deep as it has leaves, and recursion overflows the
|
|
8
|
+
* stack past about 5000 of them.
|
|
9
|
+
*/
|
|
10
|
+
export interface TreeNode {
|
|
11
|
+
name?: string
|
|
12
|
+
length?: number
|
|
13
|
+
children?: TreeNode[]
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function preorder<N extends TreeNode>(root: N) {
|
|
17
|
+
const order: N[] = []
|
|
18
|
+
const parents = new Map<N, N>()
|
|
19
|
+
const stack = [root]
|
|
20
|
+
while (stack.length > 0) {
|
|
21
|
+
const node = stack.pop()!
|
|
22
|
+
order.push(node)
|
|
23
|
+
for (const child of (node.children ?? []) as N[]) {
|
|
24
|
+
parents.set(child, node)
|
|
25
|
+
stack.push(child)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return { order, parents }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function hasLengths(order: TreeNode[]) {
|
|
32
|
+
return order.some(n => n.length !== undefined)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// the root's two children make one branch of the unrooted tree, which is the
|
|
36
|
+
// branch a rerooting at either of them splits
|
|
37
|
+
function mergedSibling<N extends TreeNode>(root: N, target: N) {
|
|
38
|
+
return root.children?.length === 2
|
|
39
|
+
? (root.children.find(c => c !== target) as N | undefined)
|
|
40
|
+
: undefined
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The tree rooted on the branch above `target`, `offset` up from it, or at the
|
|
45
|
+
* middle of that branch without one. Where the root has two children, their
|
|
46
|
+
* branches are one branch of the unrooted tree, and `offset` runs across both.
|
|
47
|
+
*
|
|
48
|
+
* The nodes between `target` and the old root turn over. A name on one of them
|
|
49
|
+
* labels the branch above it, which is where a support value sits, so the name
|
|
50
|
+
* follows that branch to the node now at its lower end. A two-child root has
|
|
51
|
+
* nothing left to split once one child leaves, so it drops out and its
|
|
52
|
+
* branches join.
|
|
53
|
+
*/
|
|
54
|
+
export function rerootTree<N extends TreeNode>(
|
|
55
|
+
root: N,
|
|
56
|
+
target: N,
|
|
57
|
+
offset?: number,
|
|
58
|
+
): TreeNode {
|
|
59
|
+
const { order, parents } = preorder(root)
|
|
60
|
+
if (!parents.has(target)) {
|
|
61
|
+
return root
|
|
62
|
+
}
|
|
63
|
+
const lengths = hasLengths(order)
|
|
64
|
+
const sibling =
|
|
65
|
+
parents.get(target) === root ? mergedSibling(root, target) : undefined
|
|
66
|
+
const branch = (target.length ?? 0) + (sibling?.length ?? 0)
|
|
67
|
+
const at = Math.min(Math.max(offset ?? branch / 2, 0), branch)
|
|
68
|
+
const length = (n: number) => (lengths ? n : undefined)
|
|
69
|
+
|
|
70
|
+
const path = [target]
|
|
71
|
+
for (let n = parents.get(target); n; n = parents.get(n)) {
|
|
72
|
+
path.push(n)
|
|
73
|
+
}
|
|
74
|
+
// Built from the old root down, so the node each turned node now hangs
|
|
75
|
+
// `above` it already exists. undefined where the old root dropped out.
|
|
76
|
+
let above: TreeNode | undefined
|
|
77
|
+
for (let i = path.length - 1; i >= 1; i--) {
|
|
78
|
+
const node = path[i]!
|
|
79
|
+
const below = path[i - 1]!
|
|
80
|
+
const children = node.children!.filter(c => c !== below)
|
|
81
|
+
if (above) {
|
|
82
|
+
children.push(above)
|
|
83
|
+
}
|
|
84
|
+
if (children.length === 0) {
|
|
85
|
+
above = undefined
|
|
86
|
+
} else if (i === path.length - 1 && children.length === 1) {
|
|
87
|
+
const only = children[0]!
|
|
88
|
+
above = {
|
|
89
|
+
...only,
|
|
90
|
+
length: length(
|
|
91
|
+
(only.length ?? 0) + (below.length ?? 0) - (i === 1 ? at : 0),
|
|
92
|
+
),
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
above = {
|
|
96
|
+
...node,
|
|
97
|
+
name: i === 1 ? undefined : below.name,
|
|
98
|
+
children,
|
|
99
|
+
length: length((below.length ?? 0) - (i === 1 ? at : 0)),
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
children: [{ ...target, length: length(at) }, ...(above ? [above] : [])],
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The tree rooted halfway along the longest path between two tips, which is
|
|
110
|
+
* where a clock would put the root: the usual choice for the unrooted tree
|
|
111
|
+
* FastTree, IQ-TREE or neighbor joining writes. A tree with no branch lengths
|
|
112
|
+
* counts branches.
|
|
113
|
+
*/
|
|
114
|
+
export function midpointRoot<N extends TreeNode>(root: N): TreeNode {
|
|
115
|
+
const { order, parents } = preorder(root)
|
|
116
|
+
const tips = order.filter(n => !n.children?.length)
|
|
117
|
+
if (tips.length < 2) {
|
|
118
|
+
return root
|
|
119
|
+
}
|
|
120
|
+
const lengths = hasLengths(order)
|
|
121
|
+
const weight = (n: N) => (lengths ? (n.length ?? 0) : 1)
|
|
122
|
+
|
|
123
|
+
// distance from `from` to every node over the unrooted tree, and the
|
|
124
|
+
// neighbor each was reached through
|
|
125
|
+
function reach(from: N) {
|
|
126
|
+
const dist = new Map<N, number>([[from, 0]])
|
|
127
|
+
const via = new Map<N, N>()
|
|
128
|
+
const stack = [from]
|
|
129
|
+
while (stack.length > 0) {
|
|
130
|
+
const node = stack.pop()!
|
|
131
|
+
const d = dist.get(node)!
|
|
132
|
+
const parent = parents.get(node)
|
|
133
|
+
if (parent && !dist.has(parent)) {
|
|
134
|
+
dist.set(parent, d + weight(node))
|
|
135
|
+
via.set(parent, node)
|
|
136
|
+
stack.push(parent)
|
|
137
|
+
}
|
|
138
|
+
for (const child of (node.children ?? []) as N[]) {
|
|
139
|
+
if (!dist.has(child)) {
|
|
140
|
+
dist.set(child, d + weight(child))
|
|
141
|
+
via.set(child, node)
|
|
142
|
+
stack.push(child)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return { dist, via }
|
|
147
|
+
}
|
|
148
|
+
function farthest(dist: Map<N, number>) {
|
|
149
|
+
return tips.reduce((best, tip) =>
|
|
150
|
+
dist.get(tip)! > dist.get(best)! ? tip : best,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const a = farthest(reach(tips[0]!).dist)
|
|
155
|
+
const { dist, via } = reach(a)
|
|
156
|
+
const b = farthest(dist)
|
|
157
|
+
if (b === a) {
|
|
158
|
+
return root
|
|
159
|
+
}
|
|
160
|
+
const half = dist.get(b)! / 2
|
|
161
|
+
let node = b
|
|
162
|
+
let next = via.get(node)!
|
|
163
|
+
while (dist.get(next)! > half) {
|
|
164
|
+
node = next
|
|
165
|
+
next = via.get(node)!
|
|
166
|
+
}
|
|
167
|
+
// the midpoint lies on the branch between `node` and `next`, and whichever
|
|
168
|
+
// of them is the child carries that branch
|
|
169
|
+
return parents.get(node) === next
|
|
170
|
+
? rerootTree(root, node, dist.get(node)! - half)
|
|
171
|
+
: rerootTree(root, next, half - dist.get(next)!)
|
|
172
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -327,10 +327,36 @@ export interface Highlight {
|
|
|
327
327
|
/**
|
|
328
328
|
* What the viewer draws over a clade. `highlight` fills the rows behind it,
|
|
329
329
|
* across the tree and the alignment. `bracket` draws a bar and the clade's
|
|
330
|
-
* `label` in the gutter right of the tip labels. `collapse
|
|
331
|
-
* the collapsed list
|
|
330
|
+
* `label` in the gutter right of the tip labels. `collapse`, `focus` and
|
|
331
|
+
* `rotate` seed the collapsed list, the subtree in focus and the rotated nodes
|
|
332
|
+
* at load.
|
|
332
333
|
*/
|
|
333
|
-
export type CladeMark =
|
|
334
|
+
export type CladeMark =
|
|
335
|
+
| 'highlight'
|
|
336
|
+
| 'bracket'
|
|
337
|
+
| 'collapse'
|
|
338
|
+
| 'focus'
|
|
339
|
+
| 'rotate'
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* The order each node's children draw in, top to bottom. `branchLength` puts
|
|
343
|
+
* the shortest branch first, `input` keeps the file's order, `ladderize` puts
|
|
344
|
+
* the clade with the fewest tips first, so the deep clades step down toward
|
|
345
|
+
* the bottom, and `ladderizeReverse` puts the one with the most tips first.
|
|
346
|
+
*/
|
|
347
|
+
export type TreeOrder =
|
|
348
|
+
| 'branchLength'
|
|
349
|
+
| 'input'
|
|
350
|
+
| 'ladderize'
|
|
351
|
+
| 'ladderizeReverse'
|
|
352
|
+
|
|
353
|
+
/**
|
|
354
|
+
* Where the tree is rooted: `midpoint` halfway along the longest path between
|
|
355
|
+
* two tips, and `{outgroup}` on the branch above those tips' most recent common
|
|
356
|
+
* ancestor, or above the rest of the tips' where the outgroup straddles the
|
|
357
|
+
* root the file gives.
|
|
358
|
+
*/
|
|
359
|
+
export type TreeRoot = 'midpoint' | { outgroup: string[] }
|
|
334
360
|
|
|
335
361
|
/**
|
|
336
362
|
* A clade of the tree and the mark drawn over it. `mrca` names tips whose most
|
|
@@ -378,8 +404,9 @@ export interface Region {
|
|
|
378
404
|
/**
|
|
379
405
|
* A cell of the alignment in the host's coordinates, 1-based like Highlight:
|
|
380
406
|
* `column` counts every column of the file, hidden gappy ones included, and
|
|
381
|
-
* `residue` counts the row's own letters, absent on a gap.
|
|
382
|
-
*
|
|
407
|
+
* `residue` counts the row's own letters, absent on a gap. `letter` is the
|
|
408
|
+
* character in the cell, the gap character (`-` or `.`) on a gap. A pointer
|
|
409
|
+
* over a track has a column and no row.
|
|
383
410
|
*/
|
|
384
411
|
export interface Cell {
|
|
385
412
|
column: number
|
|
@@ -444,10 +471,5 @@ export interface NodeWithIds {
|
|
|
444
471
|
noTree?: boolean
|
|
445
472
|
}
|
|
446
473
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
name: string
|
|
450
|
-
children: NodeWithIdsAndLength[]
|
|
451
|
-
noTree?: boolean
|
|
452
|
-
length: number
|
|
453
|
-
}
|
|
474
|
+
/** @deprecated the same type as `NodeWithIds` */
|
|
475
|
+
export type NodeWithIdsAndLength = NodeWithIds
|
package/src/useMsaSvgFigure.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { useEffect, useState } from 'react'
|
|
|
2
2
|
|
|
3
3
|
import { createJBrowseTheme } from '@jbrowse/core/ui/theme'
|
|
4
4
|
import { getSnapshot } from '@jbrowse/mobx-state-tree'
|
|
5
|
-
import {
|
|
5
|
+
import { compareShallow, reaction } from 'mobx'
|
|
6
6
|
|
|
7
7
|
import { renderToSvg } from './renderToSvg.tsx'
|
|
8
8
|
|
|
@@ -18,7 +18,8 @@ export interface MsaSvgFigure {
|
|
|
18
18
|
/**
|
|
19
19
|
* The viewer's SVG export of its viewport, as markup for the page to insert.
|
|
20
20
|
* It redraws after the view settles: `delay` ms after the last scroll, zoom,
|
|
21
|
-
* resize or change to the snapshot. A draw a later one overtakes is
|
|
21
|
+
* resize, highlight or change to the snapshot. A draw a later one overtakes is
|
|
22
|
+
* dropped.
|
|
22
23
|
*
|
|
23
24
|
* The figure's row names and letters are SVG text, so the browser's find
|
|
24
25
|
* locates them, a reader can select them, and print stylesheets apply.
|
|
@@ -37,7 +38,13 @@ export function useMsaSvgFigure(
|
|
|
37
38
|
const dispose = reaction(
|
|
38
39
|
() =>
|
|
39
40
|
model.viewInitialized && model.dataInitialized
|
|
40
|
-
? [
|
|
41
|
+
? [
|
|
42
|
+
getSnapshot(model),
|
|
43
|
+
model.width,
|
|
44
|
+
model.height,
|
|
45
|
+
model.resolvedHighlights,
|
|
46
|
+
model.highlightedColumnRuns,
|
|
47
|
+
]
|
|
41
48
|
: undefined,
|
|
42
49
|
key => {
|
|
43
50
|
if (!key) {
|
|
@@ -61,7 +68,7 @@ export function useMsaSvgFigure(
|
|
|
61
68
|
},
|
|
62
69
|
)
|
|
63
70
|
},
|
|
64
|
-
{ delay, fireImmediately: true, equals:
|
|
71
|
+
{ delay, fireImmediately: true, equals: compareShallow },
|
|
65
72
|
)
|
|
66
73
|
return () => {
|
|
67
74
|
latest = -1
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '8.
|
|
1
|
+
export const version = '8.3.0'
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { descendants } from './hierarchy.ts'
|
|
2
|
+
|
|
3
|
+
import type { HierarchyNode } from './hierarchy.ts'
|
|
4
|
+
|
|
5
|
+
// a name holding any of these reads back as grammar unless it is quoted
|
|
6
|
+
const needsQuotes = /[\s(),:;[\]']/
|
|
7
|
+
|
|
8
|
+
function quote(name: string) {
|
|
9
|
+
return needsQuotes.test(name) ? `'${name.replaceAll("'", "''")}'` : name
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* The tree as Newick, in the order it is drawn. An internal node whose name is
|
|
14
|
+
* only its generated id goes unnamed. Each subtree's string is dropped once its
|
|
15
|
+
* parent takes it in, since a caterpillar tree is as deep as it has tips and
|
|
16
|
+
* keeping every one is quadratic.
|
|
17
|
+
*/
|
|
18
|
+
export function writeNewick(root: HierarchyNode) {
|
|
19
|
+
const written = new Map<HierarchyNode, string>()
|
|
20
|
+
for (const node of descendants(root).reverse()) {
|
|
21
|
+
const { id, name, length } = node.data
|
|
22
|
+
let text = ''
|
|
23
|
+
if (node.children) {
|
|
24
|
+
text = `(${node.children.map(c => written.get(c)!).join(',')})`
|
|
25
|
+
for (const child of node.children) {
|
|
26
|
+
written.delete(child)
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (!(node.children && name === id)) {
|
|
30
|
+
text += quote(name)
|
|
31
|
+
}
|
|
32
|
+
if (length !== undefined) {
|
|
33
|
+
text += `:${length}`
|
|
34
|
+
}
|
|
35
|
+
written.set(node, text)
|
|
36
|
+
}
|
|
37
|
+
return `${written.get(root)!};`
|
|
38
|
+
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
/**
|
|
3
|
-
* A tooltip beside the pointer, portaled to the body. A panel's scroll
|
|
4
|
-
* transform is a containing block, so a fixed tooltip left inside it would
|
|
5
|
-
* position against the scrolled content instead of the window.
|
|
6
|
-
*/
|
|
7
|
-
export default function PortalTooltip({ clientX, clientY, children, }: {
|
|
8
|
-
clientX: number;
|
|
9
|
-
clientY: number;
|
|
10
|
-
children: React.ReactNode;
|
|
11
|
-
}): React.ReactPortal;
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
3
|
-
import { createPortal } from 'react-dom';
|
|
4
|
-
const useStyles = makeStyles()(theme => ({
|
|
5
|
-
tooltip: {
|
|
6
|
-
position: 'fixed',
|
|
7
|
-
pointerEvents: 'none',
|
|
8
|
-
zIndex: 10000,
|
|
9
|
-
backgroundColor: theme.palette.grey[700],
|
|
10
|
-
color: theme.palette.common.white,
|
|
11
|
-
padding: '4px 8px',
|
|
12
|
-
borderRadius: 4,
|
|
13
|
-
fontSize: 12,
|
|
14
|
-
whiteSpace: 'nowrap',
|
|
15
|
-
maxWidth: 300,
|
|
16
|
-
overflow: 'hidden',
|
|
17
|
-
textOverflow: 'ellipsis',
|
|
18
|
-
},
|
|
19
|
-
}));
|
|
20
|
-
/**
|
|
21
|
-
* A tooltip beside the pointer, portaled to the body. A panel's scroll
|
|
22
|
-
* transform is a containing block, so a fixed tooltip left inside it would
|
|
23
|
-
* position against the scrolled content instead of the window.
|
|
24
|
-
*/
|
|
25
|
-
export default function PortalTooltip({ clientX, clientY, children, }) {
|
|
26
|
-
const { classes } = useStyles();
|
|
27
|
-
return createPortal(React.createElement("div", { className: classes.tooltip, style: { left: clientX + 12, top: clientY + 12 } }, children), document.body);
|
|
28
|
-
}
|
|
29
|
-
//# sourceMappingURL=PortalTooltip.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PortalTooltip.js","sourceRoot":"","sources":["../../src/components/PortalTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,WAAW,CAAA;AAExC,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACvC,OAAO,EAAE;QACP,QAAQ,EAAE,OAAO;QACjB,aAAa,EAAE,MAAM;QACrB,MAAM,EAAE,KAAK;QACb,eAAe,EAAE,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC;QACxC,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK;QACjC,OAAO,EAAE,SAAS;QAClB,YAAY,EAAE,CAAC;QACf,QAAQ,EAAE,EAAE;QACZ,UAAU,EAAE,QAAQ;QACpB,QAAQ,EAAE,GAAG;QACb,QAAQ,EAAE,QAAQ;QAClB,YAAY,EAAE,UAAU;KACzB;CACF,CAAC,CAAC,CAAA;AAEH;;;;GAIG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,EACpC,OAAO,EACP,OAAO,EACP,QAAQ,GAKT;IACC,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAA;IAC/B,OAAO,YAAY,CACjB,6BACE,SAAS,EAAE,OAAO,CAAC,OAAO,EAC1B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,GAAG,EAAE,EAAE,GAAG,EAAE,OAAO,GAAG,EAAE,EAAE,IAE/C,QAAQ,CACL,EACN,QAAQ,CAAC,IAAI,CACd,CAAA;AACH,CAAC"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { LoadingEllipses } from '@jbrowse/core/ui';
|
|
3
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react';
|
|
4
|
-
import { Button, Typography } from '@mui/material';
|
|
5
|
-
import { observer } from 'mobx-react';
|
|
6
|
-
const useStyles = makeStyles()({
|
|
7
|
-
margin: {
|
|
8
|
-
margin: 'auto',
|
|
9
|
-
marginLeft: 10,
|
|
10
|
-
},
|
|
11
|
-
});
|
|
12
|
-
const HeaderStatusArea = observer(({ model }) => {
|
|
13
|
-
const { status } = model;
|
|
14
|
-
const { classes } = useStyles();
|
|
15
|
-
return status ? (React.createElement(Typography, { className: classes.margin },
|
|
16
|
-
React.createElement(LoadingEllipses, { message: status.msg, component: "span" }),
|
|
17
|
-
' ',
|
|
18
|
-
status.onCancel ? (React.createElement(Button, { size: "small", onClick: () => status.onCancel?.() }, "Cancel")) : null)) : null;
|
|
19
|
-
});
|
|
20
|
-
export default HeaderStatusArea;
|
|
21
|
-
//# sourceMappingURL=HeaderStatusArea.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"HeaderStatusArea.js","sourceRoot":"","sources":["../../../src/components/header/HeaderStatusArea.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAA;AACzD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAIrC,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;IAC7B,MAAM,EAAE;QACN,MAAM,EAAE,MAAM;QACd,UAAU,EAAE,EAAE;KACf;CACF,CAAC,CAAA;AAEF,MAAM,gBAAgB,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,EAA2B,EAAE,EAAE;IACvE,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IACxB,MAAM,EAAE,OAAO,EAAE,GAAG,SAAS,EAAE,CAAA;IAC/B,OAAO,MAAM,CAAC,CAAC,CAAC,CACd,oBAAC,UAAU,IAAC,SAAS,EAAE,OAAO,CAAC,MAAM;QACnC,oBAAC,eAAe,IAAC,OAAO,EAAE,MAAM,CAAC,GAAG,EAAE,SAAS,EAAC,MAAM,GAAG;QAAC,GAAG;QAC5D,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CACjB,oBAAC,MAAM,IAAC,IAAI,EAAC,OAAO,EAAC,OAAO,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,QAAQ,EAAE,EAAE,aAE9C,CACV,CAAC,CAAC,CAAC,IAAI,CACG,CACd,CAAC,CAAC,CAAC,IAAI,CAAA;AACV,CAAC,CAAC,CAAA;AAEF,eAAe,gBAAgB,CAAA"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Menu, MenuItem } from '@mui/material';
|
|
3
|
-
import { observer } from 'mobx-react';
|
|
4
|
-
const TreeBranchMenu = observer(function ({ node, model, onClose, }) {
|
|
5
|
-
return (React.createElement(Menu, { anchorReference: "anchorPosition", anchorPosition: {
|
|
6
|
-
left: node.x,
|
|
7
|
-
top: node.y,
|
|
8
|
-
}, transitionDuration: 0, open: true, onClose: onClose },
|
|
9
|
-
React.createElement(MenuItem, { dense: true, disabled: true }, node.name),
|
|
10
|
-
React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
11
|
-
model.toggleCollapsed(node.id);
|
|
12
|
-
onClose();
|
|
13
|
-
} }, model.collapsed.includes(node.id)
|
|
14
|
-
? 'Expand this node'
|
|
15
|
-
: 'Collapse this node'),
|
|
16
|
-
React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
17
|
-
if (model.showOnly === node.id) {
|
|
18
|
-
model.setShowOnly(undefined);
|
|
19
|
-
}
|
|
20
|
-
else {
|
|
21
|
-
model.setShowOnly(node.id);
|
|
22
|
-
}
|
|
23
|
-
onClose();
|
|
24
|
-
} }, model.showOnly === node.id
|
|
25
|
-
? 'Disable show only this node'
|
|
26
|
-
: 'Show only this node')));
|
|
27
|
-
});
|
|
28
|
-
export default TreeBranchMenu;
|
|
29
|
-
//# sourceMappingURL=TreeBranchMenu.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TreeBranchMenu.js","sourceRoot":"","sources":["../../../src/components/tree/TreeBranchMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAWrC,MAAM,cAAc,GAAG,QAAQ,CAAC,UAAU,EACxC,IAAI,EACJ,KAAK,EACL,OAAO,GAKR;IACC,OAAO,CACL,oBAAC,IAAI,IACH,eAAe,EAAC,gBAAgB,EAChC,cAAc,EAAE;YACd,IAAI,EAAE,IAAI,CAAC,CAAC;YACZ,GAAG,EAAE,IAAI,CAAC,CAAC;SACZ,EACD,kBAAkB,EAAE,CAAC,EACrB,IAAI,QACJ,OAAO,EAAE,OAAO;QAEhB,oBAAC,QAAQ,IAAC,KAAK,QAAC,QAAQ,UACrB,IAAI,CAAC,IAAI,CACD;QACX,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,KAAK,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;gBAC9B,OAAO,EAAE,CAAA;YACX,CAAC,IAEA,KAAK,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YAChC,CAAC,CAAC,kBAAkB;YACpB,CAAC,CAAC,oBAAoB,CACf;QACX,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE,EAAE,CAAC;oBAC/B,KAAK,CAAC,WAAW,CAAC,SAAS,CAAC,CAAA;gBAC9B,CAAC;qBAAM,CAAC;oBACN,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;gBAC5B,CAAC;gBACD,OAAO,EAAE,CAAA;YACX,CAAC,IAEA,KAAK,CAAC,QAAQ,KAAK,IAAI,CAAC,EAAE;YACzB,CAAC,CAAC,6BAA6B;YAC/B,CAAC,CAAC,qBAAqB,CAChB,CACN,CACR,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,cAAc,CAAA"}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import type { MsaViewModel } from '../../model.ts';
|
|
3
|
-
declare const TreeMenu: ({ node, onClose, model, }: {
|
|
4
|
-
node: {
|
|
5
|
-
x: number;
|
|
6
|
-
y: number;
|
|
7
|
-
name: string;
|
|
8
|
-
id: string;
|
|
9
|
-
};
|
|
10
|
-
model: MsaViewModel;
|
|
11
|
-
onClose: () => void;
|
|
12
|
-
}) => React.JSX.Element;
|
|
13
|
-
export default TreeMenu;
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import React, { lazy } from 'react';
|
|
2
|
-
import { Menu, MenuItem } from '@mui/material';
|
|
3
|
-
import { observer } from 'mobx-react';
|
|
4
|
-
// lazies
|
|
5
|
-
const TreeNodeInfoDialog = lazy(() => import('./dialogs/TreeNodeInfoDialog.js'));
|
|
6
|
-
const TreeMenu = observer(function ({ node, onClose, model, }) {
|
|
7
|
-
const { collapsed } = model;
|
|
8
|
-
const { name, id } = node;
|
|
9
|
-
const isCollapsed = collapsed.includes(id);
|
|
10
|
-
return (React.createElement(Menu, { anchorReference: "anchorPosition", anchorPosition: {
|
|
11
|
-
top: node.y,
|
|
12
|
-
left: node.x,
|
|
13
|
-
}, transitionDuration: 0, open: true, onClose: onClose },
|
|
14
|
-
React.createElement(MenuItem, { dense: true, disabled: true }, name),
|
|
15
|
-
React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
16
|
-
model.queueDialog(onClose => [
|
|
17
|
-
TreeNodeInfoDialog,
|
|
18
|
-
{
|
|
19
|
-
info: model.getRowData(name),
|
|
20
|
-
model,
|
|
21
|
-
nodeName: name,
|
|
22
|
-
onClose,
|
|
23
|
-
},
|
|
24
|
-
]);
|
|
25
|
-
onClose();
|
|
26
|
-
} }, "More info..."),
|
|
27
|
-
React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
28
|
-
model.toggleCollapsed(id);
|
|
29
|
-
onClose();
|
|
30
|
-
} }, isCollapsed ? 'Expand subtree' : 'Collapse subtree'),
|
|
31
|
-
React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
32
|
-
model.drawRelativeTo(node.name);
|
|
33
|
-
onClose();
|
|
34
|
-
} }, "Indicate differences from this row"),
|
|
35
|
-
model.relativeTo ? (React.createElement(MenuItem, { dense: true, onClick: () => {
|
|
36
|
-
model.drawRelativeTo(undefined);
|
|
37
|
-
onClose();
|
|
38
|
-
} }, "Clear reference row")) : null));
|
|
39
|
-
});
|
|
40
|
-
export default TreeMenu;
|
|
41
|
-
//# sourceMappingURL=TreeNodeMenu.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TreeNodeMenu.js","sourceRoot":"","sources":["../../../src/components/tree/TreeNodeMenu.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,OAAO,CAAA;AAEnC,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAIrC,SAAS;AACT,MAAM,kBAAkB,GAAG,IAAI,CAC7B,GAAG,EAAE,CAAC,MAAM,CAAC,iCAAkC,CAAC,CACjD,CAAA;AAED,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,EAClC,IAAI,EACJ,OAAO,EACP,KAAK,GAUN;IACC,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAA;IAC3B,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,GAAG,IAAI,CAAA;IACzB,MAAM,WAAW,GAAG,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC1C,OAAO,CACL,oBAAC,IAAI,IACH,eAAe,EAAC,gBAAgB,EAChC,cAAc,EAAE;YACd,GAAG,EAAE,IAAI,CAAC,CAAC;YACX,IAAI,EAAE,IAAI,CAAC,CAAC;SACb,EACD,kBAAkB,EAAE,CAAC,EACrB,IAAI,QACJ,OAAO,EAAE,OAAO;QAEhB,oBAAC,QAAQ,IAAC,KAAK,QAAC,QAAQ,UACrB,IAAI,CACI;QAEX,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;oBAC3B,kBAAkB;oBAClB;wBACE,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC5B,KAAK;wBACL,QAAQ,EAAE,IAAI;wBACd,OAAO;qBACR;iBACF,CAAC,CAAA;gBACF,OAAO,EAAE,CAAA;YACX,CAAC,mBAGQ;QACX,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAA;gBACzB,OAAO,EAAE,CAAA;YACX,CAAC,IAEA,WAAW,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,kBAAkB,CAC3C;QACX,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBAC/B,OAAO,EAAE,CAAA;YACX,CAAC,yCAGQ;QACV,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAClB,oBAAC,QAAQ,IACP,KAAK,QACL,OAAO,EAAE,GAAG,EAAE;gBACZ,KAAK,CAAC,cAAc,CAAC,SAAS,CAAC,CAAA;gBAC/B,OAAO,EAAE,CAAA;YACX,CAAC,0BAGQ,CACZ,CAAC,CAAC,CAAC,IAAI,CACH,CACR,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,QAAQ,CAAA"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react'
|
|
4
|
-
import { createPortal } from 'react-dom'
|
|
5
|
-
|
|
6
|
-
const useStyles = makeStyles()(theme => ({
|
|
7
|
-
tooltip: {
|
|
8
|
-
position: 'fixed',
|
|
9
|
-
pointerEvents: 'none',
|
|
10
|
-
zIndex: 10000,
|
|
11
|
-
backgroundColor: theme.palette.grey[700],
|
|
12
|
-
color: theme.palette.common.white,
|
|
13
|
-
padding: '4px 8px',
|
|
14
|
-
borderRadius: 4,
|
|
15
|
-
fontSize: 12,
|
|
16
|
-
whiteSpace: 'nowrap',
|
|
17
|
-
maxWidth: 300,
|
|
18
|
-
overflow: 'hidden',
|
|
19
|
-
textOverflow: 'ellipsis',
|
|
20
|
-
},
|
|
21
|
-
}))
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* A tooltip beside the pointer, portaled to the body. A panel's scroll
|
|
25
|
-
* transform is a containing block, so a fixed tooltip left inside it would
|
|
26
|
-
* position against the scrolled content instead of the window.
|
|
27
|
-
*/
|
|
28
|
-
export default function PortalTooltip({
|
|
29
|
-
clientX,
|
|
30
|
-
clientY,
|
|
31
|
-
children,
|
|
32
|
-
}: {
|
|
33
|
-
clientX: number
|
|
34
|
-
clientY: number
|
|
35
|
-
children: React.ReactNode
|
|
36
|
-
}) {
|
|
37
|
-
const { classes } = useStyles()
|
|
38
|
-
return createPortal(
|
|
39
|
-
<div
|
|
40
|
-
className={classes.tooltip}
|
|
41
|
-
style={{ left: clientX + 12, top: clientY + 12 }}
|
|
42
|
-
>
|
|
43
|
-
{children}
|
|
44
|
-
</div>,
|
|
45
|
-
document.body,
|
|
46
|
-
)
|
|
47
|
-
}
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { LoadingEllipses } from '@jbrowse/core/ui'
|
|
4
|
-
import { makeStyles } from '@jbrowse/core/util/tss-react'
|
|
5
|
-
import { Button, Typography } from '@mui/material'
|
|
6
|
-
import { observer } from 'mobx-react'
|
|
7
|
-
|
|
8
|
-
import type { MsaViewModel } from '../../model.ts'
|
|
9
|
-
|
|
10
|
-
const useStyles = makeStyles()({
|
|
11
|
-
margin: {
|
|
12
|
-
margin: 'auto',
|
|
13
|
-
marginLeft: 10,
|
|
14
|
-
},
|
|
15
|
-
})
|
|
16
|
-
|
|
17
|
-
const HeaderStatusArea = observer(({ model }: { model: MsaViewModel }) => {
|
|
18
|
-
const { status } = model
|
|
19
|
-
const { classes } = useStyles()
|
|
20
|
-
return status ? (
|
|
21
|
-
<Typography className={classes.margin}>
|
|
22
|
-
<LoadingEllipses message={status.msg} component="span" />{' '}
|
|
23
|
-
{status.onCancel ? (
|
|
24
|
-
<Button size="small" onClick={() => status.onCancel?.()}>
|
|
25
|
-
Cancel
|
|
26
|
-
</Button>
|
|
27
|
-
) : null}
|
|
28
|
-
</Typography>
|
|
29
|
-
) : null
|
|
30
|
-
})
|
|
31
|
-
|
|
32
|
-
export default HeaderStatusArea
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { Menu, MenuItem } from '@mui/material'
|
|
4
|
-
import { observer } from 'mobx-react'
|
|
5
|
-
|
|
6
|
-
import type { MsaViewModel } from '../../model.ts'
|
|
7
|
-
|
|
8
|
-
interface Node {
|
|
9
|
-
x: number
|
|
10
|
-
y: number
|
|
11
|
-
name: string
|
|
12
|
-
id: string
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const TreeBranchMenu = observer(function ({
|
|
16
|
-
node,
|
|
17
|
-
model,
|
|
18
|
-
onClose,
|
|
19
|
-
}: {
|
|
20
|
-
node: Node
|
|
21
|
-
model: MsaViewModel
|
|
22
|
-
onClose: () => void
|
|
23
|
-
}) {
|
|
24
|
-
return (
|
|
25
|
-
<Menu
|
|
26
|
-
anchorReference="anchorPosition"
|
|
27
|
-
anchorPosition={{
|
|
28
|
-
left: node.x,
|
|
29
|
-
top: node.y,
|
|
30
|
-
}}
|
|
31
|
-
transitionDuration={0}
|
|
32
|
-
open
|
|
33
|
-
onClose={onClose}
|
|
34
|
-
>
|
|
35
|
-
<MenuItem dense disabled>
|
|
36
|
-
{node.name}
|
|
37
|
-
</MenuItem>
|
|
38
|
-
<MenuItem
|
|
39
|
-
dense
|
|
40
|
-
onClick={() => {
|
|
41
|
-
model.toggleCollapsed(node.id)
|
|
42
|
-
onClose()
|
|
43
|
-
}}
|
|
44
|
-
>
|
|
45
|
-
{model.collapsed.includes(node.id)
|
|
46
|
-
? 'Expand this node'
|
|
47
|
-
: 'Collapse this node'}
|
|
48
|
-
</MenuItem>
|
|
49
|
-
<MenuItem
|
|
50
|
-
dense
|
|
51
|
-
onClick={() => {
|
|
52
|
-
if (model.showOnly === node.id) {
|
|
53
|
-
model.setShowOnly(undefined)
|
|
54
|
-
} else {
|
|
55
|
-
model.setShowOnly(node.id)
|
|
56
|
-
}
|
|
57
|
-
onClose()
|
|
58
|
-
}}
|
|
59
|
-
>
|
|
60
|
-
{model.showOnly === node.id
|
|
61
|
-
? 'Disable show only this node'
|
|
62
|
-
: 'Show only this node'}
|
|
63
|
-
</MenuItem>
|
|
64
|
-
</Menu>
|
|
65
|
-
)
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
export default TreeBranchMenu
|