jbrowse-plugin-graphgenomeviewer 7.1.2 → 7.1.3
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/dist/chunks/{GraphGenomeView-NJ5XCREB.js → GraphGenomeView-LX7GDEDM.js} +2 -2
- package/dist/chunks/{LinearGraphDisplay-TXTKAACH.js → LinearGraphDisplay-QLPIRKPR.js} +2 -2
- package/dist/chunks/{WalkTabixSyntenyAdapter-U53JLYVU.js → WalkTabixSyntenyAdapter-GH6NYQTF.js} +2 -2
- package/dist/chunks/{WalkTabixSyntenyAdapter-U53JLYVU.js.map → WalkTabixSyntenyAdapter-GH6NYQTF.js.map} +1 -1
- package/dist/chunks/{chunk-NWJYLP6Z.js → chunk-6PC7WKLS.js} +2 -2
- package/dist/chunks/chunk-BHSELHTZ.js +2 -0
- package/dist/chunks/chunk-BHSELHTZ.js.map +7 -0
- package/dist/chunks/{chunk-WEGWTC52.js → chunk-LBY7U6OJ.js} +2 -2
- package/dist/chunks/{chunk-WEGWTC52.js.map → chunk-LBY7U6OJ.js.map} +4 -4
- package/dist/chunks/chunk-LVQUQSAH.js +3 -0
- package/dist/chunks/chunk-LVQUQSAH.js.map +7 -0
- package/dist/chunks/chunk-PJ43KEV6.js +2 -0
- package/dist/chunks/chunk-PJ43KEV6.js.map +7 -0
- package/dist/chunks/renderSvg-GGJXJHCS.js +2 -0
- package/dist/chunks/renderSvg-GGJXJHCS.js.map +7 -0
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js +3 -3
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js.map +4 -4
- package/package.json +1 -1
- package/src/GbzBaseSyntenyAdapter/configSchema.ts +2 -2
- package/src/GetSubgraph.ts +1 -1
- package/src/GraphGenomeView/components/Legend.tsx +3 -121
- package/src/GraphGenomeView/components/LegendSwatch.tsx +237 -0
- package/src/GraphGenomeView/components/PaneSvg.tsx +2 -189
- package/src/GraphGenomeView/components/WalkStrip.tsx +1 -1
- package/src/GraphTrack/index.ts +2 -2
- package/src/LinearGraphDisplay/denseWindow.ts +0 -14
- package/src/LinearGraphDisplay/model.ts +2 -1
- package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.ts +1 -1
- package/src/nodeLimitError.ts +12 -0
- package/src/version.ts +1 -1
- package/dist/chunks/chunk-2MCOY3YG.js +0 -3
- package/dist/chunks/chunk-2MCOY3YG.js.map +0 -7
- package/dist/chunks/chunk-MURN3JPK.js +0 -2
- package/dist/chunks/chunk-MURN3JPK.js.map +0 -7
- package/dist/chunks/chunk-WCGVUZWP.js +0 -2
- package/dist/chunks/chunk-WCGVUZWP.js.map +0 -7
- package/dist/chunks/renderSvg-KSQI5DH6.js +0 -2
- package/dist/chunks/renderSvg-KSQI5DH6.js.map +0 -7
- /package/dist/chunks/{GraphGenomeView-NJ5XCREB.js.map → GraphGenomeView-LX7GDEDM.js.map} +0 -0
- /package/dist/chunks/{LinearGraphDisplay-TXTKAACH.js.map → LinearGraphDisplay-QLPIRKPR.js.map} +0 -0
- /package/dist/chunks/{chunk-NWJYLP6Z.js.map → chunk-6PC7WKLS.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jbrowse-plugin-graphgenomeviewer",
|
|
3
|
-
"version": "7.1.
|
|
3
|
+
"version": "7.1.3",
|
|
4
4
|
"description": "JBrowse 2 graph genome (pangenome) view: rGFA reference-anchored layouts, the Bandage force-directed engine, and haplotype lanes read from a gbz-base database",
|
|
5
5
|
"license": "GPL-3.0-or-later",
|
|
6
6
|
"repository": {
|
|
@@ -22,8 +22,8 @@ import type { Instance } from '@jbrowse/mobx-state-tree'
|
|
|
22
22
|
* haplotype a walk belongs to.
|
|
23
23
|
*
|
|
24
24
|
* Only the fine tier exists: a whole-chromosome view stays on a PIF's coarse
|
|
25
|
-
* tier. A
|
|
26
|
-
*
|
|
25
|
+
* tier. A window of the anchor answers any two lanes' alignment, so the
|
|
26
|
+
* multi-way display fetches each adjacent lane pair directly.
|
|
27
27
|
*
|
|
28
28
|
* #example
|
|
29
29
|
* ```js
|
package/src/GetSubgraph.ts
CHANGED
|
@@ -65,7 +65,7 @@ declare module '@jbrowse/core/rpc/RpcRegistry' {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
// Adapters that can cut a local subgraph out of a graph file implement this:
|
|
68
|
-
// RgfaTabixAdapter and GbzBaseSyntenyAdapter
|
|
68
|
+
// RgfaTabixAdapter, WalkTabixSyntenyAdapter and GbzBaseSyntenyAdapter.
|
|
69
69
|
interface SubgraphAdapter {
|
|
70
70
|
getSubgraph(
|
|
71
71
|
region: Region,
|
|
@@ -1,132 +1,14 @@
|
|
|
1
1
|
import type { ReactNode } from 'react'
|
|
2
2
|
|
|
3
|
-
import { rulerInk } from '@jbrowse/bandage-core/tubeMap/axis'
|
|
4
3
|
import { observer } from 'mobx-react'
|
|
5
4
|
|
|
6
|
-
import {
|
|
5
|
+
import { LegendSwatchView } from './LegendSwatch'
|
|
7
6
|
import { legendBoxStyle, legendNoteStyle, legendRowStyle } from './legendStyles'
|
|
7
|
+
import { legendSections } from '../legendSections'
|
|
8
8
|
|
|
9
|
-
import type { LegendRow
|
|
9
|
+
import type { LegendRow } from '../legendSections'
|
|
10
10
|
import type { GraphPaneModel } from '../model'
|
|
11
11
|
|
|
12
|
-
function stopsCss(stops: readonly Stop[]) {
|
|
13
|
-
return stops.length === 1
|
|
14
|
-
? stops[0]!.color
|
|
15
|
-
: `linear-gradient(to right, ${stops.map(s => `${s.color} ${s.offset * 100}%`).join(', ')})`
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const glyphStyle = {
|
|
19
|
-
width: SWATCH_PX,
|
|
20
|
-
flex: 'none',
|
|
21
|
-
textAlign: 'center' as const,
|
|
22
|
-
fontFamily: 'monospace',
|
|
23
|
-
fontSize: 12,
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
export function LegendSwatchView({ swatch }: { swatch: LegendSwatch }) {
|
|
27
|
-
const width = swatchWidth(swatch)
|
|
28
|
-
const box = { width, flex: 'none' }
|
|
29
|
-
switch (swatch.kind) {
|
|
30
|
-
case 'fill':
|
|
31
|
-
return (
|
|
32
|
-
<div
|
|
33
|
-
style={{
|
|
34
|
-
...box,
|
|
35
|
-
height: swatch.height ?? 8,
|
|
36
|
-
borderRadius: swatch.square ? 0 : 2,
|
|
37
|
-
background: stopsCss(swatch.stops),
|
|
38
|
-
}}
|
|
39
|
-
/>
|
|
40
|
-
)
|
|
41
|
-
case 'bands':
|
|
42
|
-
return (
|
|
43
|
-
<div style={box}>
|
|
44
|
-
{swatch.bands.map((stops, i) => (
|
|
45
|
-
<div
|
|
46
|
-
key={i}
|
|
47
|
-
style={{
|
|
48
|
-
height: swatch.bands.length > 1 ? 3 : 4,
|
|
49
|
-
background: stopsCss(stops),
|
|
50
|
-
}}
|
|
51
|
-
/>
|
|
52
|
-
))}
|
|
53
|
-
</div>
|
|
54
|
-
)
|
|
55
|
-
case 'line':
|
|
56
|
-
return (
|
|
57
|
-
<div
|
|
58
|
-
style={{
|
|
59
|
-
...box,
|
|
60
|
-
height: 3,
|
|
61
|
-
borderRadius: 2,
|
|
62
|
-
background: swatch.color,
|
|
63
|
-
}}
|
|
64
|
-
/>
|
|
65
|
-
)
|
|
66
|
-
case 'halo':
|
|
67
|
-
return (
|
|
68
|
-
<svg width={width} height={10} style={{ flex: 'none' }}>
|
|
69
|
-
<line
|
|
70
|
-
x1={5}
|
|
71
|
-
y1={5}
|
|
72
|
-
x2={13}
|
|
73
|
-
y2={5}
|
|
74
|
-
stroke={swatch.color}
|
|
75
|
-
strokeOpacity={0.35}
|
|
76
|
-
strokeWidth={8}
|
|
77
|
-
strokeLinecap="round"
|
|
78
|
-
/>
|
|
79
|
-
</svg>
|
|
80
|
-
)
|
|
81
|
-
case 'outline':
|
|
82
|
-
return (
|
|
83
|
-
<div
|
|
84
|
-
style={{
|
|
85
|
-
...box,
|
|
86
|
-
height: swatch.height,
|
|
87
|
-
boxSizing: 'border-box',
|
|
88
|
-
border: `${swatch.stroke}px solid ${swatch.color}`,
|
|
89
|
-
borderRadius: swatch.radius,
|
|
90
|
-
}}
|
|
91
|
-
/>
|
|
92
|
-
)
|
|
93
|
-
case 'overhang':
|
|
94
|
-
return (
|
|
95
|
-
<svg width={width} height={10} style={{ flex: 'none' }}>
|
|
96
|
-
<path d="M0,5 L8,0 L8,10 Z M18,5 L10,0 L10,10 Z" fill="#18181c" />
|
|
97
|
-
</svg>
|
|
98
|
-
)
|
|
99
|
-
case 'glyph':
|
|
100
|
-
return <span style={glyphStyle}>{swatch.char}</span>
|
|
101
|
-
case 'tick':
|
|
102
|
-
return (
|
|
103
|
-
<div
|
|
104
|
-
style={{
|
|
105
|
-
...box,
|
|
106
|
-
height: swatch.height,
|
|
107
|
-
display: 'flex',
|
|
108
|
-
justifyContent: 'center',
|
|
109
|
-
background: swatch.backing,
|
|
110
|
-
}}
|
|
111
|
-
>
|
|
112
|
-
<div style={{ width: 2, backgroundColor: swatch.color }} />
|
|
113
|
-
</div>
|
|
114
|
-
)
|
|
115
|
-
case 'bracket':
|
|
116
|
-
return (
|
|
117
|
-
<svg width={width} height={7} style={{ flex: 'none' }}>
|
|
118
|
-
<path
|
|
119
|
-
d={`M0.5,6 V1.5 H5.5 V6 M8.5,6 V1.5 H${SWATCH_PX - 0.5} V6`}
|
|
120
|
-
fill="none"
|
|
121
|
-
stroke={rulerInk()}
|
|
122
|
-
/>
|
|
123
|
-
</svg>
|
|
124
|
-
)
|
|
125
|
-
case 'blank':
|
|
126
|
-
return <span style={box} />
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
12
|
// One row: its swatch then its words, or a note with neither. `at`, where
|
|
131
13
|
// the hovered node sits on a walk, stands in for the line under it.
|
|
132
14
|
export function LegendRowView({
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { rulerInk } from '@jbrowse/bandage-core/tubeMap/axis'
|
|
2
|
+
|
|
3
|
+
import { useSvgId } from './ElTree'
|
|
4
|
+
import { SWATCH_PX, swatchWidth } from '../legendSections'
|
|
5
|
+
|
|
6
|
+
import type { LegendSwatch, Stop } from '../legendSections'
|
|
7
|
+
|
|
8
|
+
function Gradient({
|
|
9
|
+
id,
|
|
10
|
+
x,
|
|
11
|
+
y,
|
|
12
|
+
stops,
|
|
13
|
+
width,
|
|
14
|
+
height,
|
|
15
|
+
square,
|
|
16
|
+
}: {
|
|
17
|
+
id: string
|
|
18
|
+
x: number
|
|
19
|
+
y: number
|
|
20
|
+
stops: readonly Stop[]
|
|
21
|
+
width: number
|
|
22
|
+
height: number
|
|
23
|
+
square?: boolean
|
|
24
|
+
}) {
|
|
25
|
+
const rect = (fill: string) => (
|
|
26
|
+
<rect
|
|
27
|
+
x={x}
|
|
28
|
+
y={y}
|
|
29
|
+
width={width}
|
|
30
|
+
height={height}
|
|
31
|
+
rx={square ? 0 : 2}
|
|
32
|
+
fill={fill}
|
|
33
|
+
/>
|
|
34
|
+
)
|
|
35
|
+
return stops.length > 1 ? (
|
|
36
|
+
<>
|
|
37
|
+
<defs>
|
|
38
|
+
<linearGradient id={id}>
|
|
39
|
+
{stops.map((s, i) => (
|
|
40
|
+
<stop key={i} offset={s.offset} stopColor={s.color} />
|
|
41
|
+
))}
|
|
42
|
+
</linearGradient>
|
|
43
|
+
</defs>
|
|
44
|
+
{rect(`url(#${id})`)}
|
|
45
|
+
</>
|
|
46
|
+
) : (
|
|
47
|
+
rect(stops[0]!.color)
|
|
48
|
+
)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const bandPx = (bands: readonly unknown[]) => (bands.length > 1 ? 3 : 4)
|
|
52
|
+
|
|
53
|
+
function swatchHeight(swatch: LegendSwatch) {
|
|
54
|
+
switch (swatch.kind) {
|
|
55
|
+
case 'fill':
|
|
56
|
+
return swatch.height ?? 8
|
|
57
|
+
case 'bands':
|
|
58
|
+
return bandPx(swatch.bands) * swatch.bands.length
|
|
59
|
+
case 'line':
|
|
60
|
+
return 3
|
|
61
|
+
case 'halo':
|
|
62
|
+
case 'overhang':
|
|
63
|
+
return 10
|
|
64
|
+
case 'outline':
|
|
65
|
+
case 'tick':
|
|
66
|
+
return swatch.height
|
|
67
|
+
case 'glyph':
|
|
68
|
+
return 15
|
|
69
|
+
case 'bracket':
|
|
70
|
+
return 7
|
|
71
|
+
case 'blank':
|
|
72
|
+
return 0
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// A row's swatch with its left edge at x, centred on the row's text 5 px
|
|
77
|
+
// above the baseline
|
|
78
|
+
export function SvgSwatch({
|
|
79
|
+
swatch,
|
|
80
|
+
x,
|
|
81
|
+
id,
|
|
82
|
+
}: {
|
|
83
|
+
swatch: LegendSwatch
|
|
84
|
+
x: number
|
|
85
|
+
id: string
|
|
86
|
+
}) {
|
|
87
|
+
const mid = -5
|
|
88
|
+
switch (swatch.kind) {
|
|
89
|
+
case 'fill': {
|
|
90
|
+
const height = swatchHeight(swatch)
|
|
91
|
+
return (
|
|
92
|
+
<Gradient
|
|
93
|
+
id={id}
|
|
94
|
+
x={x}
|
|
95
|
+
y={mid - height / 2}
|
|
96
|
+
stops={swatch.stops}
|
|
97
|
+
width={swatchWidth(swatch)}
|
|
98
|
+
height={height}
|
|
99
|
+
square={swatch.square}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
case 'bands': {
|
|
104
|
+
const band = bandPx(swatch.bands)
|
|
105
|
+
const top = mid - swatchHeight(swatch) / 2
|
|
106
|
+
return (
|
|
107
|
+
<>
|
|
108
|
+
{swatch.bands.map((stops, i) => (
|
|
109
|
+
<Gradient
|
|
110
|
+
key={i}
|
|
111
|
+
id={`${id}-${i}`}
|
|
112
|
+
x={x}
|
|
113
|
+
y={top + i * band}
|
|
114
|
+
stops={stops}
|
|
115
|
+
width={SWATCH_PX}
|
|
116
|
+
height={band}
|
|
117
|
+
square
|
|
118
|
+
/>
|
|
119
|
+
))}
|
|
120
|
+
</>
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
case 'line':
|
|
124
|
+
return (
|
|
125
|
+
<rect
|
|
126
|
+
x={x}
|
|
127
|
+
y={mid - 1.5}
|
|
128
|
+
width={SWATCH_PX}
|
|
129
|
+
height={3}
|
|
130
|
+
rx={2}
|
|
131
|
+
fill={swatch.color}
|
|
132
|
+
/>
|
|
133
|
+
)
|
|
134
|
+
case 'halo':
|
|
135
|
+
return (
|
|
136
|
+
<line
|
|
137
|
+
x1={x + 5}
|
|
138
|
+
x2={x + 13}
|
|
139
|
+
y1={mid}
|
|
140
|
+
y2={mid}
|
|
141
|
+
stroke={swatch.color}
|
|
142
|
+
strokeOpacity={0.35}
|
|
143
|
+
strokeWidth={8}
|
|
144
|
+
strokeLinecap="round"
|
|
145
|
+
/>
|
|
146
|
+
)
|
|
147
|
+
case 'outline': {
|
|
148
|
+
const inset = swatch.stroke / 2
|
|
149
|
+
return (
|
|
150
|
+
<rect
|
|
151
|
+
x={x + inset}
|
|
152
|
+
y={mid - swatch.height / 2 + inset}
|
|
153
|
+
width={SWATCH_PX - swatch.stroke}
|
|
154
|
+
height={swatch.height - swatch.stroke}
|
|
155
|
+
rx={Math.max(0, swatch.radius - inset)}
|
|
156
|
+
fill="none"
|
|
157
|
+
stroke={swatch.color}
|
|
158
|
+
strokeWidth={swatch.stroke}
|
|
159
|
+
/>
|
|
160
|
+
)
|
|
161
|
+
}
|
|
162
|
+
case 'overhang':
|
|
163
|
+
return (
|
|
164
|
+
<path
|
|
165
|
+
transform={`translate(${x} ${mid - 5})`}
|
|
166
|
+
d="M0,5 L8,0 L8,10 Z M18,5 L10,0 L10,10 Z"
|
|
167
|
+
fill="#18181c"
|
|
168
|
+
/>
|
|
169
|
+
)
|
|
170
|
+
case 'glyph':
|
|
171
|
+
return (
|
|
172
|
+
<text
|
|
173
|
+
x={x + SWATCH_PX / 2}
|
|
174
|
+
y={mid + 4}
|
|
175
|
+
textAnchor="middle"
|
|
176
|
+
fontFamily="monospace"
|
|
177
|
+
fontSize={12}
|
|
178
|
+
fill="currentColor"
|
|
179
|
+
>
|
|
180
|
+
{swatch.char}
|
|
181
|
+
</text>
|
|
182
|
+
)
|
|
183
|
+
case 'tick': {
|
|
184
|
+
const y = mid - swatch.height / 2
|
|
185
|
+
return (
|
|
186
|
+
<>
|
|
187
|
+
{swatch.backing ? (
|
|
188
|
+
<rect
|
|
189
|
+
x={x}
|
|
190
|
+
y={y}
|
|
191
|
+
width={SWATCH_PX}
|
|
192
|
+
height={swatch.height}
|
|
193
|
+
fill={swatch.backing}
|
|
194
|
+
/>
|
|
195
|
+
) : null}
|
|
196
|
+
<rect
|
|
197
|
+
x={x + SWATCH_PX / 2 - 1}
|
|
198
|
+
y={y}
|
|
199
|
+
width={2}
|
|
200
|
+
height={swatch.height}
|
|
201
|
+
fill={swatch.color}
|
|
202
|
+
/>
|
|
203
|
+
</>
|
|
204
|
+
)
|
|
205
|
+
}
|
|
206
|
+
case 'bracket':
|
|
207
|
+
return (
|
|
208
|
+
<path
|
|
209
|
+
transform={`translate(${x} ${mid - 3.5})`}
|
|
210
|
+
d={`M0.5,6 V1.5 H5.5 V6 M8.5,6 V1.5 H${SWATCH_PX - 0.5} V6`}
|
|
211
|
+
fill="none"
|
|
212
|
+
stroke={rulerInk()}
|
|
213
|
+
/>
|
|
214
|
+
)
|
|
215
|
+
case 'blank':
|
|
216
|
+
return null
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// The same swatch on screen, in a box as tall as the swatch so the row
|
|
221
|
+
// centres it on its words
|
|
222
|
+
export function LegendSwatchView({ swatch }: { swatch: LegendSwatch }) {
|
|
223
|
+
const id = useSvgId()
|
|
224
|
+
const height = swatchHeight(swatch)
|
|
225
|
+
return (
|
|
226
|
+
<svg
|
|
227
|
+
width={swatchWidth(swatch)}
|
|
228
|
+
height={height}
|
|
229
|
+
overflow="visible"
|
|
230
|
+
style={{ flex: 'none' }}
|
|
231
|
+
>
|
|
232
|
+
<g transform={`translate(0 ${height / 2 + 5})`}>
|
|
233
|
+
<SvgSwatch swatch={swatch} x={0} id={id} />
|
|
234
|
+
</g>
|
|
235
|
+
</svg>
|
|
236
|
+
)
|
|
237
|
+
}
|
|
@@ -3,24 +3,23 @@ import { LEGEND_INSET_PX } from '@jbrowse/bandage-core/labelLayout'
|
|
|
3
3
|
import { LABEL_CHAR_PX } from '@jbrowse/bandage-core/overlayLabels'
|
|
4
4
|
import { Canvas2DRenderer } from '@jbrowse/bandage-core/renderer/Canvas2DRenderer'
|
|
5
5
|
import { svgCanvas } from '@jbrowse/bandage-core/renderer/svgCanvas'
|
|
6
|
-
import { rulerInk } from '@jbrowse/bandage-core/tubeMap/axis'
|
|
7
6
|
import { PaintLayer } from '@jbrowse/core/util/paintLayer'
|
|
8
7
|
|
|
9
8
|
import BubbleHalos from './BubbleHalos'
|
|
10
9
|
import GenePins from './GenePins'
|
|
11
10
|
import LabelLayer from './LabelLayer'
|
|
11
|
+
import { SvgSwatch } from './LegendSwatch'
|
|
12
12
|
import { paintReferenceStrip } from './ReferenceStripOverlay'
|
|
13
13
|
import { paintTubeMap } from './TubeMapOverlay'
|
|
14
14
|
import WalkRowsOverlay from './WalkRowsOverlay'
|
|
15
15
|
import {
|
|
16
|
-
SWATCH_PX,
|
|
17
16
|
facetKeyRows,
|
|
18
17
|
legendSections,
|
|
19
18
|
swatchWidth,
|
|
20
19
|
walkKeyRow,
|
|
21
20
|
} from '../legendSections'
|
|
22
21
|
|
|
23
|
-
import type { LegendRow
|
|
22
|
+
import type { LegendRow } from '../legendSections'
|
|
24
23
|
import type { GraphPaneModel } from '../model'
|
|
25
24
|
import type { WalkLift } from '@jbrowse/bandage-core/walkHighlight'
|
|
26
25
|
import type { Ctx2D } from '@jbrowse/core/util/paintLayer'
|
|
@@ -79,192 +78,6 @@ function Body({
|
|
|
79
78
|
)
|
|
80
79
|
}
|
|
81
80
|
|
|
82
|
-
function Gradient({
|
|
83
|
-
id,
|
|
84
|
-
x,
|
|
85
|
-
y,
|
|
86
|
-
stops,
|
|
87
|
-
width,
|
|
88
|
-
height,
|
|
89
|
-
square,
|
|
90
|
-
}: {
|
|
91
|
-
id: string
|
|
92
|
-
x: number
|
|
93
|
-
y: number
|
|
94
|
-
stops: readonly Stop[]
|
|
95
|
-
width: number
|
|
96
|
-
height: number
|
|
97
|
-
square?: boolean
|
|
98
|
-
}) {
|
|
99
|
-
const rect = (fill: string) => (
|
|
100
|
-
<rect
|
|
101
|
-
x={x}
|
|
102
|
-
y={y}
|
|
103
|
-
width={width}
|
|
104
|
-
height={height}
|
|
105
|
-
rx={square ? 0 : 2}
|
|
106
|
-
fill={fill}
|
|
107
|
-
/>
|
|
108
|
-
)
|
|
109
|
-
return stops.length > 1 ? (
|
|
110
|
-
<>
|
|
111
|
-
<defs>
|
|
112
|
-
<linearGradient id={id}>
|
|
113
|
-
{stops.map((s, i) => (
|
|
114
|
-
<stop key={i} offset={s.offset} stopColor={s.color} />
|
|
115
|
-
))}
|
|
116
|
-
</linearGradient>
|
|
117
|
-
</defs>
|
|
118
|
-
{rect(`url(#${id})`)}
|
|
119
|
-
</>
|
|
120
|
-
) : (
|
|
121
|
-
rect(stops[0]!.color)
|
|
122
|
-
)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// A row's swatch with its left edge at x, centred on the row's text 5 px
|
|
126
|
-
// above the baseline, as the screen centres it
|
|
127
|
-
function SvgSwatch({
|
|
128
|
-
swatch,
|
|
129
|
-
x,
|
|
130
|
-
id,
|
|
131
|
-
}: {
|
|
132
|
-
swatch: LegendSwatch
|
|
133
|
-
x: number
|
|
134
|
-
id: string
|
|
135
|
-
}) {
|
|
136
|
-
const mid = -5
|
|
137
|
-
switch (swatch.kind) {
|
|
138
|
-
case 'fill': {
|
|
139
|
-
const height = swatch.height ?? 8
|
|
140
|
-
return (
|
|
141
|
-
<Gradient
|
|
142
|
-
id={id}
|
|
143
|
-
x={x}
|
|
144
|
-
y={mid - height / 2}
|
|
145
|
-
stops={swatch.stops}
|
|
146
|
-
width={swatchWidth(swatch)}
|
|
147
|
-
height={height}
|
|
148
|
-
square={swatch.square}
|
|
149
|
-
/>
|
|
150
|
-
)
|
|
151
|
-
}
|
|
152
|
-
case 'bands': {
|
|
153
|
-
const band = swatch.bands.length > 1 ? 3 : 4
|
|
154
|
-
const top = mid - (band * swatch.bands.length) / 2
|
|
155
|
-
return (
|
|
156
|
-
<>
|
|
157
|
-
{swatch.bands.map((stops, i) => (
|
|
158
|
-
<Gradient
|
|
159
|
-
key={i}
|
|
160
|
-
id={`${id}-${i}`}
|
|
161
|
-
x={x}
|
|
162
|
-
y={top + i * band}
|
|
163
|
-
stops={stops}
|
|
164
|
-
width={SWATCH_PX}
|
|
165
|
-
height={band}
|
|
166
|
-
square
|
|
167
|
-
/>
|
|
168
|
-
))}
|
|
169
|
-
</>
|
|
170
|
-
)
|
|
171
|
-
}
|
|
172
|
-
case 'line':
|
|
173
|
-
return (
|
|
174
|
-
<rect
|
|
175
|
-
x={x}
|
|
176
|
-
y={mid - 1.5}
|
|
177
|
-
width={SWATCH_PX}
|
|
178
|
-
height={3}
|
|
179
|
-
rx={2}
|
|
180
|
-
fill={swatch.color}
|
|
181
|
-
/>
|
|
182
|
-
)
|
|
183
|
-
case 'halo':
|
|
184
|
-
return (
|
|
185
|
-
<line
|
|
186
|
-
x1={x + 5}
|
|
187
|
-
x2={x + 13}
|
|
188
|
-
y1={mid}
|
|
189
|
-
y2={mid}
|
|
190
|
-
stroke={swatch.color}
|
|
191
|
-
strokeOpacity={0.35}
|
|
192
|
-
strokeWidth={8}
|
|
193
|
-
strokeLinecap="round"
|
|
194
|
-
/>
|
|
195
|
-
)
|
|
196
|
-
case 'outline': {
|
|
197
|
-
const inset = swatch.stroke / 2
|
|
198
|
-
return (
|
|
199
|
-
<rect
|
|
200
|
-
x={x + inset}
|
|
201
|
-
y={mid - swatch.height / 2 + inset}
|
|
202
|
-
width={SWATCH_PX - swatch.stroke}
|
|
203
|
-
height={swatch.height - swatch.stroke}
|
|
204
|
-
rx={Math.max(0, swatch.radius - inset)}
|
|
205
|
-
fill="none"
|
|
206
|
-
stroke={swatch.color}
|
|
207
|
-
strokeWidth={swatch.stroke}
|
|
208
|
-
/>
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
case 'overhang':
|
|
212
|
-
return (
|
|
213
|
-
<path
|
|
214
|
-
transform={`translate(${x} ${mid - 5})`}
|
|
215
|
-
d="M0,5 L8,0 L8,10 Z M18,5 L10,0 L10,10 Z"
|
|
216
|
-
fill="#18181c"
|
|
217
|
-
/>
|
|
218
|
-
)
|
|
219
|
-
case 'glyph':
|
|
220
|
-
return (
|
|
221
|
-
<text
|
|
222
|
-
x={x + SWATCH_PX / 2}
|
|
223
|
-
y={0}
|
|
224
|
-
textAnchor="middle"
|
|
225
|
-
fontFamily="monospace"
|
|
226
|
-
fontSize={12}
|
|
227
|
-
>
|
|
228
|
-
{swatch.char}
|
|
229
|
-
</text>
|
|
230
|
-
)
|
|
231
|
-
case 'tick': {
|
|
232
|
-
const y = mid - swatch.height / 2
|
|
233
|
-
return (
|
|
234
|
-
<>
|
|
235
|
-
{swatch.backing ? (
|
|
236
|
-
<rect
|
|
237
|
-
x={x}
|
|
238
|
-
y={y}
|
|
239
|
-
width={SWATCH_PX}
|
|
240
|
-
height={swatch.height}
|
|
241
|
-
fill={swatch.backing}
|
|
242
|
-
/>
|
|
243
|
-
) : null}
|
|
244
|
-
<rect
|
|
245
|
-
x={x + SWATCH_PX / 2 - 1}
|
|
246
|
-
y={y}
|
|
247
|
-
width={2}
|
|
248
|
-
height={swatch.height}
|
|
249
|
-
fill={swatch.color}
|
|
250
|
-
/>
|
|
251
|
-
</>
|
|
252
|
-
)
|
|
253
|
-
}
|
|
254
|
-
case 'bracket':
|
|
255
|
-
return (
|
|
256
|
-
<path
|
|
257
|
-
transform={`translate(${x} ${mid - 4})`}
|
|
258
|
-
d={`M0.5,6 V1.5 H5.5 V6 M8.5,6 V1.5 H${SWATCH_PX - 0.5} V6`}
|
|
259
|
-
fill="none"
|
|
260
|
-
stroke={rulerInk()}
|
|
261
|
-
/>
|
|
262
|
-
)
|
|
263
|
-
case 'blank':
|
|
264
|
-
return null
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
81
|
interface KeyRow {
|
|
269
82
|
key: string
|
|
270
83
|
width: number
|
|
@@ -16,7 +16,7 @@ import { isAlive } from '@jbrowse/mobx-state-tree'
|
|
|
16
16
|
import { observer } from 'mobx-react'
|
|
17
17
|
|
|
18
18
|
import ElTree, { useSvgId } from './ElTree'
|
|
19
|
-
import { LegendSwatchView } from './
|
|
19
|
+
import { LegendSwatchView } from './LegendSwatch'
|
|
20
20
|
import PaneContextMenu from './PaneContextMenu'
|
|
21
21
|
import { legendRowStyle } from './legendStyles'
|
|
22
22
|
import { walkRowSwatch } from '../legendSections'
|
package/src/GraphTrack/index.ts
CHANGED
|
@@ -8,8 +8,8 @@ import {
|
|
|
8
8
|
import type PluginManager from '@jbrowse/core/PluginManager'
|
|
9
9
|
import type DisplayType from '@jbrowse/core/pluggableElementTypes/DisplayType'
|
|
10
10
|
|
|
11
|
-
// core's synteny displays, copied to ask for headerLanes so only gbz-base
|
|
12
|
-
//
|
|
11
|
+
// core's synteny displays, copied to ask for headerLanes so only the gbz-base
|
|
12
|
+
// and walk-tabix adapters open in a synteny, dotplot or circular view
|
|
13
13
|
export const SYNTENY_DISPLAYS = [
|
|
14
14
|
'MultiWaySyntenyDisplay',
|
|
15
15
|
'LinearSyntenyDisplay',
|
|
@@ -1,20 +1,6 @@
|
|
|
1
1
|
import type { SubgraphRegion } from '../GetSubgraph'
|
|
2
2
|
import type { HostWindow } from '../GraphGenomeView/host'
|
|
3
3
|
|
|
4
|
-
// A cut refused for its node count: the GBZ adapter's own error, marked
|
|
5
|
-
// regionTooLarge so core shows it as a zoom-in notice, or gbz-base's when it
|
|
6
|
-
// reaches the display unwrapped
|
|
7
|
-
export function isNodeLimitError(error: unknown) {
|
|
8
|
-
return (
|
|
9
|
-
error instanceof Error &&
|
|
10
|
-
(error.name === 'NodeLimitError' ||
|
|
11
|
-
(error as { regionTooLarge?: unknown }).regionTooLarge === true ||
|
|
12
|
-
/reads more than nodeLimit|^Subgraph size limit of \d+ nodes exceeded/.test(
|
|
13
|
-
error.message,
|
|
14
|
-
))
|
|
15
|
-
)
|
|
16
|
-
}
|
|
17
|
-
|
|
18
4
|
// Whether `seen` is near where a cut came back over its node limit. The graph
|
|
19
5
|
// is as dense as that only near it, so the refusal stands for windows as wide
|
|
20
6
|
// or wider on the same contig within one window-width of it.
|
|
@@ -23,7 +23,8 @@ import RouteIcon from '@mui/icons-material/Route'
|
|
|
23
23
|
import SettingsIcon from '@mui/icons-material/Settings'
|
|
24
24
|
import { reaction } from 'mobx'
|
|
25
25
|
|
|
26
|
-
import {
|
|
26
|
+
import { isNodeLimitError } from '../nodeLimitError'
|
|
27
|
+
import { denseCovers } from './denseWindow'
|
|
27
28
|
import { cutHolds, hostCut, hostWindow } from '../GraphGenomeView/host'
|
|
28
29
|
import { lenientOptionalEnum } from '../GraphGenomeView/lenientEnum'
|
|
29
30
|
import { GraphPane, formatSpanBp } from '../GraphGenomeView/model'
|
|
@@ -11,8 +11,8 @@ import { ObservableCreate } from '@jbrowse/core/util/rxjs'
|
|
|
11
11
|
import { walksKept } from '@jbrowse/graph-walks'
|
|
12
12
|
|
|
13
13
|
import { chainFeature, referenceAligner, walkAligner } from './walkLanes.ts'
|
|
14
|
-
import { isNodeLimitError } from '../LinearGraphDisplay/denseWindow.ts'
|
|
15
14
|
import { WalkIndex } from '../RgfaTabixAdapter/walkReader.ts'
|
|
15
|
+
import { isNodeLimitError } from '../nodeLimitError.ts'
|
|
16
16
|
import { PanSNRefNames, openTabixSlot } from '../panSNTabix.ts'
|
|
17
17
|
import { ComparativeAdapterBase } from '../synteny/ComparativeAdapterBase.ts'
|
|
18
18
|
import {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// The GBZ adapter's own refusal, marked regionTooLarge so core shows it as a
|
|
2
|
+
// zoom-in notice, or gbz-base's when it reaches the display unwrapped
|
|
3
|
+
export function isNodeLimitError(error: unknown) {
|
|
4
|
+
return (
|
|
5
|
+
error instanceof Error &&
|
|
6
|
+
(error.name === 'NodeLimitError' ||
|
|
7
|
+
(error as { regionTooLarge?: unknown }).regionTooLarge === true ||
|
|
8
|
+
/reads more than nodeLimit|^Subgraph size limit of \d+ nodes exceeded/.test(
|
|
9
|
+
error.message,
|
|
10
|
+
))
|
|
11
|
+
)
|
|
12
|
+
}
|