react-msaview 4.4.5 → 4.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/bundle/index.js +9 -9
- package/bundle/index.js.LICENSE.txt +8 -8
- package/bundle/index.js.map +1 -1
- package/dist/colorSchemes.d.ts +0 -6
- package/dist/colorSchemes.js +1 -119
- package/dist/colorSchemes.js.map +1 -1
- package/dist/components/ConservationTrack.d.ts +8 -0
- package/dist/components/ConservationTrack.js +54 -0
- package/dist/components/ConservationTrack.js.map +1 -0
- package/dist/components/Loading.js +14 -2
- package/dist/components/Loading.js.map +1 -1
- package/dist/components/MSAView.js +36 -0
- package/dist/components/MSAView.js.map +1 -1
- package/dist/components/SequenceTextArea.js +3 -2
- package/dist/components/SequenceTextArea.js.map +1 -1
- package/dist/components/TextTrack.d.ts +3 -3
- package/dist/components/TextTrack.js +4 -1
- package/dist/components/TextTrack.js.map +1 -1
- package/dist/components/Track.js +21 -8
- package/dist/components/Track.js.map +1 -1
- package/dist/components/dialogs/ExportSVGDialog.js +19 -3
- package/dist/components/dialogs/ExportSVGDialog.js.map +1 -1
- package/dist/components/header/GappynessSlider.d.ts +6 -0
- package/dist/components/header/GappynessSlider.js +19 -0
- package/dist/components/header/GappynessSlider.js.map +1 -0
- package/dist/components/header/Header.js +3 -1
- package/dist/components/header/Header.js.map +1 -1
- package/dist/components/header/HeaderMenu.js +30 -14
- package/dist/components/header/HeaderMenu.js.map +1 -1
- package/dist/components/minimap/MinimapSVG.js +4 -3
- package/dist/components/minimap/MinimapSVG.js.map +1 -1
- package/dist/components/msa/MSACanvasBlock.js +56 -42
- package/dist/components/msa/MSACanvasBlock.js.map +1 -1
- package/dist/components/msa/renderMSABlock.js +53 -10
- package/dist/components/msa/renderMSABlock.js.map +1 -1
- package/dist/components/tracks/renderTracksSvg.d.ts +29 -0
- package/dist/components/tracks/renderTracksSvg.js +83 -0
- package/dist/components/tracks/renderTracksSvg.js.map +1 -0
- package/dist/components/tree/TreeCanvasBlock.js +1 -1
- package/dist/components/tree/TreeCanvasBlock.js.map +1 -1
- package/dist/components/tree/TreeNodeMenu.js +2 -2
- package/dist/components/tree/TreeNodeMenu.js.map +1 -1
- package/dist/components/tree/renderTreeCanvas.js +1 -1
- package/dist/components/tree/renderTreeCanvas.js.map +1 -1
- package/dist/constants.d.ts +22 -0
- package/dist/constants.js +26 -0
- package/dist/constants.js.map +1 -0
- package/dist/layout.js.map +1 -1
- package/dist/model/msaModel.js +3 -2
- package/dist/model/msaModel.js.map +1 -1
- package/dist/model/treeModel.js +9 -8
- package/dist/model/treeModel.js.map +1 -1
- package/dist/model.d.ts +256 -15
- package/dist/model.js +408 -128
- package/dist/model.js.map +1 -1
- package/dist/neighborJoining.d.ts +1 -0
- package/dist/neighborJoining.js +839 -0
- package/dist/neighborJoining.js.map +1 -0
- package/dist/neighborJoining.test.d.ts +1 -0
- package/dist/neighborJoining.test.js +110 -0
- package/dist/neighborJoining.test.js.map +1 -0
- package/dist/parsers/A3mMSA.d.ts +43 -0
- package/dist/parsers/A3mMSA.js +277 -0
- package/dist/parsers/A3mMSA.js.map +1 -0
- package/dist/parsers/A3mMSA.test.d.ts +1 -0
- package/dist/parsers/A3mMSA.test.js +138 -0
- package/dist/parsers/A3mMSA.test.js.map +1 -0
- package/dist/parsers/ClustalMSA.d.ts +4 -4
- package/dist/parsers/ClustalMSA.js +3 -1
- package/dist/parsers/ClustalMSA.js.map +1 -1
- package/dist/parsers/FastaMSA.js +17 -16
- package/dist/parsers/FastaMSA.js.map +1 -1
- package/dist/renderToSvg.d.ts +1 -0
- package/dist/renderToSvg.js +48 -18
- package/dist/renderToSvg.js.map +1 -1
- package/dist/rowCoordinateCalculations.js +3 -5
- package/dist/rowCoordinateCalculations.js.map +1 -1
- package/dist/rowCoordinateCalculations.test.js +14 -2
- package/dist/rowCoordinateCalculations.test.js.map +1 -1
- package/dist/seqCoordToRowSpecificGlobalCoord.js +9 -5
- package/dist/seqCoordToRowSpecificGlobalCoord.js.map +1 -1
- package/dist/seqCoordToRowSpecificGlobalCoord.test.js +6 -6
- package/dist/types.d.ts +2 -3
- package/dist/util.js +17 -9
- package/dist/util.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -6
- package/src/colorSchemes.ts +1 -179
- package/src/components/ConservationTrack.tsx +104 -0
- package/src/components/Loading.tsx +44 -2
- package/src/components/MSAView.tsx +68 -0
- package/src/components/SequenceTextArea.tsx +3 -2
- package/src/components/TextTrack.tsx +7 -4
- package/src/components/Track.tsx +25 -9
- package/src/components/dialogs/ExportSVGDialog.tsx +25 -1
- package/src/components/header/GappynessSlider.tsx +35 -0
- package/src/components/header/Header.tsx +3 -1
- package/src/components/header/HeaderMenu.tsx +36 -15
- package/src/components/minimap/MinimapSVG.tsx +6 -3
- package/src/components/msa/MSACanvasBlock.tsx +66 -48
- package/src/components/msa/renderMSABlock.ts +82 -22
- package/src/components/tracks/renderTracksSvg.ts +157 -0
- package/src/components/tree/TreeCanvasBlock.tsx +1 -1
- package/src/components/tree/TreeNodeMenu.tsx +2 -2
- package/src/components/tree/renderTreeCanvas.ts +1 -1
- package/src/constants.ts +27 -0
- package/src/layout.ts +1 -6
- package/src/model/msaModel.ts +4 -2
- package/src/model/treeModel.ts +19 -8
- package/src/model.ts +496 -140
- package/src/neighborJoining.test.ts +129 -0
- package/src/neighborJoining.ts +885 -0
- package/src/parsers/A3mMSA.test.ts +164 -0
- package/src/parsers/A3mMSA.ts +321 -0
- package/src/parsers/ClustalMSA.ts +7 -5
- package/src/parsers/FastaMSA.ts +17 -17
- package/src/renderToSvg.tsx +105 -26
- package/src/rowCoordinateCalculations.test.ts +15 -2
- package/src/rowCoordinateCalculations.ts +3 -5
- package/src/seqCoordToRowSpecificGlobalCoord.test.ts +6 -6
- package/src/seqCoordToRowSpecificGlobalCoord.ts +9 -4
- package/src/types.ts +2 -4
- package/src/util.ts +21 -8
- package/src/version.ts +1 -1
- package/dist/components/dialogs/TracklistDialog.d.ts +0 -7
- package/dist/components/dialogs/TracklistDialog.js +0 -23
- package/dist/components/dialogs/TracklistDialog.js.map +0 -1
- package/src/components/dialogs/TracklistDialog.tsx +0 -73
package/src/renderToSvg.tsx
CHANGED
|
@@ -7,6 +7,7 @@ import { when } from 'mobx'
|
|
|
7
7
|
import MinimapSVG from './components/minimap/MinimapSVG'
|
|
8
8
|
import { renderBoxFeatureCanvasBlock } from './components/msa/renderBoxFeatureCanvasBlock'
|
|
9
9
|
import { renderMSABlock } from './components/msa/renderMSABlock'
|
|
10
|
+
import { renderAllTracks } from './components/tracks/renderTracksSvg'
|
|
10
11
|
import { renderTreeCanvas } from './components/tree/renderTreeCanvas'
|
|
11
12
|
import { colorContrast } from './util'
|
|
12
13
|
|
|
@@ -16,33 +17,41 @@ import type { Theme } from '@mui/material'
|
|
|
16
17
|
export interface ExportSvgOptions {
|
|
17
18
|
theme: Theme
|
|
18
19
|
includeMinimap?: boolean
|
|
20
|
+
includeTracks?: boolean
|
|
19
21
|
exportType: string
|
|
20
22
|
}
|
|
21
23
|
export async function renderToSvg(model: MsaViewModel, opts: ExportSvgOptions) {
|
|
22
24
|
await when(() => !!model.dataInitialized)
|
|
23
|
-
const { width, height, scrollX, scrollY } = model
|
|
24
|
-
const { exportType, theme, includeMinimap } = opts
|
|
25
|
+
const { width, height, scrollX, scrollY, totalTrackAreaHeight } = model
|
|
26
|
+
const { exportType, theme, includeMinimap, includeTracks } = opts
|
|
27
|
+
const trackHeight = includeTracks ? totalTrackAreaHeight : 0
|
|
25
28
|
|
|
26
29
|
if (exportType === 'entire') {
|
|
27
30
|
return render({
|
|
28
31
|
width: model.totalWidth + model.treeAreaWidth,
|
|
29
|
-
height: model.totalHeight,
|
|
32
|
+
height: model.totalHeight + trackHeight,
|
|
33
|
+
contentHeight: model.totalHeight,
|
|
34
|
+
trackHeight,
|
|
30
35
|
theme,
|
|
31
36
|
model,
|
|
32
37
|
offsetY: 0,
|
|
33
38
|
offsetX: 0,
|
|
34
39
|
includeMinimap,
|
|
40
|
+
includeTracks,
|
|
35
41
|
})
|
|
36
42
|
}
|
|
37
43
|
if (exportType === 'viewport') {
|
|
38
44
|
return render({
|
|
39
45
|
width,
|
|
40
|
-
height,
|
|
46
|
+
height: height + (includeMinimap ? model.minimapHeight : 0) + trackHeight,
|
|
47
|
+
contentHeight: height,
|
|
48
|
+
trackHeight,
|
|
41
49
|
theme,
|
|
42
50
|
model,
|
|
43
|
-
offsetY: scrollY,
|
|
51
|
+
offsetY: -scrollY,
|
|
44
52
|
offsetX: -scrollX,
|
|
45
53
|
includeMinimap,
|
|
54
|
+
includeTracks,
|
|
46
55
|
})
|
|
47
56
|
}
|
|
48
57
|
throw new Error('unknown export type')
|
|
@@ -51,19 +60,25 @@ export async function renderToSvg(model: MsaViewModel, opts: ExportSvgOptions) {
|
|
|
51
60
|
async function render({
|
|
52
61
|
width,
|
|
53
62
|
height,
|
|
63
|
+
contentHeight,
|
|
64
|
+
trackHeight,
|
|
54
65
|
offsetX,
|
|
55
66
|
offsetY,
|
|
56
67
|
theme,
|
|
57
68
|
model,
|
|
58
69
|
includeMinimap,
|
|
70
|
+
includeTracks,
|
|
59
71
|
}: {
|
|
60
72
|
width: number
|
|
61
73
|
height: number
|
|
74
|
+
contentHeight: number
|
|
75
|
+
trackHeight: number
|
|
62
76
|
offsetX: number
|
|
63
77
|
offsetY: number
|
|
64
78
|
theme: Theme
|
|
65
79
|
model: MsaViewModel
|
|
66
80
|
includeMinimap?: boolean
|
|
81
|
+
includeTracks?: boolean
|
|
67
82
|
}) {
|
|
68
83
|
const { Context } = await import('svgcanvas')
|
|
69
84
|
const Wrapper = includeMinimap ? MinimapWrapper : NullWrapper
|
|
@@ -71,15 +86,31 @@ async function render({
|
|
|
71
86
|
return renderToStaticMarkup(
|
|
72
87
|
<SvgWrapper width={width} height={height}>
|
|
73
88
|
<Wrapper model={model}>
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
89
|
+
{includeTracks && trackHeight > 0 ? (
|
|
90
|
+
<TrackRendering
|
|
91
|
+
Context={Context}
|
|
92
|
+
model={model}
|
|
93
|
+
theme={theme}
|
|
94
|
+
offsetX={offsetX}
|
|
95
|
+
width={width}
|
|
96
|
+
trackHeight={trackHeight}
|
|
97
|
+
/>
|
|
98
|
+
) : null}
|
|
99
|
+
<g
|
|
100
|
+
transform={
|
|
101
|
+
trackHeight > 0 ? `translate(0 ${trackHeight})` : undefined
|
|
102
|
+
}
|
|
103
|
+
>
|
|
104
|
+
<CoreRendering
|
|
105
|
+
Context={Context}
|
|
106
|
+
model={model}
|
|
107
|
+
theme={theme}
|
|
108
|
+
offsetX={offsetX}
|
|
109
|
+
offsetY={offsetY}
|
|
110
|
+
width={width}
|
|
111
|
+
contentHeight={contentHeight}
|
|
112
|
+
/>
|
|
113
|
+
</g>
|
|
83
114
|
</Wrapper>
|
|
84
115
|
</SvgWrapper>,
|
|
85
116
|
)
|
|
@@ -89,7 +120,7 @@ function CoreRendering({
|
|
|
89
120
|
model,
|
|
90
121
|
theme,
|
|
91
122
|
width,
|
|
92
|
-
|
|
123
|
+
contentHeight,
|
|
93
124
|
offsetX,
|
|
94
125
|
offsetY,
|
|
95
126
|
Context,
|
|
@@ -97,7 +128,7 @@ function CoreRendering({
|
|
|
97
128
|
model: MsaViewModel
|
|
98
129
|
theme: Theme
|
|
99
130
|
width: number
|
|
100
|
-
|
|
131
|
+
contentHeight: number
|
|
101
132
|
offsetX: number
|
|
102
133
|
offsetY: number
|
|
103
134
|
Context: (
|
|
@@ -105,18 +136,18 @@ function CoreRendering({
|
|
|
105
136
|
height: number,
|
|
106
137
|
) => CanvasRenderingContext2D & { getSvg: () => { innerHTML: string } }
|
|
107
138
|
}) {
|
|
108
|
-
const
|
|
109
|
-
const
|
|
110
|
-
const
|
|
139
|
+
const { treeAreaWidth, colorScheme, id } = model
|
|
140
|
+
const clipId1 = `tree-${id}`
|
|
141
|
+
const clipId2 = `msa-${id}`
|
|
111
142
|
const contrastScheme = colorContrast(colorScheme, theme)
|
|
112
|
-
const ctx1 = Context(width,
|
|
113
|
-
const ctx2 = Context(width,
|
|
143
|
+
const ctx1 = Context(width, contentHeight)
|
|
144
|
+
const ctx2 = Context(width, contentHeight)
|
|
114
145
|
renderBoxFeatureCanvasBlock({
|
|
115
146
|
ctx: ctx2,
|
|
116
147
|
offsetX,
|
|
117
148
|
offsetY,
|
|
118
149
|
model,
|
|
119
|
-
blockSizeYOverride:
|
|
150
|
+
blockSizeYOverride: contentHeight,
|
|
120
151
|
highResScaleFactorOverride: 1,
|
|
121
152
|
})
|
|
122
153
|
const msaAreaWidth = width - treeAreaWidth
|
|
@@ -125,7 +156,7 @@ function CoreRendering({
|
|
|
125
156
|
offsetY,
|
|
126
157
|
ctx: ctx1,
|
|
127
158
|
theme,
|
|
128
|
-
blockSizeYOverride:
|
|
159
|
+
blockSizeYOverride: contentHeight,
|
|
129
160
|
highResScaleFactorOverride: 1,
|
|
130
161
|
})
|
|
131
162
|
renderMSABlock({
|
|
@@ -136,19 +167,19 @@ function CoreRendering({
|
|
|
136
167
|
contrastScheme,
|
|
137
168
|
ctx: ctx2,
|
|
138
169
|
blockSizeXOverride: msaAreaWidth,
|
|
139
|
-
blockSizeYOverride:
|
|
170
|
+
blockSizeYOverride: contentHeight,
|
|
140
171
|
highResScaleFactorOverride: 1,
|
|
141
172
|
})
|
|
142
173
|
return (
|
|
143
174
|
<>
|
|
144
175
|
<defs>
|
|
145
176
|
<clipPath id={clipId1}>
|
|
146
|
-
<rect x={0} y={0} width={treeAreaWidth} height={
|
|
177
|
+
<rect x={0} y={0} width={treeAreaWidth} height={contentHeight} />
|
|
147
178
|
</clipPath>
|
|
148
179
|
</defs>
|
|
149
180
|
<defs>
|
|
150
181
|
<clipPath id={clipId2}>
|
|
151
|
-
<rect x={0} y={0} width={msaAreaWidth} height={
|
|
182
|
+
<rect x={0} y={0} width={msaAreaWidth} height={contentHeight} />
|
|
152
183
|
</clipPath>
|
|
153
184
|
</defs>
|
|
154
185
|
|
|
@@ -165,6 +196,54 @@ function CoreRendering({
|
|
|
165
196
|
)
|
|
166
197
|
}
|
|
167
198
|
|
|
199
|
+
function TrackRendering({
|
|
200
|
+
model,
|
|
201
|
+
theme,
|
|
202
|
+
width,
|
|
203
|
+
trackHeight,
|
|
204
|
+
offsetX,
|
|
205
|
+
Context,
|
|
206
|
+
}: {
|
|
207
|
+
model: MsaViewModel
|
|
208
|
+
theme: Theme
|
|
209
|
+
width: number
|
|
210
|
+
trackHeight: number
|
|
211
|
+
offsetX: number
|
|
212
|
+
Context: (
|
|
213
|
+
width: number,
|
|
214
|
+
height: number,
|
|
215
|
+
) => CanvasRenderingContext2D & { getSvg: () => { innerHTML: string } }
|
|
216
|
+
}) {
|
|
217
|
+
const { treeAreaWidth, colorScheme, id } = model
|
|
218
|
+
const clipId = `tracks-${id}`
|
|
219
|
+
const contrastScheme = colorContrast(colorScheme, theme)
|
|
220
|
+
const msaAreaWidth = width - treeAreaWidth
|
|
221
|
+
const ctx = Context(msaAreaWidth, trackHeight)
|
|
222
|
+
|
|
223
|
+
renderAllTracks({
|
|
224
|
+
model,
|
|
225
|
+
ctx,
|
|
226
|
+
offsetX,
|
|
227
|
+
contrastScheme,
|
|
228
|
+
blockSizeXOverride: msaAreaWidth,
|
|
229
|
+
highResScaleFactorOverride: 1,
|
|
230
|
+
})
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<g transform={`translate(${treeAreaWidth} 0)`}>
|
|
234
|
+
<defs>
|
|
235
|
+
<clipPath id={clipId}>
|
|
236
|
+
<rect x={0} y={0} width={msaAreaWidth} height={trackHeight} />
|
|
237
|
+
</clipPath>
|
|
238
|
+
</defs>
|
|
239
|
+
<g
|
|
240
|
+
clipPath={`url(#${clipId})`}
|
|
241
|
+
dangerouslySetInnerHTML={{ __html: ctx.getSvg().innerHTML }}
|
|
242
|
+
/>
|
|
243
|
+
</g>
|
|
244
|
+
)
|
|
245
|
+
}
|
|
246
|
+
|
|
168
247
|
function MinimapWrapper({
|
|
169
248
|
model,
|
|
170
249
|
children,
|
|
@@ -90,11 +90,24 @@ test('with gaps in sequence', () => {
|
|
|
90
90
|
expect(globalCoordToRowSpecificCoord(sequence, 0)).toBe(0)
|
|
91
91
|
expect(globalCoordToRowSpecificCoord(sequence, 1)).toBe(1)
|
|
92
92
|
expect(globalCoordToRowSpecificCoord(sequence, 2)).toBe(2)
|
|
93
|
-
// Position
|
|
93
|
+
// Position 2 is a gap, so count before it is 2
|
|
94
94
|
expect(globalCoordToRowSpecificCoord(sequence, 3)).toBe(2)
|
|
95
95
|
expect(globalCoordToRowSpecificCoord(sequence, 4)).toBe(3)
|
|
96
96
|
expect(globalCoordToRowSpecificCoord(sequence, 5)).toBe(4)
|
|
97
|
-
// Position
|
|
97
|
+
// Position 5 is a gap, so count before it is 4
|
|
98
|
+
expect(globalCoordToRowSpecificCoord(sequence, 6)).toBe(4)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
test('with mixed gap characters (- and .)', () => {
|
|
102
|
+
const sequence = 'AC.GT-A'
|
|
103
|
+
expect(globalCoordToRowSpecificCoord(sequence, 0)).toBe(0)
|
|
104
|
+
expect(globalCoordToRowSpecificCoord(sequence, 1)).toBe(1)
|
|
105
|
+
// Position 2 is a gap (.), so count before it is 2
|
|
106
|
+
expect(globalCoordToRowSpecificCoord(sequence, 2)).toBe(2)
|
|
107
|
+
expect(globalCoordToRowSpecificCoord(sequence, 3)).toBe(2)
|
|
108
|
+
expect(globalCoordToRowSpecificCoord(sequence, 4)).toBe(3)
|
|
109
|
+
// Position 5 is a gap (-), so count before it is 4
|
|
110
|
+
expect(globalCoordToRowSpecificCoord(sequence, 5)).toBe(4)
|
|
98
111
|
expect(globalCoordToRowSpecificCoord(sequence, 6)).toBe(4)
|
|
99
112
|
})
|
|
100
113
|
|
|
@@ -12,6 +12,8 @@ export function mouseOverCoordToGlobalCoord(
|
|
|
12
12
|
// Iterate until we reach the target mouse position
|
|
13
13
|
while (mousePosition < position) {
|
|
14
14
|
// Skip any blank positions in the sequence
|
|
15
|
+
// Check if the next position (globalPosition + 1) is blank by comparing
|
|
16
|
+
// blanks[blankArrayIndex] - 1 with current globalPosition
|
|
15
17
|
while (
|
|
16
18
|
blankArrayIndex < blanksLen &&
|
|
17
19
|
blanks[blankArrayIndex]! - 1 === globalPosition
|
|
@@ -38,13 +40,9 @@ export function globalCoordToRowSpecificCoord(seq: string, position: number) {
|
|
|
38
40
|
// Iterate until we reach the target position or end of sequence
|
|
39
41
|
while (currentPosition < position && currentPosition < sequenceLength) {
|
|
40
42
|
// If current character is not a gap, increment the non-gap counter
|
|
41
|
-
if (seq[currentPosition]
|
|
43
|
+
if (!isBlank(seq[currentPosition])) {
|
|
42
44
|
nonGapCount++
|
|
43
45
|
}
|
|
44
|
-
// If we've reached the target position in non-gap coordinates, break
|
|
45
|
-
else if (nonGapCount >= position) {
|
|
46
|
-
break
|
|
47
|
-
}
|
|
48
46
|
currentPosition++
|
|
49
47
|
}
|
|
50
48
|
|
|
@@ -19,13 +19,13 @@ describe('seqCoordToRowSpecificGlobalCoord', () => {
|
|
|
19
19
|
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
|
|
20
20
|
|
|
21
21
|
// Position 1 (T after first gap) -> Global index 2
|
|
22
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(
|
|
22
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(2)
|
|
23
23
|
|
|
24
24
|
// Position 3 (C after second gap) -> Global index 5
|
|
25
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(
|
|
25
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(5)
|
|
26
26
|
|
|
27
27
|
// Position 5 (T after third gap) -> Global index 8
|
|
28
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 5 })).toBe(
|
|
28
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 5 })).toBe(8)
|
|
29
29
|
|
|
30
30
|
// Position 8 (end of sequence) -> Global index 11
|
|
31
31
|
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 8 })).toBe(11)
|
|
@@ -46,8 +46,8 @@ describe('seqCoordToRowSpecificGlobalCoord', () => {
|
|
|
46
46
|
// Sequence positions: A(0) G(1) C(2)
|
|
47
47
|
|
|
48
48
|
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 0 })).toBe(0)
|
|
49
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(
|
|
50
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 2 })).toBe(
|
|
51
|
-
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(
|
|
49
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 1 })).toBe(3)
|
|
50
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 2 })).toBe(5)
|
|
51
|
+
expect(seqCoordToRowSpecificGlobalCoord({ row, position: 3 })).toBe(7)
|
|
52
52
|
})
|
|
53
53
|
})
|
|
@@ -9,12 +9,17 @@ export function seqCoordToRowSpecificGlobalCoord({
|
|
|
9
9
|
}) {
|
|
10
10
|
let k = 0
|
|
11
11
|
let i = 0
|
|
12
|
-
|
|
12
|
+
// Find the position-th non-gap character
|
|
13
|
+
while (i < row.length) {
|
|
13
14
|
if (!isBlank(row[i])) {
|
|
15
|
+
if (k === position) {
|
|
16
|
+
return i
|
|
17
|
+
}
|
|
14
18
|
k++
|
|
15
|
-
} else if (k >= position) {
|
|
16
|
-
break
|
|
17
19
|
}
|
|
20
|
+
i++
|
|
18
21
|
}
|
|
19
|
-
return
|
|
22
|
+
// If position is 0 and we didn't find any non-gap character, return 0
|
|
23
|
+
// Otherwise return i (which is row.length at this point)
|
|
24
|
+
return position === 0 ? 0 : i
|
|
20
25
|
}
|
package/src/types.ts
CHANGED
|
@@ -12,16 +12,14 @@ export interface BasicTrackModel {
|
|
|
12
12
|
|
|
13
13
|
export interface TextTrackModel extends BasicTrackModel {
|
|
14
14
|
customColorScheme?: Record<string, string>
|
|
15
|
-
data
|
|
15
|
+
data?: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export interface
|
|
18
|
+
export interface BasicTrack {
|
|
19
19
|
ReactComponent: React.FC<any>
|
|
20
20
|
model: TextTrackModel
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export type BasicTrack = ITextTrack
|
|
24
|
-
|
|
25
23
|
export interface Node {
|
|
26
24
|
children?: Node[]
|
|
27
25
|
name?: string
|
package/src/util.ts
CHANGED
|
@@ -44,16 +44,29 @@ export function colorContrast(
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export function skipBlanks(blanks: number[], arg: string | string[]) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
if (blanks.length === 0) {
|
|
48
|
+
return typeof arg === 'string' ? arg : arg.join('')
|
|
49
|
+
}
|
|
50
|
+
const chunks = []
|
|
51
|
+
let lastEnd = 0
|
|
52
|
+
for (const blankIdx of blanks) {
|
|
53
|
+
if (blankIdx > lastEnd) {
|
|
54
|
+
chunks.push(
|
|
55
|
+
typeof arg === 'string'
|
|
56
|
+
? arg.slice(lastEnd, blankIdx)
|
|
57
|
+
: arg.slice(lastEnd, blankIdx).join(''),
|
|
58
|
+
)
|
|
54
59
|
}
|
|
60
|
+
lastEnd = blankIdx + 1
|
|
61
|
+
}
|
|
62
|
+
if (lastEnd < arg.length) {
|
|
63
|
+
chunks.push(
|
|
64
|
+
typeof arg === 'string'
|
|
65
|
+
? arg.slice(lastEnd)
|
|
66
|
+
: arg.slice(lastEnd).join(''),
|
|
67
|
+
)
|
|
55
68
|
}
|
|
56
|
-
return
|
|
69
|
+
return chunks.join('')
|
|
57
70
|
}
|
|
58
71
|
|
|
59
72
|
// basically same as setRadius from https://observablehq.com/@d3/tree-of-life
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '4.4.
|
|
1
|
+
export const version = '4.4.7'
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { Dialog } from '@jbrowse/core/ui';
|
|
3
|
-
import { Button, Checkbox, DialogActions, DialogContent, FormControlLabel, FormGroup, Typography, } from '@mui/material';
|
|
4
|
-
import { observer } from 'mobx-react';
|
|
5
|
-
const TracklistDialog = observer(function ({ model, onClose, }) {
|
|
6
|
-
const { tracks } = model;
|
|
7
|
-
return (React.createElement(Dialog, { onClose: () => {
|
|
8
|
-
onClose();
|
|
9
|
-
}, open: true, title: "Add track" },
|
|
10
|
-
React.createElement(DialogContent, null,
|
|
11
|
-
React.createElement(Typography, null, "Open relevant per-alignment tracks e.g. protein domains"),
|
|
12
|
-
React.createElement(FormGroup, null, tracks.map(track => {
|
|
13
|
-
return (React.createElement(FormControlLabel, { key: track.model.id, control: React.createElement(Checkbox, { checked: !model.turnedOffTracks.has(track.model.id), onChange: () => {
|
|
14
|
-
model.toggleTrack(track.model.id);
|
|
15
|
-
} }), label: track.model.name }));
|
|
16
|
-
})),
|
|
17
|
-
React.createElement(DialogActions, null,
|
|
18
|
-
React.createElement(Button, { onClick: () => {
|
|
19
|
-
onClose();
|
|
20
|
-
}, variant: "contained", color: "primary" }, "Close")))));
|
|
21
|
-
});
|
|
22
|
-
export default TracklistDialog;
|
|
23
|
-
//# sourceMappingURL=TracklistDialog.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"TracklistDialog.js","sourceRoot":"","sources":["../../../src/components/dialogs/TracklistDialog.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AACzC,OAAO,EACL,MAAM,EACN,QAAQ,EACR,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,SAAS,EACT,UAAU,GACX,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAIrC,MAAM,eAAe,GAAG,QAAQ,CAAC,UAAU,EACzC,KAAK,EACL,OAAO,GAIR;IACC,MAAM,EAAE,MAAM,EAAE,GAAG,KAAK,CAAA;IAExB,OAAO,CACL,oBAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,EAAE,CAAA;QACX,CAAC,EACD,IAAI,QACJ,KAAK,EAAC,WAAW;QAEjB,oBAAC,aAAa;YACZ,oBAAC,UAAU,kEAEE;YAEb,oBAAC,SAAS,QACP,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;gBAClB,OAAO,CACL,oBAAC,gBAAgB,IACf,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,EAAE,EACnB,OAAO,EACL,oBAAC,QAAQ,IACP,OAAO,EAAE,CAAC,KAAK,CAAC,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,EACnD,QAAQ,EAAE,GAAG,EAAE;4BACb,KAAK,CAAC,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAA;wBACnC,CAAC,GACD,EAEJ,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,GACvB,CACH,CAAA;YACH,CAAC,CAAC,CACQ;YACZ,oBAAC,aAAa;gBACZ,oBAAC,MAAM,IACL,OAAO,EAAE,GAAG,EAAE;wBACZ,OAAO,EAAE,CAAA;oBACX,CAAC,EACD,OAAO,EAAC,WAAW,EACnB,KAAK,EAAC,SAAS,YAGR,CACK,CACF,CACT,CACV,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,eAAe,eAAe,CAAA"}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
|
|
3
|
-
import { Dialog } from '@jbrowse/core/ui'
|
|
4
|
-
import {
|
|
5
|
-
Button,
|
|
6
|
-
Checkbox,
|
|
7
|
-
DialogActions,
|
|
8
|
-
DialogContent,
|
|
9
|
-
FormControlLabel,
|
|
10
|
-
FormGroup,
|
|
11
|
-
Typography,
|
|
12
|
-
} from '@mui/material'
|
|
13
|
-
import { observer } from 'mobx-react'
|
|
14
|
-
|
|
15
|
-
import type { MsaViewModel } from '../../model'
|
|
16
|
-
|
|
17
|
-
const TracklistDialog = observer(function ({
|
|
18
|
-
model,
|
|
19
|
-
onClose,
|
|
20
|
-
}: {
|
|
21
|
-
model: MsaViewModel
|
|
22
|
-
onClose: () => void
|
|
23
|
-
}) {
|
|
24
|
-
const { tracks } = model
|
|
25
|
-
|
|
26
|
-
return (
|
|
27
|
-
<Dialog
|
|
28
|
-
onClose={() => {
|
|
29
|
-
onClose()
|
|
30
|
-
}}
|
|
31
|
-
open
|
|
32
|
-
title="Add track"
|
|
33
|
-
>
|
|
34
|
-
<DialogContent>
|
|
35
|
-
<Typography>
|
|
36
|
-
Open relevant per-alignment tracks e.g. protein domains
|
|
37
|
-
</Typography>
|
|
38
|
-
|
|
39
|
-
<FormGroup>
|
|
40
|
-
{tracks.map(track => {
|
|
41
|
-
return (
|
|
42
|
-
<FormControlLabel
|
|
43
|
-
key={track.model.id}
|
|
44
|
-
control={
|
|
45
|
-
<Checkbox
|
|
46
|
-
checked={!model.turnedOffTracks.has(track.model.id)}
|
|
47
|
-
onChange={() => {
|
|
48
|
-
model.toggleTrack(track.model.id)
|
|
49
|
-
}}
|
|
50
|
-
/>
|
|
51
|
-
}
|
|
52
|
-
label={track.model.name}
|
|
53
|
-
/>
|
|
54
|
-
)
|
|
55
|
-
})}
|
|
56
|
-
</FormGroup>
|
|
57
|
-
<DialogActions>
|
|
58
|
-
<Button
|
|
59
|
-
onClick={() => {
|
|
60
|
-
onClose()
|
|
61
|
-
}}
|
|
62
|
-
variant="contained"
|
|
63
|
-
color="primary"
|
|
64
|
-
>
|
|
65
|
-
Close
|
|
66
|
-
</Button>
|
|
67
|
-
</DialogActions>
|
|
68
|
-
</DialogContent>
|
|
69
|
-
</Dialog>
|
|
70
|
-
)
|
|
71
|
-
})
|
|
72
|
-
|
|
73
|
-
export default TracklistDialog
|