jbrowse-plugin-graphgenomeviewer 4.0.0 → 4.0.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/README.md +6 -5
- package/dist/chunks/LinearGraphDisplay-7POYIRIB.js +2 -0
- package/dist/chunks/{LinearGraphDisplay-P7U6NCZF.js.map → LinearGraphDisplay-7POYIRIB.js.map} +2 -2
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js +2 -2
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js.map +3 -3
- package/package.json +1 -1
- package/src/LinearGraphDisplay/LinearGraphDisplay.test.ts +88 -19
- package/src/LinearGraphDisplay/components/LinearGraphDisplay.tsx +4 -0
- package/src/LinearGraphDisplay/model.ts +264 -187
- package/src/version.ts +1 -1
- package/dist/chunks/LinearGraphDisplay-P7U6NCZF.js +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jbrowse-plugin-graphgenomeviewer",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.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": {
|
|
@@ -13,6 +13,7 @@ import { types } from '@jbrowse/mobx-state-tree'
|
|
|
13
13
|
import { linearGenomeViewStateModelFactory } from '@jbrowse/plugin-linear-genome-view'
|
|
14
14
|
|
|
15
15
|
import LinearGraphDisplayF from './index'
|
|
16
|
+
import GbzBaseSyntenyAdapterF from '../GbzBaseSyntenyAdapter/index'
|
|
16
17
|
import RgfaTabixAdapterF from '../RgfaTabixAdapter/index'
|
|
17
18
|
|
|
18
19
|
import type { LinearGraphDisplayModel } from './model'
|
|
@@ -97,25 +98,28 @@ function createEnvironment({ tiered = true } = {}) {
|
|
|
97
98
|
console.warn = vi.fn()
|
|
98
99
|
const pluginManager = new PluginManager()
|
|
99
100
|
RgfaTabixAdapterF(pluginManager)
|
|
100
|
-
pluginManager
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
101
|
+
GbzBaseSyntenyAdapterF(pluginManager)
|
|
102
|
+
for (const name of ['FeatureTrack', 'SyntenyTrack']) {
|
|
103
|
+
pluginManager.addTrackType(() => {
|
|
104
|
+
const trackConfigSchema = ConfigurationSchema(
|
|
105
|
+
name,
|
|
106
|
+
{},
|
|
107
|
+
{
|
|
108
|
+
baseConfiguration: createBaseTrackConfig(pluginManager),
|
|
109
|
+
explicitIdentifier: 'trackId',
|
|
110
|
+
},
|
|
111
|
+
)
|
|
112
|
+
return new TrackType({
|
|
113
|
+
name,
|
|
114
|
+
configSchema: trackConfigSchema,
|
|
115
|
+
stateModel: createBaseTrackModel(
|
|
116
|
+
pluginManager,
|
|
117
|
+
name,
|
|
118
|
+
trackConfigSchema,
|
|
119
|
+
),
|
|
120
|
+
})
|
|
117
121
|
})
|
|
118
|
-
}
|
|
122
|
+
}
|
|
119
123
|
LinearGraphDisplayF(pluginManager)
|
|
120
124
|
pluginManager.addViewType(
|
|
121
125
|
() =>
|
|
@@ -155,7 +159,20 @@ function createEnvironment({ tiered = true } = {}) {
|
|
|
155
159
|
},
|
|
156
160
|
{ pluginManager },
|
|
157
161
|
)
|
|
158
|
-
const
|
|
162
|
+
const gbzTrackConfig = trackSchema.create(
|
|
163
|
+
{
|
|
164
|
+
type: 'SyntenyTrack',
|
|
165
|
+
trackId: 'walks',
|
|
166
|
+
name: 'walks',
|
|
167
|
+
assemblyNames: [ASM, 'HG1.1', 'HG2.1'],
|
|
168
|
+
adapter: { type: 'GbzBaseSyntenyAdapter', assemblyNames: [ASM] },
|
|
169
|
+
displays: [
|
|
170
|
+
{ type: 'LinearGraphDisplay', displayId: 'walks-LinearGraphDisplay' },
|
|
171
|
+
],
|
|
172
|
+
},
|
|
173
|
+
{ pluginManager },
|
|
174
|
+
)
|
|
175
|
+
const trackConfigs = [trackConfig, gbzTrackConfig]
|
|
159
176
|
|
|
160
177
|
const assemblyRegions = [
|
|
161
178
|
{ refName: REF, start: 0, end: CONTIG, assemblyName: ASM },
|
|
@@ -343,6 +360,58 @@ test('the track is as tall as its rows, up to the configured height', async () =
|
|
|
343
360
|
expect(display.height).toBe(pane.canvasHeight)
|
|
344
361
|
})
|
|
345
362
|
|
|
363
|
+
test("a launch names the pane's props without its type, and opens in that layout", async () => {
|
|
364
|
+
const { view, cuts } = createEnvironment()
|
|
365
|
+
view.zoomTo(60_000 / WIDTH_PX)
|
|
366
|
+
view.scrollTo(1_000_000 / view.bpPerPx)
|
|
367
|
+
view.showTrack(
|
|
368
|
+
'graph',
|
|
369
|
+
{},
|
|
370
|
+
{
|
|
371
|
+
type: 'LinearGraphDisplay',
|
|
372
|
+
pane: { layoutMode: 'force', colorScheme: 'uniform' },
|
|
373
|
+
},
|
|
374
|
+
)
|
|
375
|
+
const display = view.tracks[0]!.displays[0] as LinearGraphDisplayModel
|
|
376
|
+
display.pane.startRenderingBackend(fakeRenderer())
|
|
377
|
+
await wait(SETTLE_MS)
|
|
378
|
+
expect(cuts).toHaveLength(1)
|
|
379
|
+
expect(display.pane.layoutMode).toBe('force')
|
|
380
|
+
expect(display.pane.colorScheme).toBe('uniform')
|
|
381
|
+
expect(display.pane.hostPlacesX).toBe(false)
|
|
382
|
+
})
|
|
383
|
+
|
|
384
|
+
test('a launch that states one pane prop takes the rest from the config', async () => {
|
|
385
|
+
const { view, cuts } = createEnvironment()
|
|
386
|
+
view.zoomTo(60_000 / WIDTH_PX)
|
|
387
|
+
view.scrollTo(1_000_000 / view.bpPerPx)
|
|
388
|
+
view.showTrack(
|
|
389
|
+
'graph',
|
|
390
|
+
{},
|
|
391
|
+
{
|
|
392
|
+
type: 'LinearGraphDisplay',
|
|
393
|
+
pane: { colorScheme: 'uniform' },
|
|
394
|
+
},
|
|
395
|
+
)
|
|
396
|
+
const display = view.tracks[0]!.displays[0] as LinearGraphDisplayModel
|
|
397
|
+
display.pane.startRenderingBackend(fakeRenderer())
|
|
398
|
+
await wait(SETTLE_MS)
|
|
399
|
+
expect(cuts).toHaveLength(1)
|
|
400
|
+
expect(display.pane.colorScheme).toBe('uniform')
|
|
401
|
+
expect(display.pane.layoutMode).toBe('auto')
|
|
402
|
+
expect(display.pane.hostPlacesX).toBe(true)
|
|
403
|
+
})
|
|
404
|
+
|
|
405
|
+
test('a GBZ track cuts for the lanes it names', async () => {
|
|
406
|
+
const { view } = createEnvironment()
|
|
407
|
+
view.zoomTo(60_000 / WIDTH_PX)
|
|
408
|
+
view.scrollTo(1_000_000 / view.bpPerPx)
|
|
409
|
+
view.showTrack('walks')
|
|
410
|
+
const display = view.tracks[0]!.displays[0] as LinearGraphDisplayModel
|
|
411
|
+
expect(display.type).toBe('LinearGraphDisplay')
|
|
412
|
+
expect(display.pane.subgraphHaplotypes).toEqual(['HG1.1', 'HG2.1'])
|
|
413
|
+
})
|
|
414
|
+
|
|
346
415
|
test('the track menu offers the layouts, colours and the settings dialog', async () => {
|
|
347
416
|
const { display } = await shownGraph()
|
|
348
417
|
const labels = display
|
|
@@ -25,6 +25,10 @@ const LinearGraphDisplay = observer(function LinearGraphDisplay({
|
|
|
25
25
|
return (
|
|
26
26
|
<div
|
|
27
27
|
data-testid="linear-graph-display"
|
|
28
|
+
data-layout={pane.layoutMode}
|
|
29
|
+
data-cut-tier={pane.cutTier}
|
|
30
|
+
data-recuts={pane.recuts}
|
|
31
|
+
data-node-count={pane.hasGraph ? pane.nodeCount : undefined}
|
|
28
32
|
style={{
|
|
29
33
|
position: 'relative',
|
|
30
34
|
width: pane.width,
|
|
@@ -12,6 +12,7 @@ import { COLOR_SCHEMES } from '../GraphGenomeView/colorSchemes'
|
|
|
12
12
|
import { isLinearHost } from '../GraphGenomeView/host'
|
|
13
13
|
import { LAYOUT_MODES } from '../GraphGenomeView/layoutModes'
|
|
14
14
|
import paneModelFactory from '../GraphGenomeView/model'
|
|
15
|
+
import { trackLanes } from '../launchSubgraph/subgraphTracks'
|
|
15
16
|
|
|
16
17
|
import type { LinearGraphDisplayConfigModel } from './configSchema'
|
|
17
18
|
import type { MenuItem } from '@jbrowse/core/ui'
|
|
@@ -21,206 +22,282 @@ const GraphSettingsDialog = lazy(
|
|
|
21
22
|
() => import('../GraphGenomeView/components/GraphSettingsDialog'),
|
|
22
23
|
)
|
|
23
24
|
|
|
25
|
+
type ConfiguredSlot = 'layoutMode' | 'colorScheme' | 'height'
|
|
26
|
+
|
|
24
27
|
export function stateModelFactory(configSchema: LinearGraphDisplayConfigModel) {
|
|
25
28
|
const Pane = paneModelFactory()
|
|
26
|
-
return
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
29
|
+
return (
|
|
30
|
+
types
|
|
31
|
+
.compose(
|
|
32
|
+
'LinearGraphDisplay',
|
|
33
|
+
BaseDisplay,
|
|
34
|
+
TrackHeightMixin(),
|
|
35
|
+
types.model({
|
|
36
|
+
type: types.literal('LinearGraphDisplay'),
|
|
37
|
+
configuration: ConfigurationReference(configSchema),
|
|
38
|
+
// The graph pane, the same model the standalone view is. Here the
|
|
39
|
+
// linear view above is its host: x is that view's window for a layout
|
|
40
|
+
// whose x is reference bp, and the cut is re-made when the window
|
|
41
|
+
// leaves it (pane.host).
|
|
42
|
+
pane: types.optional(Pane, () => ({
|
|
43
|
+
type: 'GraphGenomeView' as const,
|
|
44
|
+
})),
|
|
45
|
+
// Which of the config's slots have reached the pane. Each reaches it
|
|
46
|
+
// once, so a choice made in the track menu survives a reload, and a
|
|
47
|
+
// launch that states a pane prop keeps it over the config's.
|
|
48
|
+
configured: types.optional(
|
|
49
|
+
types.frozen<Partial<Record<ConfiguredSlot, boolean>>>(),
|
|
50
|
+
{},
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
)
|
|
54
|
+
// A launch names the pane's props without the pane's own type, and what
|
|
55
|
+
// it states is what the config does not set.
|
|
56
|
+
.preProcessSnapshot(snapshot => {
|
|
57
|
+
const { pane, configured } = snapshot as {
|
|
58
|
+
pane?: Record<string, unknown>
|
|
59
|
+
configured?: Partial<Record<ConfiguredSlot, boolean>>
|
|
53
60
|
}
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
const { pane } = self
|
|
63
|
-
const { graph } = pane
|
|
64
|
-
const walks = pane.walkChoices
|
|
65
|
-
return [
|
|
66
|
-
{
|
|
67
|
-
label: 'Layout',
|
|
68
|
-
subMenu: LAYOUT_MODES.map(mode => ({
|
|
69
|
-
type: 'radio' as const,
|
|
70
|
-
label: mode.label,
|
|
71
|
-
checked: pane.layoutMode === mode.value,
|
|
72
|
-
disabled: graph ? !mode.available(graph) : false,
|
|
73
|
-
onClick: () => {
|
|
74
|
-
void pane.switchLayout(mode.value)
|
|
75
|
-
},
|
|
76
|
-
})),
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
label: 'Color',
|
|
80
|
-
subMenu: COLOR_SCHEMES.map(scheme => ({
|
|
81
|
-
type: 'radio' as const,
|
|
82
|
-
label: scheme.label,
|
|
83
|
-
checked: pane.colorScheme === scheme.value,
|
|
84
|
-
onClick: () => {
|
|
85
|
-
pane.setColorScheme(scheme.value)
|
|
61
|
+
return pane
|
|
62
|
+
? ({
|
|
63
|
+
...snapshot,
|
|
64
|
+
configured: {
|
|
65
|
+
layoutMode: pane.layoutMode !== undefined,
|
|
66
|
+
colorScheme: pane.colorScheme !== undefined,
|
|
67
|
+
height: pane.paneHeight !== undefined,
|
|
68
|
+
...configured,
|
|
86
69
|
},
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
70
|
+
pane:
|
|
71
|
+
pane.type === undefined
|
|
72
|
+
? { type: 'GraphGenomeView', ...pane }
|
|
73
|
+
: pane,
|
|
74
|
+
} as typeof snapshot)
|
|
75
|
+
: snapshot
|
|
76
|
+
})
|
|
77
|
+
.views(self => ({
|
|
78
|
+
get host() {
|
|
79
|
+
let view: unknown
|
|
80
|
+
try {
|
|
81
|
+
view = getContainingView(self)
|
|
82
|
+
} catch {
|
|
83
|
+
return undefined
|
|
84
|
+
}
|
|
85
|
+
return isLinearHost(view) ? view : undefined
|
|
86
|
+
},
|
|
87
|
+
get trackId(): string {
|
|
88
|
+
return getConf(self.parentTrack, 'trackId')
|
|
89
|
+
},
|
|
90
|
+
}))
|
|
91
|
+
.views(self => ({
|
|
92
|
+
trackMenuItems(): MenuItem[] {
|
|
93
|
+
const { pane } = self
|
|
94
|
+
const { graph } = pane
|
|
95
|
+
const walks = pane.walkChoices
|
|
96
|
+
return [
|
|
97
|
+
{
|
|
98
|
+
label: 'Layout',
|
|
99
|
+
subMenu: LAYOUT_MODES.map(mode => ({
|
|
100
|
+
type: 'radio' as const,
|
|
101
|
+
label: mode.label,
|
|
102
|
+
checked: pane.layoutMode === mode.value,
|
|
103
|
+
disabled: graph ? !mode.available(graph) : false,
|
|
104
|
+
onClick: () => {
|
|
105
|
+
void pane.switchLayout(mode.value)
|
|
106
|
+
},
|
|
107
|
+
})),
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
label: 'Color',
|
|
111
|
+
subMenu: COLOR_SCHEMES.map(scheme => ({
|
|
112
|
+
type: 'radio' as const,
|
|
113
|
+
label: scheme.label,
|
|
114
|
+
checked: pane.colorScheme === scheme.value,
|
|
115
|
+
onClick: () => {
|
|
116
|
+
pane.setColorScheme(scheme.value)
|
|
117
|
+
},
|
|
118
|
+
})),
|
|
119
|
+
},
|
|
120
|
+
...(walks.length > 0
|
|
121
|
+
? [
|
|
122
|
+
{
|
|
123
|
+
label: 'Walk',
|
|
124
|
+
subMenu: [
|
|
125
|
+
{
|
|
126
|
+
type: 'radio' as const,
|
|
127
|
+
label: 'None',
|
|
128
|
+
checked: pane.highlightedPath === '',
|
|
129
|
+
onClick: () => {
|
|
130
|
+
pane.setHighlightedPath('')
|
|
131
|
+
},
|
|
100
132
|
},
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
...walks.map(walk => ({
|
|
134
|
+
type: 'radio' as const,
|
|
135
|
+
label: walk.label,
|
|
136
|
+
checked: pane.highlightedPath === walk.name,
|
|
137
|
+
onClick: () => {
|
|
138
|
+
pane.setHighlightedPath(walk.name)
|
|
139
|
+
},
|
|
140
|
+
})),
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
]
|
|
144
|
+
: []),
|
|
145
|
+
...(pane.layoutMode === 'walkrows' && pane.repeatChoices.length > 0
|
|
146
|
+
? [
|
|
147
|
+
{
|
|
148
|
+
label: 'Repeat',
|
|
149
|
+
subMenu: [
|
|
150
|
+
{
|
|
151
|
+
type: 'radio' as const,
|
|
152
|
+
label: 'Whole window',
|
|
153
|
+
checked: pane.repeatKey === '',
|
|
154
|
+
onClick: () => {
|
|
155
|
+
pane.setRepeatKey('')
|
|
156
|
+
},
|
|
108
157
|
},
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
label: 'Zoom in',
|
|
119
|
-
onClick: () => {
|
|
120
|
-
pane.zoom(1.5, pane.width / 2, pane.canvasHeight / 2)
|
|
158
|
+
...pane.repeatChoices.map(({ key, name, unit }) => ({
|
|
159
|
+
type: 'radio' as const,
|
|
160
|
+
label: `${name} · ${unit.toLocaleString()} bp unit`,
|
|
161
|
+
checked: pane.repeatKey === key,
|
|
162
|
+
onClick: () => {
|
|
163
|
+
pane.setRepeatKey(key)
|
|
164
|
+
},
|
|
165
|
+
})),
|
|
166
|
+
],
|
|
121
167
|
},
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
168
|
+
]
|
|
169
|
+
: []),
|
|
170
|
+
...(pane.hostPlacesX
|
|
171
|
+
? []
|
|
172
|
+
: [
|
|
173
|
+
{
|
|
174
|
+
label: 'Zoom in',
|
|
175
|
+
onClick: () => {
|
|
176
|
+
pane.zoom(1.5, pane.width / 2, pane.canvasHeight / 2)
|
|
177
|
+
},
|
|
127
178
|
},
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
179
|
+
{
|
|
180
|
+
label: 'Zoom out',
|
|
181
|
+
onClick: () => {
|
|
182
|
+
pane.zoom(1 / 1.5, pane.width / 2, pane.canvasHeight / 2)
|
|
183
|
+
},
|
|
133
184
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
onClick: () => {
|
|
149
|
-
pane.setShowDeletionEdges(!pane.showDeletionEdges)
|
|
150
|
-
},
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
type: 'checkbox',
|
|
154
|
-
label: 'Genes on the backbone',
|
|
155
|
-
checked: pane.showGenes,
|
|
156
|
-
onClick: () => {
|
|
157
|
-
pane.setShowGenes(!pane.showGenes)
|
|
185
|
+
{
|
|
186
|
+
label: 'Zoom to fit',
|
|
187
|
+
onClick: () => {
|
|
188
|
+
pane.zoomToFit()
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
]),
|
|
192
|
+
{
|
|
193
|
+
type: 'checkbox',
|
|
194
|
+
label: 'Mark bubbles',
|
|
195
|
+
checked: pane.showBubbles,
|
|
196
|
+
onClick: () => {
|
|
197
|
+
pane.setShowBubbles(!pane.showBubbles)
|
|
198
|
+
},
|
|
158
199
|
},
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
{ model: pane, open: true, onClose },
|
|
167
|
-
])
|
|
200
|
+
{
|
|
201
|
+
type: 'checkbox',
|
|
202
|
+
label: 'Show deletion edges',
|
|
203
|
+
checked: pane.showDeletionEdges,
|
|
204
|
+
onClick: () => {
|
|
205
|
+
pane.setShowDeletionEdges(!pane.showDeletionEdges)
|
|
206
|
+
},
|
|
168
207
|
},
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
},
|
|
177
|
-
// The track's height is the pane's ceiling: a layout shorter than it
|
|
178
|
-
// takes only what it needs, and a drag on the handle moves the ceiling.
|
|
179
|
-
resizeHeight(distance: number) {
|
|
180
|
-
const before = self.height
|
|
181
|
-
const target = Math.max(before + distance, 40)
|
|
182
|
-
self.pane.setPaneHeight(target)
|
|
183
|
-
return target - before
|
|
184
|
-
},
|
|
185
|
-
}))
|
|
186
|
-
.actions(self => ({
|
|
187
|
-
afterAttach() {
|
|
188
|
-
const { pane } = self
|
|
189
|
-
if (!self.configured) {
|
|
190
|
-
pane.setLayoutMode(getConf(self, 'layoutMode'))
|
|
191
|
-
pane.setColorScheme(getConf(self, 'colorScheme'))
|
|
192
|
-
pane.setPaneHeight(getConf(self, 'height'))
|
|
193
|
-
self.setConfigured()
|
|
194
|
-
}
|
|
195
|
-
pane.adoptTrack(self.trackId)
|
|
196
|
-
pane.startHosting()
|
|
197
|
-
addDisposer(
|
|
198
|
-
self,
|
|
199
|
-
autorun(
|
|
200
|
-
() => {
|
|
201
|
-
const { host } = self
|
|
202
|
-
if (host) {
|
|
203
|
-
pane.setWidth(host.width)
|
|
204
|
-
pane.pairWithLinearView(host.id)
|
|
205
|
-
}
|
|
208
|
+
{
|
|
209
|
+
type: 'checkbox',
|
|
210
|
+
label: 'Genes on the backbone',
|
|
211
|
+
checked: pane.showGenes,
|
|
212
|
+
onClick: () => {
|
|
213
|
+
pane.setShowGenes(!pane.showGenes)
|
|
214
|
+
},
|
|
206
215
|
},
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
self.setHeight(height)
|
|
217
|
-
}
|
|
216
|
+
{
|
|
217
|
+
label: 'Settings',
|
|
218
|
+
icon: SettingsIcon,
|
|
219
|
+
onClick: () => {
|
|
220
|
+
getSession(self).queueDialog(onClose => [
|
|
221
|
+
GraphSettingsDialog,
|
|
222
|
+
{ model: pane, open: true, onClose },
|
|
223
|
+
])
|
|
224
|
+
},
|
|
218
225
|
},
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
226
|
+
]
|
|
227
|
+
},
|
|
228
|
+
}))
|
|
229
|
+
.actions(self => ({
|
|
230
|
+
// The config's slots the pane has not yet taken, then all of them.
|
|
231
|
+
applyConfig() {
|
|
232
|
+
const { pane, configured } = self
|
|
233
|
+
if (!configured.layoutMode) {
|
|
234
|
+
pane.setLayoutMode(getConf(self, 'layoutMode'))
|
|
235
|
+
}
|
|
236
|
+
if (!configured.colorScheme) {
|
|
237
|
+
pane.setColorScheme(getConf(self, 'colorScheme'))
|
|
238
|
+
}
|
|
239
|
+
if (!configured.height) {
|
|
240
|
+
pane.setPaneHeight(getConf(self, 'height'))
|
|
241
|
+
}
|
|
242
|
+
self.configured = {
|
|
243
|
+
layoutMode: true,
|
|
244
|
+
colorScheme: true,
|
|
245
|
+
height: true,
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
// The track's height is the pane's ceiling: a layout shorter than it
|
|
249
|
+
// takes only what it needs, and a drag on the handle moves the ceiling.
|
|
250
|
+
resizeHeight(distance: number) {
|
|
251
|
+
const before = self.height
|
|
252
|
+
const target = Math.max(before + distance, 40)
|
|
253
|
+
self.pane.setPaneHeight(target)
|
|
254
|
+
return target - before
|
|
255
|
+
},
|
|
256
|
+
}))
|
|
257
|
+
.actions(self => ({
|
|
258
|
+
afterAttach() {
|
|
259
|
+
const { pane } = self
|
|
260
|
+
self.applyConfig()
|
|
261
|
+
pane.adoptTrack(self.trackId)
|
|
262
|
+
// A GBZ track cuts for the lanes it names, as its lanes display
|
|
263
|
+
// draws them, unless a launch or a reader picked others.
|
|
264
|
+
if (
|
|
265
|
+
pane.subgraphHaplotypes === undefined &&
|
|
266
|
+
self.adapterConfig.type === 'GbzBaseSyntenyAdapter'
|
|
267
|
+
) {
|
|
268
|
+
pane.setSubgraphHaplotypes(
|
|
269
|
+
trackLanes(self.parentTrack.configuration),
|
|
270
|
+
)
|
|
271
|
+
}
|
|
272
|
+
pane.startHosting()
|
|
273
|
+
addDisposer(
|
|
274
|
+
self,
|
|
275
|
+
autorun(
|
|
276
|
+
() => {
|
|
277
|
+
const { host } = self
|
|
278
|
+
if (host) {
|
|
279
|
+
pane.setWidth(host.width)
|
|
280
|
+
pane.pairWithLinearView(host.id)
|
|
281
|
+
}
|
|
282
|
+
},
|
|
283
|
+
{ name: 'LinearGraphDisplayHost' },
|
|
284
|
+
),
|
|
285
|
+
)
|
|
286
|
+
addDisposer(
|
|
287
|
+
self,
|
|
288
|
+
autorun(
|
|
289
|
+
() => {
|
|
290
|
+
const height = pane.canvasHeight
|
|
291
|
+
if (self.height !== height) {
|
|
292
|
+
self.setHeight(height)
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{ name: 'LinearGraphDisplayHeight' },
|
|
296
|
+
),
|
|
297
|
+
)
|
|
298
|
+
},
|
|
299
|
+
}))
|
|
300
|
+
)
|
|
224
301
|
}
|
|
225
302
|
|
|
226
303
|
export type LinearGraphDisplayStateModel = ReturnType<typeof stateModelFactory>
|
package/src/version.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const version = '4.0.
|
|
1
|
+
export const version = '4.0.3'
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e,b as i}from"./chunk-SDTCVLC3.js";import"./chunk-A4ZWFDQY.js";import"./chunk-ZNGDWZ6Z.js";import"./chunk-OHT6UX4C.js";import"./chunk-OP7IRVG6.js";import"./chunk-F4C3BEPV.js";import{a as r,b as s,c as h}from"./chunk-XEJ47DLD.js";import{b as t}from"./chunk-FY3BTKY4.js";var p=t(h(),1),n=t(s(),1);var o=t(r(),1),m={position:"absolute",left:8,top:4,zIndex:5,background:"rgba(255,255,255,0.82)",padding:"0 4px",borderRadius:3},y=(0,n.observer)(function({model:l}){let{pane:a,height:d}=l;return(0,o.jsxs)("div",{"data-testid":"linear-graph-display",style:{position:"relative",width:a.width,height:d,overflow:"hidden"},children:[(0,o.jsx)(e,{model:a,toolbar:!1}),a.hasGraph?null:(0,o.jsx)(i,{model:a}),a.cutNote?(0,o.jsx)(p.Typography,{variant:"caption",color:"warning.main",style:m,"data-testid":"graph-cut-note",children:a.cutNote}):null]})}),g=y;export{g as default};
|
|
2
|
-
//# sourceMappingURL=LinearGraphDisplay-P7U6NCZF.js.map
|