jbrowse-plugin-graphgenomeviewer 7.1.0 → 7.1.2
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 +17 -8
- package/dist/chunks/AddTrackWorkflow-RPH4ZFSX.js +2 -0
- package/dist/chunks/{AddTrackWorkflow-Q6RY23LF.js.map → AddTrackWorkflow-RPH4ZFSX.js.map} +2 -2
- package/dist/chunks/{ChooseSamplesDialog-BNVYBGJQ.js → ChooseSamplesDialog-JRN4YLBY.js} +2 -2
- package/dist/chunks/{ChooseWalksDialog-EN3C6AQA.js → ChooseWalksDialog-UXLFZTZJ.js} +2 -2
- package/dist/chunks/GbzBaseSyntenyAdapter-LRECKL74.js +2 -0
- package/dist/chunks/GbzBaseSyntenyAdapter-LRECKL74.js.map +7 -0
- package/dist/chunks/{GraphGenomeView-Z2WZKEEO.js → GraphGenomeView-NJ5XCREB.js} +2 -2
- package/dist/chunks/GraphTrackSettingsDialog-47PQ6LM7.js +6 -0
- package/dist/chunks/GraphTrackSettingsDialog-47PQ6LM7.js.map +7 -0
- package/dist/chunks/{HighlightColorDialog-EYBKFSJU.js → HighlightColorDialog-UK5VDDV6.js} +2 -2
- package/dist/chunks/{LinearGraphDisplay-WIBVWRQE.js → LinearGraphDisplay-TXTKAACH.js} +2 -2
- package/dist/chunks/MinigraphBubbleAdapter-HW7XQMAI.js +2 -0
- package/dist/chunks/MinigraphBubbleAdapter-HW7XQMAI.js.map +7 -0
- package/dist/chunks/RgfaTabixAdapter-PSKYWD2X.js +3 -0
- package/dist/chunks/RgfaTabixAdapter-PSKYWD2X.js.map +7 -0
- package/dist/chunks/{TrackWarningsDialog-QT4YEXGD.js → TrackWarningsDialog-TRYBOIHX.js} +2 -2
- package/dist/chunks/WalkTabixSyntenyAdapter-U53JLYVU.js +2 -0
- package/dist/chunks/WalkTabixSyntenyAdapter-U53JLYVU.js.map +7 -0
- package/dist/chunks/chunk-2MCOY3YG.js +3 -0
- package/dist/chunks/chunk-2MCOY3YG.js.map +7 -0
- package/dist/chunks/{chunk-EWFJBQDV.js → chunk-5O6YRJHL.js} +2 -2
- package/dist/chunks/{chunk-EWFJBQDV.js.map → chunk-5O6YRJHL.js.map} +1 -1
- package/dist/chunks/chunk-BUY2PV7D.js +2 -0
- package/dist/chunks/chunk-BUY2PV7D.js.map +7 -0
- package/dist/chunks/chunk-DVCZ3BOC.js +2 -0
- package/dist/chunks/chunk-DVCZ3BOC.js.map +7 -0
- package/dist/chunks/{chunk-SAMJE6GH.js → chunk-EGDLEQ47.js} +3 -3
- package/dist/chunks/{chunk-SAMJE6GH.js.map → chunk-EGDLEQ47.js.map} +4 -4
- package/dist/chunks/chunk-FHZXW7IG.js +2 -0
- package/dist/chunks/chunk-FHZXW7IG.js.map +7 -0
- package/dist/chunks/{chunk-DZ4OUKQV.js → chunk-FITPB5X6.js} +2 -2
- package/dist/chunks/{chunk-DZ4OUKQV.js.map → chunk-FITPB5X6.js.map} +1 -1
- package/dist/chunks/chunk-FVK2THE4.js +2 -0
- package/dist/chunks/chunk-FVK2THE4.js.map +7 -0
- package/dist/chunks/{chunk-AHFQHYJI.js → chunk-IBWORBGY.js} +2 -2
- package/dist/chunks/chunk-MND7GAOG.js +2 -0
- package/dist/chunks/chunk-MND7GAOG.js.map +7 -0
- package/dist/chunks/chunk-MURN3JPK.js +2 -0
- package/dist/chunks/chunk-MURN3JPK.js.map +7 -0
- package/dist/chunks/{chunk-3Q4RBDCL.js → chunk-N6PQZSAX.js} +1 -1
- package/dist/chunks/{chunk-3Q4RBDCL.js.map → chunk-N6PQZSAX.js.map} +1 -1
- package/dist/chunks/chunk-NWJYLP6Z.js +4 -0
- package/dist/chunks/chunk-NWJYLP6Z.js.map +7 -0
- package/dist/chunks/{chunk-YJHYBDYF.js → chunk-S75W27NT.js} +2 -2
- package/dist/chunks/{chunk-YJHYBDYF.js.map → chunk-S75W27NT.js.map} +1 -1
- package/dist/chunks/{chunk-IXQK7JAW.js → chunk-T4HOC6O3.js} +1 -1
- package/dist/chunks/{chunk-IXQK7JAW.js.map → chunk-T4HOC6O3.js.map} +1 -1
- package/dist/chunks/{chunk-AU73K7LX.js → chunk-TUKJRVBS.js} +1 -1
- package/dist/chunks/{chunk-AU73K7LX.js.map → chunk-TUKJRVBS.js.map} +1 -1
- package/dist/chunks/chunk-UGCNPRKC.js +2 -0
- package/dist/chunks/{chunk-E3WYW7Z6.js.map → chunk-UGCNPRKC.js.map} +2 -2
- package/dist/chunks/{chunk-YSTMDXXX.js → chunk-VJ3SO4CH.js} +1 -1
- package/dist/chunks/{chunk-YSTMDXXX.js.map → chunk-VJ3SO4CH.js.map} +1 -1
- package/dist/chunks/{chunk-XT766CZ5.js → chunk-W6EQLQ6H.js} +1 -1
- package/dist/chunks/{chunk-XT766CZ5.js.map → chunk-W6EQLQ6H.js.map} +1 -1
- package/dist/chunks/chunk-WAMBI7OX.js +2 -0
- package/dist/chunks/chunk-WAMBI7OX.js.map +7 -0
- package/dist/chunks/chunk-WCGVUZWP.js +2 -0
- package/dist/chunks/chunk-WCGVUZWP.js.map +7 -0
- package/dist/chunks/chunk-WEGWTC52.js +2 -0
- package/dist/chunks/chunk-WEGWTC52.js.map +7 -0
- package/dist/chunks/chunk-YU7T5WOQ.js +2 -0
- package/dist/chunks/{chunk-6OPB7FOJ.js.map → chunk-YU7T5WOQ.js.map} +2 -2
- package/dist/chunks/{chunk-446RWIA3.js → chunk-ZMOMFU2B.js} +1 -1
- package/dist/chunks/{chunk-446RWIA3.js.map → chunk-ZMOMFU2B.js.map} +1 -1
- package/dist/chunks/renderSvg-KSQI5DH6.js +2 -0
- package/dist/chunks/renderSvg-KSQI5DH6.js.map +7 -0
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js +4 -4
- package/dist/jbrowse-plugin-graphgenomeviewer.esm.js.map +4 -4
- package/package.json +8 -9
- package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.test.ts +12 -10
- package/src/GbzBaseSyntenyAdapter/GbzBaseSyntenyAdapter.ts +31 -39
- package/src/GbzBaseSyntenyAdapter/configSchema.ts +5 -29
- package/src/GetGraphHaplotypes.ts +6 -15
- package/src/GetGraphReads.ts +7 -14
- package/src/GetSubgraph.ts +11 -20
- package/src/GraphAddTrackWorkflow/AddTrackWorkflow.test.tsx +73 -0
- package/src/GraphAddTrackWorkflow/AddTrackWorkflow.tsx +1 -0
- package/src/GraphAddTrackWorkflow/buildTrackConfig.test.ts +3 -2
- package/src/GraphAddTrackWorkflow/buildTrackConfig.ts +2 -11
- package/src/GraphAddTrackWorkflow/graphManifest.ts +15 -3
- package/src/GraphGenomeView/components/BubbleHalos.tsx +5 -24
- package/src/GraphGenomeView/components/ElTree.tsx +6 -1
- package/src/GraphGenomeView/components/FacetPanels.test.tsx +65 -0
- package/src/GraphGenomeView/components/FacetPanels.tsx +17 -12
- package/src/GraphGenomeView/components/GenePins.tsx +5 -22
- package/src/GraphGenomeView/components/GraphCanvas.tsx +40 -234
- package/src/GraphGenomeView/components/GraphSettingsDialog.tsx +102 -108
- package/src/GraphGenomeView/components/GraphToolbar.tsx +5 -6
- package/src/GraphGenomeView/components/HoverLayer.tsx +3 -7
- package/src/GraphGenomeView/components/HoverTooltip.test.tsx +39 -0
- package/src/GraphGenomeView/components/HoverTooltip.tsx +122 -0
- package/src/GraphGenomeView/components/LabelChip.tsx +3 -5
- package/src/GraphGenomeView/components/LabelLayer.tsx +4 -17
- package/src/GraphGenomeView/components/LabelledSelect.tsx +1 -1
- package/src/GraphGenomeView/components/Legend.tsx +14 -23
- package/src/GraphGenomeView/components/PaneContextMenu.test.tsx +48 -0
- package/src/GraphGenomeView/components/PaneContextMenu.tsx +144 -0
- package/src/GraphGenomeView/components/PaneLayer.tsx +91 -0
- package/src/GraphGenomeView/components/PaneSvg.tsx +32 -50
- package/src/GraphGenomeView/components/ReferenceStripOverlay.test.tsx +48 -0
- package/src/GraphGenomeView/components/ReferenceStripOverlay.tsx +13 -42
- package/src/GraphGenomeView/components/SettingsMenu.test.tsx +29 -0
- package/src/GraphGenomeView/components/SettingsMenu.tsx +56 -65
- package/src/GraphGenomeView/components/TubeMapOverlay.tsx +15 -46
- package/src/GraphGenomeView/components/WalkRowsOverlay.tsx +58 -132
- package/src/GraphGenomeView/components/WalkStrip.tsx +17 -20
- package/src/GraphGenomeView/components/WalkStripLocator.tsx +8 -15
- package/src/GraphGenomeView/components/usePaneGestures.test.tsx +35 -0
- package/src/GraphGenomeView/components/usePaneGestures.ts +88 -91
- package/src/GraphGenomeView/genes/geneFeatures.ts +27 -45
- package/src/GraphGenomeView/graphLayers.ts +4 -4
- package/src/GraphGenomeView/host.ts +1 -1
- package/src/GraphGenomeView/legendSections.test.ts +23 -1
- package/src/GraphGenomeView/legendSections.ts +68 -74
- package/src/GraphGenomeView/model.test.ts +373 -39
- package/src/GraphGenomeView/model.ts +67 -11
- package/src/GraphGenomeView/pane/fitViews.ts +57 -514
- package/src/GraphGenomeView/pane/graphViews.ts +219 -160
- package/src/GraphGenomeView/pane/hostViews.ts +2 -10
- package/src/GraphGenomeView/pane/keepInView.ts +5 -4
- package/src/GraphGenomeView/pane/launchActions.ts +117 -139
- package/src/GraphGenomeView/pane/launchViews.ts +8 -27
- package/src/GraphGenomeView/pane/loadActions.ts +208 -187
- package/src/GraphGenomeView/pane/morph.ts +3 -9
- package/src/GraphGenomeView/pane/paneBase.ts +22 -11
- package/src/GraphGenomeView/pane/renderingActions.ts +65 -11
- package/src/GraphGenomeView/pane/settingActions.ts +17 -42
- package/src/GraphGenomeView/pane/tubeMapViews.ts +445 -0
- package/src/GraphGenomeView/pane/walkRowViews.ts +29 -37
- package/src/GraphGenomeView/renderPipeline.test.ts +1 -1
- package/src/GraphGenomeView/repeats/repeatFeatures.test.ts +23 -0
- package/src/GraphGenomeView/repeats/repeatFeatures.ts +16 -23
- package/src/GraphGenomeView/repeats/walkCalls.test.ts +18 -0
- package/src/GraphGenomeView/repeats/walkCalls.ts +46 -38
- package/src/GraphGenomeView/subgraphLoad.test.ts +67 -3
- package/src/GraphGenomeView/trackFeatures.ts +24 -0
- package/src/GraphGenomeView/tubeMapPanels.ts +28 -36
- package/src/GraphGenomeView/viewModel.ts +8 -56
- package/src/GraphGenomeView/walkRowGroups.ts +104 -30
- package/src/GraphGenomeView/walkRowSpans.test.ts +6 -0
- package/src/GraphGenomeView/walkRowSpans.ts +22 -31
- package/src/GraphGenomeView/walkRowsCut.ts +8 -17
- package/src/LinearGraphDisplay/LinearGraphDisplay.test.ts +173 -26
- package/src/LinearGraphDisplay/components/SubgraphContextSelect.test.tsx +1 -1
- package/src/LinearGraphDisplay/components/SubgraphContextSelect.tsx +3 -3
- package/src/LinearGraphDisplay/components/SubgraphHaplotypesField.test.tsx +3 -3
- package/src/LinearGraphDisplay/components/SubgraphHaplotypesField.tsx +7 -10
- package/src/LinearGraphDisplay/configSchema.ts +0 -3
- package/src/LinearGraphDisplay/denseWindow.ts +8 -11
- package/src/LinearGraphDisplay/model.ts +89 -82
- package/src/MinigraphBubbleAdapter/MinigraphBubbleAdapter.test.ts +21 -0
- package/src/MinigraphBubbleAdapter/MinigraphBubbleAdapter.ts +6 -14
- package/src/MinigraphBubbleAdapter/configSchema.ts +3 -9
- package/src/MinigraphBubbleAdapter/index.ts +1 -2
- package/src/RgfaTabixAdapter/RgfaTabixAdapter.test.ts +45 -1
- package/src/RgfaTabixAdapter/RgfaTabixAdapter.ts +111 -276
- package/src/RgfaTabixAdapter/configSchema.ts +15 -49
- package/src/RgfaTabixAdapter/index.ts +1 -2
- package/src/RgfaTabixAdapter/rgfaBed.ts +25 -15
- package/src/RgfaTabixAdapter/rgfaCut.ts +139 -0
- package/src/RgfaTabixAdapter/test_data/walks2_twopart.GRCh38.walks.bed.gz +0 -0
- package/src/RgfaTabixAdapter/test_data/walks2_twopart.GRCh38.walks.bed.gz.tbi +0 -0
- package/src/RgfaTabixAdapter/walkFiles.test.ts +33 -0
- package/src/RgfaTabixAdapter/walkReader.ts +103 -27
- package/src/RgfaTabixAdapter/walkRowRuns.test.ts +53 -0
- package/src/RgfaTabixAdapter/walkRowRuns.ts +42 -24
- package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.test.ts +37 -6
- package/src/WalkTabixSyntenyAdapter/WalkTabixSyntenyAdapter.ts +23 -45
- package/src/WalkTabixSyntenyAdapter/configSchema.ts +11 -24
- package/src/WalkTabixSyntenyAdapter/index.ts +1 -2
- package/src/WalkTabixSyntenyAdapter/walkLanes.ts +35 -43
- package/src/adapterImplementing.ts +27 -0
- package/src/graphTrackDefaults/index.ts +14 -20
- package/src/hoverSync/lgvHover.ts +2 -4
- package/src/launchFromGraph/contributors.ts +1 -5
- package/src/launchFromGraph/graphMenuItems.ts +3 -4
- package/src/launchFromGraph/launchFromGraph.test.ts +0 -1
- package/src/launchFromGraph/launchFromGraph.ts +8 -13
- package/src/panSNTabix.test.ts +1 -26
- package/src/panSNTabix.ts +54 -51
- package/src/synteny/lanePairs.ts +8 -0
- package/src/synteny/matchFeature.ts +52 -0
- package/src/tabixRange.ts +13 -10
- package/src/version.ts +1 -1
- package/dist/chunks/AddTrackWorkflow-Q6RY23LF.js +0 -2
- package/dist/chunks/GbzBaseSyntenyAdapter-TIXR4Y3J.js +0 -2
- package/dist/chunks/GbzBaseSyntenyAdapter-TIXR4Y3J.js.map +0 -7
- package/dist/chunks/GraphTrackSettingsDialog-TAM6PMXD.js +0 -6
- package/dist/chunks/GraphTrackSettingsDialog-TAM6PMXD.js.map +0 -7
- package/dist/chunks/MinigraphBubbleAdapter-AGI2UYQR.js +0 -2
- package/dist/chunks/MinigraphBubbleAdapter-AGI2UYQR.js.map +0 -7
- package/dist/chunks/RgfaTabixAdapter-2OL5X3HF.js +0 -3
- package/dist/chunks/RgfaTabixAdapter-2OL5X3HF.js.map +0 -7
- package/dist/chunks/WalkTabixSyntenyAdapter-UKFHCFOF.js +0 -2
- package/dist/chunks/WalkTabixSyntenyAdapter-UKFHCFOF.js.map +0 -7
- package/dist/chunks/chunk-5SFGHDQA.js +0 -2
- package/dist/chunks/chunk-5SFGHDQA.js.map +0 -7
- package/dist/chunks/chunk-6OPB7FOJ.js +0 -2
- package/dist/chunks/chunk-AMFIBQVR.js +0 -2
- package/dist/chunks/chunk-AMFIBQVR.js.map +0 -7
- package/dist/chunks/chunk-BJMRBVG3.js +0 -2
- package/dist/chunks/chunk-BJMRBVG3.js.map +0 -7
- package/dist/chunks/chunk-E3WYW7Z6.js +0 -2
- package/dist/chunks/chunk-EHCF6AXH.js +0 -2
- package/dist/chunks/chunk-EHCF6AXH.js.map +0 -7
- package/dist/chunks/chunk-GOFS7BXK.js +0 -3
- package/dist/chunks/chunk-GOFS7BXK.js.map +0 -7
- package/dist/chunks/chunk-IJQTSJGT.js +0 -4
- package/dist/chunks/chunk-IJQTSJGT.js.map +0 -7
- package/dist/chunks/chunk-J6NZIAZF.js +0 -2
- package/dist/chunks/chunk-J6NZIAZF.js.map +0 -7
- package/dist/chunks/chunk-LUTMKRXY.js +0 -2
- package/dist/chunks/chunk-LUTMKRXY.js.map +0 -7
- package/dist/chunks/chunk-MHPJB22Z.js +0 -2
- package/dist/chunks/chunk-MHPJB22Z.js.map +0 -7
- package/dist/chunks/chunk-TXI43PEN.js +0 -2
- package/dist/chunks/chunk-TXI43PEN.js.map +0 -7
- package/dist/chunks/chunk-WRH2EJKX.js +0 -2
- package/dist/chunks/chunk-WRH2EJKX.js.map +0 -7
- package/dist/chunks/chunk-WX26KTZM.js +0 -2
- package/dist/chunks/chunk-WX26KTZM.js.map +0 -7
- package/dist/chunks/renderSvg-ST2GBBOC.js +0 -2
- package/dist/chunks/renderSvg-ST2GBBOC.js.map +0 -7
- package/src/GraphGenomeView/components/WalkRowContextMenu.tsx +0 -105
- /package/dist/chunks/{ChooseSamplesDialog-BNVYBGJQ.js.map → ChooseSamplesDialog-JRN4YLBY.js.map} +0 -0
- /package/dist/chunks/{ChooseWalksDialog-EN3C6AQA.js.map → ChooseWalksDialog-UXLFZTZJ.js.map} +0 -0
- /package/dist/chunks/{GraphGenomeView-Z2WZKEEO.js.map → GraphGenomeView-NJ5XCREB.js.map} +0 -0
- /package/dist/chunks/{HighlightColorDialog-EYBKFSJU.js.map → HighlightColorDialog-UK5VDDV6.js.map} +0 -0
- /package/dist/chunks/{LinearGraphDisplay-WIBVWRQE.js.map → LinearGraphDisplay-TXTKAACH.js.map} +0 -0
- /package/dist/chunks/{TrackWarningsDialog-QT4YEXGD.js.map → TrackWarningsDialog-TRYBOIHX.js.map} +0 -0
- /package/dist/chunks/{chunk-AHFQHYJI.js.map → chunk-IBWORBGY.js.map} +0 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { sameBubble } from '@jbrowse/bandage-core/bubbles/bubbleLine'
|
|
2
2
|
import { bubbleSegmentIds } from '@jbrowse/bandage-core/bubbles/classifyBubble'
|
|
3
3
|
import { foldVariants } from '@jbrowse/bandage-core/foldVariants'
|
|
4
|
+
import { regionLabel } from '@jbrowse/bandage-core/hoverText'
|
|
4
5
|
import {
|
|
5
6
|
clipToWindow,
|
|
6
7
|
trimToWindow,
|
|
@@ -32,7 +33,6 @@ import {
|
|
|
32
33
|
import { withSettingActions } from './settingActions'
|
|
33
34
|
import { namesReads } from '../../GetGraphReads'
|
|
34
35
|
import { walkRowsOf } from '../../RgfaTabixAdapter/walkRowRuns.ts'
|
|
35
|
-
import { locLabel } from '../../launchFromGraph/contributors'
|
|
36
36
|
import { geneModelsFrom } from '../genes/geneFeatures'
|
|
37
37
|
import { repeatArraysFrom } from '../repeats/repeatFeatures'
|
|
38
38
|
import {
|
|
@@ -54,7 +54,19 @@ import type { Graph, LayoutResult } from '@jbrowse/bandage-core/types'
|
|
|
54
54
|
import type { Feature } from '@jbrowse/core/util'
|
|
55
55
|
import type { FileLocation } from '@jbrowse/core/util/types'
|
|
56
56
|
|
|
57
|
-
|
|
57
|
+
const withEngineSettings = withSettingActions.views(self => ({
|
|
58
|
+
get engineSettings() {
|
|
59
|
+
return engineSettingsOf({
|
|
60
|
+
engine: self.layoutEngine,
|
|
61
|
+
quality: self.layoutQuality,
|
|
62
|
+
linearLayout: self.linearLayout,
|
|
63
|
+
bubbleSpread: self.bubbleSpread,
|
|
64
|
+
showDeletionEdges: self.showDeletionEdges,
|
|
65
|
+
})
|
|
66
|
+
},
|
|
67
|
+
}))
|
|
68
|
+
|
|
69
|
+
export const withLoadActions = withEngineSettings.actions(self => {
|
|
58
70
|
let loadController: AbortController | undefined
|
|
59
71
|
// the samples TSV location the table was read from, or is being read from
|
|
60
72
|
let sampleTableKey: string | undefined
|
|
@@ -78,16 +90,6 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
78
90
|
}) as Promise<{ result: LayoutResult; duration: number }>
|
|
79
91
|
}
|
|
80
92
|
|
|
81
|
-
function engineSettings() {
|
|
82
|
-
return engineSettingsOf({
|
|
83
|
-
engine: self.layoutEngine,
|
|
84
|
-
quality: self.layoutQuality,
|
|
85
|
-
linearLayout: self.linearLayout,
|
|
86
|
-
bubbleSpread: self.bubbleSpread,
|
|
87
|
-
showDeletionEdges: self.showDeletionEdges,
|
|
88
|
-
})
|
|
89
|
-
}
|
|
90
|
-
|
|
91
93
|
// Single dispatch point for every layout mode. A mode that returns a
|
|
92
94
|
// result computed it locally; one that returns undefined can't draw this
|
|
93
95
|
// graph and hands off to the remote FMMM engine, which is also how
|
|
@@ -145,7 +147,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
145
147
|
mode: self.chosenLayoutMode,
|
|
146
148
|
}
|
|
147
149
|
}
|
|
148
|
-
const settings = engineSettings
|
|
150
|
+
const settings = self.engineSettings
|
|
149
151
|
const hit = forceLayouts.ready(graph, settings)
|
|
150
152
|
if (hit) {
|
|
151
153
|
return {
|
|
@@ -165,9 +167,9 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
165
167
|
}
|
|
166
168
|
|
|
167
169
|
// Which layout request is the live one. A layout is async and nothing in
|
|
168
|
-
// the UI waits for it, so several are routinely in flight: every
|
|
169
|
-
//
|
|
170
|
-
//
|
|
170
|
+
// the UI waits for it, so several are routinely in flight: every engine
|
|
171
|
+
// setting lays the graph out again on change, and a force layout takes
|
|
172
|
+
// seconds where an anchored one is instant.
|
|
171
173
|
//
|
|
172
174
|
// The graph identity below is not enough to order them, because the
|
|
173
175
|
// competing requests are usually layouts of the SAME graph. Left to
|
|
@@ -177,6 +179,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
177
179
|
// one over the top of the chosen one seconds later, with the dropdown
|
|
178
180
|
// still naming the choice that was discarded.
|
|
179
181
|
let liveRequest = 0
|
|
182
|
+
let liveRequestPending = false
|
|
180
183
|
// the error the last failed layout raised, which the next one to land clears
|
|
181
184
|
let layoutError: unknown
|
|
182
185
|
// the graph the layout on screen was computed for
|
|
@@ -184,11 +187,20 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
184
187
|
// a haplotype's genes by track and contig span
|
|
185
188
|
const walkGeneCache = new Map<string, GeneModel[]>()
|
|
186
189
|
|
|
190
|
+
function dropLayoutOfReplacedGraph() {
|
|
191
|
+
if (self.graph !== laidOutGraph) {
|
|
192
|
+
laidOutGraph = undefined
|
|
193
|
+
self.layoutResult = undefined
|
|
194
|
+
self.drawnLayoutMode = undefined
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
187
198
|
// Applied under a guard because a layout is async and the user can load a
|
|
188
199
|
// different graph, or ask for a different layout of it, while one is in
|
|
189
200
|
// flight; the stale result must not land.
|
|
190
201
|
function* layoutInto(graph: Graph) {
|
|
191
202
|
const request = ++liveRequest
|
|
203
|
+
liveRequestPending = true
|
|
192
204
|
awaitedRun = undefined
|
|
193
205
|
const isLive = () => self.graph === graph && request === liveRequest
|
|
194
206
|
const signal = loadController?.signal
|
|
@@ -211,7 +223,13 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
211
223
|
return false
|
|
212
224
|
}
|
|
213
225
|
layoutError = e
|
|
226
|
+
dropLayoutOfReplacedGraph()
|
|
214
227
|
throw e
|
|
228
|
+
} finally {
|
|
229
|
+
if (request === liveRequest) {
|
|
230
|
+
liveRequestPending = false
|
|
231
|
+
settle()
|
|
232
|
+
}
|
|
215
233
|
}
|
|
216
234
|
const live = isLive()
|
|
217
235
|
if (live) {
|
|
@@ -220,12 +238,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
220
238
|
}
|
|
221
239
|
layoutError = undefined
|
|
222
240
|
const previous = self.layoutResult
|
|
223
|
-
const before =
|
|
224
|
-
scaleX: self.scaleX,
|
|
225
|
-
scaleY: self.scaleY,
|
|
226
|
-
translateX: self.translateX,
|
|
227
|
-
translateY: self.translateY,
|
|
228
|
-
}
|
|
241
|
+
const before = self.screenTransform
|
|
229
242
|
laidOutGraph = graph
|
|
230
243
|
self.layoutResult = computed.result
|
|
231
244
|
self.drawnLayoutMode = computed.mode
|
|
@@ -276,6 +289,33 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
276
289
|
return parsed
|
|
277
290
|
}
|
|
278
291
|
|
|
292
|
+
// Replaces the graph on screen and the cut it came from, and drops the
|
|
293
|
+
// annotations read beside the last graph. It drops the hover and the
|
|
294
|
+
// selection too, because hoveredEdge is an index into graph.edges and
|
|
295
|
+
// hoveredNode/selectedNode are ids, which would point the tooltip and the
|
|
296
|
+
// highlight at whatever sits there in the new graph.
|
|
297
|
+
function resetCut(cut?: {
|
|
298
|
+
graph: Graph
|
|
299
|
+
walkCut: WalkCut | undefined
|
|
300
|
+
region: SubgraphRegion | undefined
|
|
301
|
+
loadedReferencePath: string | undefined
|
|
302
|
+
foldedBelowBp: number | undefined
|
|
303
|
+
readsShown: { shown: number; total: number } | undefined
|
|
304
|
+
}) {
|
|
305
|
+
self.graph = cut?.graph
|
|
306
|
+
self.walkCut = cut?.walkCut
|
|
307
|
+
self.graphRegion = cut?.region
|
|
308
|
+
self.loadedReferencePath = cut?.loadedReferencePath
|
|
309
|
+
self.foldedBelowBp = cut?.foldedBelowBp
|
|
310
|
+
self.readsShown = cut?.readsShown
|
|
311
|
+
self.indexBubbles = undefined
|
|
312
|
+
self.geneTrackFeatures = undefined
|
|
313
|
+
self.walkGeneFeatures = undefined
|
|
314
|
+
walkGeneCache.clear()
|
|
315
|
+
self.repeatArrays = undefined
|
|
316
|
+
self.clearInteractionState()
|
|
317
|
+
}
|
|
318
|
+
|
|
279
319
|
// `keepSelection` for a re-cut of the same source: node ids survive one
|
|
280
320
|
// where edge indexes do not, so the selection is found again by id.
|
|
281
321
|
// `readsOf` fetches the reads over the parsed graph before its one
|
|
@@ -291,7 +331,6 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
291
331
|
foldBelowBp = 0,
|
|
292
332
|
) {
|
|
293
333
|
const signal = loadController?.signal
|
|
294
|
-
self.setStatusMessage('Parsing GFA')
|
|
295
334
|
const walkCut =
|
|
296
335
|
typeof source !== 'string' && source.walkRowRuns ? source : undefined
|
|
297
336
|
const parsed = parseCut(source, name, region)
|
|
@@ -328,27 +367,19 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
328
367
|
}
|
|
329
368
|
}
|
|
330
369
|
const selected = keepSelection ? self.selectedNode : null
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
self.walkGeneFeatures = undefined
|
|
340
|
-
walkGeneCache.clear()
|
|
341
|
-
self.repeatArrays = undefined
|
|
370
|
+
resetCut({
|
|
371
|
+
graph,
|
|
372
|
+
walkCut,
|
|
373
|
+
region,
|
|
374
|
+
loadedReferencePath: loaded,
|
|
375
|
+
foldedBelowBp: folded === anchored ? undefined : foldBelowBp,
|
|
376
|
+
readsShown,
|
|
377
|
+
})
|
|
342
378
|
// a re-cut keeps the bubbles still in it open
|
|
343
379
|
const names = new Set(graph.nodes.map(n => n.name))
|
|
344
380
|
self.openBubbles = self.openBubbles.filter(b =>
|
|
345
381
|
bubbleSegmentIds(b).some(id => names.has(id)),
|
|
346
382
|
)
|
|
347
|
-
// hoveredEdge is an index into graph.edges and hoveredNode/selectedNode
|
|
348
|
-
// are ids, so all three address the graph being replaced here. Carrying
|
|
349
|
-
// them over points the tooltip and the highlight at whatever now happens
|
|
350
|
-
// to sit at that index.
|
|
351
|
-
self.clearInteractionState()
|
|
352
383
|
// against the new graph's own nodes: nodeById reads through the layout,
|
|
353
384
|
// which is still the last graph's
|
|
354
385
|
if (selected !== null && graph.nodes.some(n => n.id === selected)) {
|
|
@@ -378,14 +409,64 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
378
409
|
}
|
|
379
410
|
}
|
|
380
411
|
|
|
412
|
+
// The spinner stays up while a load or the layout last asked for is in
|
|
413
|
+
// flight. Clearing it sooner reports "done" while the layout the user
|
|
414
|
+
// asked for is still computing, the common case when a cheap choice
|
|
415
|
+
// follows an expensive one.
|
|
416
|
+
function settle() {
|
|
417
|
+
if (loadInFlight === undefined && !liveRequestPending) {
|
|
418
|
+
self.finishLoading()
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
381
422
|
function endLoad() {
|
|
382
423
|
loadInFlight = undefined
|
|
383
|
-
|
|
424
|
+
settle()
|
|
384
425
|
}
|
|
385
426
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
427
|
+
// Runs `body` as a load. It raises the spinner and clears the error first,
|
|
428
|
+
// and while it is the live load it reports a failure and ends the spinner.
|
|
429
|
+
function* runLoad(
|
|
430
|
+
label: string,
|
|
431
|
+
body: (load: {
|
|
432
|
+
isLive: () => boolean
|
|
433
|
+
signal: AbortSignal
|
|
434
|
+
}) => Generator<PromiseLike<unknown>, void, unknown>,
|
|
435
|
+
) {
|
|
436
|
+
const load = beginLoad()
|
|
437
|
+
self.isLoading = true
|
|
438
|
+
self.error = undefined
|
|
439
|
+
try {
|
|
440
|
+
yield* body(load)
|
|
441
|
+
} catch (e) {
|
|
442
|
+
if (load.isLive()) {
|
|
443
|
+
console.error(`[GraphGenomeView.${label}]`, e)
|
|
444
|
+
self.error = e
|
|
445
|
+
}
|
|
446
|
+
} finally {
|
|
447
|
+
if (load.isLive()) {
|
|
448
|
+
endLoad()
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// Features over the cut. A failed read warns and returns undefined, so an
|
|
454
|
+
// annotation never fails the load.
|
|
455
|
+
function* readFeatures(
|
|
456
|
+
adapterConfig: Record<string, unknown>,
|
|
457
|
+
region: SubgraphRegion,
|
|
458
|
+
what: string,
|
|
459
|
+
signal?: AbortSignal,
|
|
460
|
+
) {
|
|
461
|
+
try {
|
|
462
|
+
return (yield getSession(self).rpcManager.call(
|
|
463
|
+
getRpcSessionId(self),
|
|
464
|
+
'CoreGetFeatures',
|
|
465
|
+
{ adapterConfig, regions: [region], signal },
|
|
466
|
+
)) as Feature[]
|
|
467
|
+
} catch (e) {
|
|
468
|
+
console.warn(`[GraphGenomeView] no ${what} for this graph`, e)
|
|
469
|
+
return undefined
|
|
389
470
|
}
|
|
390
471
|
}
|
|
391
472
|
|
|
@@ -408,81 +489,63 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
408
489
|
if (adapterConfig.type !== 'RgfaTabixAdapter' || prefix === undefined) {
|
|
409
490
|
return
|
|
410
491
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
longestAllele: undefined,
|
|
446
|
-
},
|
|
447
|
-
]
|
|
448
|
-
})
|
|
449
|
-
self.indexBubbles = bubbles
|
|
450
|
-
}
|
|
451
|
-
} catch (e) {
|
|
452
|
-
console.warn('[GraphGenomeView] no bubble index for this graph', e)
|
|
492
|
+
const features = yield* readFeatures(
|
|
493
|
+
{
|
|
494
|
+
type: 'MinigraphBubbleAdapter',
|
|
495
|
+
uri: `${prefix}.bubbles.bed.gz`,
|
|
496
|
+
baseUri: adapterConfig.baseUri,
|
|
497
|
+
assemblyNameToPanSN: adapterConfig.assemblyNameToPanSN,
|
|
498
|
+
},
|
|
499
|
+
region,
|
|
500
|
+
'bubble index',
|
|
501
|
+
signal,
|
|
502
|
+
)
|
|
503
|
+
if (features && isLive()) {
|
|
504
|
+
self.indexBubbles = features.flatMap(f => {
|
|
505
|
+
const start = f.get('start')
|
|
506
|
+
const end = f.get('end')
|
|
507
|
+
const longestAlleleLength = f.get('longestAlleleLength') as number
|
|
508
|
+
return Math.max(end - start, longestAlleleLength) < foldBelowBp
|
|
509
|
+
? []
|
|
510
|
+
: [
|
|
511
|
+
{
|
|
512
|
+
refName: region.refName,
|
|
513
|
+
start,
|
|
514
|
+
end,
|
|
515
|
+
segmentCount: f.get('segmentCount') as number,
|
|
516
|
+
pathCount: (f.get('pathCount') as number | undefined) ?? 0,
|
|
517
|
+
inversion: f.get('inversion') as boolean,
|
|
518
|
+
shortestAlleleLength: f.get('shortestAlleleLength') as number,
|
|
519
|
+
longestAlleleLength,
|
|
520
|
+
segments: f.get('segments') as string,
|
|
521
|
+
shortestAllele: undefined,
|
|
522
|
+
longestAllele: undefined,
|
|
523
|
+
},
|
|
524
|
+
]
|
|
525
|
+
})
|
|
453
526
|
}
|
|
454
527
|
}
|
|
455
528
|
|
|
456
|
-
// A session track's features over the cut
|
|
457
|
-
//
|
|
458
|
-
// graph's problem.
|
|
529
|
+
// A session track's features over the cut, undefined when the session has
|
|
530
|
+
// no such track
|
|
459
531
|
function* trackFeatures(
|
|
460
532
|
trackId: string | undefined,
|
|
461
533
|
region: SubgraphRegion,
|
|
462
534
|
what: string,
|
|
463
535
|
signal?: AbortSignal,
|
|
464
536
|
) {
|
|
465
|
-
const session = getSession(self)
|
|
466
537
|
const config = trackId
|
|
467
|
-
?
|
|
538
|
+
? getSession(self).tracks.find(t => t.trackId === trackId)
|
|
468
539
|
: undefined
|
|
469
540
|
if (!config) {
|
|
470
541
|
return undefined
|
|
471
542
|
}
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
regions: [region],
|
|
479
|
-
signal,
|
|
480
|
-
},
|
|
481
|
-
)) as Feature[]
|
|
482
|
-
} catch (e) {
|
|
483
|
-
console.warn(`[GraphGenomeView] no ${what} for this graph`, e)
|
|
484
|
-
return undefined
|
|
485
|
-
}
|
|
543
|
+
return yield* readFeatures(
|
|
544
|
+
readConfObject(config, 'adapter'),
|
|
545
|
+
region,
|
|
546
|
+
what,
|
|
547
|
+
signal,
|
|
548
|
+
)
|
|
486
549
|
}
|
|
487
550
|
|
|
488
551
|
// The annotation tracks read over the cut: genes, which `geneFeatures`
|
|
@@ -504,6 +567,8 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
504
567
|
}
|
|
505
568
|
type Annotation = keyof typeof annotations
|
|
506
569
|
|
|
570
|
+
// Lands only while the track it read is still the one chosen, so a slow
|
|
571
|
+
// read cannot land over the pick that followed it
|
|
507
572
|
function* loadAnnotation(
|
|
508
573
|
kind: Annotation,
|
|
509
574
|
region: SubgraphRegion,
|
|
@@ -511,58 +576,55 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
511
576
|
signal?: AbortSignal,
|
|
512
577
|
) {
|
|
513
578
|
const { trackId, set } = annotations[kind]
|
|
514
|
-
const
|
|
515
|
-
|
|
579
|
+
const track = trackId()
|
|
580
|
+
const features = yield* trackFeatures(track, region, kind, signal)
|
|
581
|
+
if (features && isLive() && trackId() === track) {
|
|
516
582
|
set(features)
|
|
517
583
|
}
|
|
518
584
|
}
|
|
519
585
|
|
|
520
|
-
//
|
|
521
|
-
|
|
522
|
-
|
|
586
|
+
// The annotation reads over a cut, each landing as it arrives
|
|
587
|
+
function annotationReads(
|
|
588
|
+
region: SubgraphRegion,
|
|
589
|
+
isLive: () => boolean,
|
|
590
|
+
signal: AbortSignal,
|
|
591
|
+
) {
|
|
592
|
+
return (['genes', 'repeats'] as const).map(kind =>
|
|
593
|
+
flow(loadAnnotation)(kind, region, isLive, signal),
|
|
594
|
+
)
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// One annotation read again alone, for a track change
|
|
523
598
|
function* reloadAnnotation(kind: Annotation) {
|
|
524
|
-
const { trackId, set } = annotations[kind]
|
|
525
599
|
const region = self.graphRegion
|
|
526
|
-
const track = trackId()
|
|
527
600
|
if (region) {
|
|
528
|
-
set(undefined)
|
|
529
|
-
yield* loadAnnotation(
|
|
530
|
-
kind,
|
|
531
|
-
region,
|
|
532
|
-
() => self.graphRegion === region && trackId() === track,
|
|
533
|
-
)
|
|
601
|
+
annotations[kind].set(undefined)
|
|
602
|
+
yield* loadAnnotation(kind, region, () => self.graphRegion === region)
|
|
534
603
|
}
|
|
535
604
|
}
|
|
536
605
|
|
|
537
606
|
// Raises `isLoading` before any fetch, so a view waiting on a remote file
|
|
538
607
|
// shows its loading state instead of the import form. Text already in
|
|
539
608
|
// hand is parsed without yielding first. `region` is the window a
|
|
540
|
-
// declared file was stated beside, which the parse anchors on
|
|
609
|
+
// declared file was stated beside, which the parse anchors on and the
|
|
610
|
+
// annotations are read over.
|
|
541
611
|
function* loadWholeGFA(
|
|
542
612
|
name: string,
|
|
543
613
|
source: string | ((signal: AbortSignal) => Promise<string>),
|
|
544
614
|
region?: SubgraphRegion,
|
|
545
615
|
) {
|
|
546
|
-
|
|
547
|
-
self.isLoading = true
|
|
548
|
-
self.error = undefined
|
|
549
|
-
try {
|
|
616
|
+
yield* runLoad('loadWholeGFA', function* ({ isLive, signal }) {
|
|
550
617
|
const text =
|
|
551
618
|
typeof source === 'string' ? source : ((yield source(signal)) as string)
|
|
552
|
-
if (isLive()) {
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
} catch (e) {
|
|
556
|
-
if (isLive()) {
|
|
557
|
-
console.error('[GraphGenomeView.loadWholeGFA]', e)
|
|
558
|
-
self.error = e
|
|
619
|
+
if (!isLive()) {
|
|
620
|
+
return
|
|
559
621
|
}
|
|
560
|
-
|
|
561
|
-
if (isLive()) {
|
|
562
|
-
|
|
622
|
+
yield* parseAndLayout(text, name, region)
|
|
623
|
+
if (region && isLive()) {
|
|
624
|
+
self.setStatusMessage('Reading annotations')
|
|
625
|
+
yield Promise.all(annotationReads(region, isLive, signal))
|
|
563
626
|
}
|
|
564
|
-
}
|
|
565
|
-
return isLive()
|
|
627
|
+
})
|
|
566
628
|
}
|
|
567
629
|
|
|
568
630
|
function abortLoad() {
|
|
@@ -571,6 +633,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
571
633
|
loadInFlight = undefined
|
|
572
634
|
liveLoad++
|
|
573
635
|
liveRequest++
|
|
636
|
+
liveRequestPending = false
|
|
574
637
|
awaitedRun = undefined
|
|
575
638
|
}
|
|
576
639
|
|
|
@@ -592,27 +655,18 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
592
655
|
// would otherwise land its graph afterwards
|
|
593
656
|
function dropGraph() {
|
|
594
657
|
abortLoad()
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
self.loadedReferencePath = undefined
|
|
658
|
+
resetCut()
|
|
659
|
+
laidOutGraph = undefined
|
|
660
|
+
layoutError = undefined
|
|
599
661
|
self.layoutResult = undefined
|
|
600
662
|
self.drawnLayoutMode = undefined
|
|
601
|
-
self.indexBubbles = undefined
|
|
602
|
-
self.foldedBelowBp = undefined
|
|
603
|
-
self.geneTrackFeatures = undefined
|
|
604
|
-
self.walkGeneFeatures = undefined
|
|
605
|
-
walkGeneCache.clear()
|
|
606
|
-
self.repeatArrays = undefined
|
|
607
663
|
self.walkRowSampleTable = undefined
|
|
608
664
|
sampleTableKey = undefined
|
|
609
|
-
self.readsShown = undefined
|
|
610
665
|
self.openBubbles = []
|
|
611
666
|
self.error = undefined
|
|
612
667
|
self.isLoading = false
|
|
613
668
|
self.loadCanceled = false
|
|
614
669
|
self.statusMessage = ''
|
|
615
|
-
self.clearInteractionState()
|
|
616
670
|
self.clearPerfMetrics()
|
|
617
671
|
// the next graph has nothing to do with where the user left this one
|
|
618
672
|
if (self.viewportOwner === 'user') {
|
|
@@ -636,11 +690,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
636
690
|
// The user's stop, leaving whatever is drawn under it
|
|
637
691
|
stopLoad() {
|
|
638
692
|
abortLoad()
|
|
639
|
-
|
|
640
|
-
if (self.graph !== laidOutGraph) {
|
|
641
|
-
self.layoutResult = undefined
|
|
642
|
-
self.drawnLayoutMode = undefined
|
|
643
|
-
}
|
|
693
|
+
dropLayoutOfReplacedGraph()
|
|
644
694
|
self.isLoading = false
|
|
645
695
|
self.statusMessage = ''
|
|
646
696
|
self.loadCanceled = true
|
|
@@ -656,18 +706,11 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
656
706
|
region?: SubgraphRegion,
|
|
657
707
|
) {
|
|
658
708
|
self.setStatusMessage('Fetching GFA')
|
|
659
|
-
|
|
709
|
+
yield* loadWholeGFA(
|
|
660
710
|
fileName(location) || 'GFA',
|
|
661
711
|
signal => openLocation(location).readFile({ encoding: 'utf8', signal }),
|
|
662
712
|
region,
|
|
663
713
|
)
|
|
664
|
-
if (region && live && self.graph) {
|
|
665
|
-
const isLive = () => self.graphRegion === region
|
|
666
|
-
yield Promise.all([
|
|
667
|
-
flow(loadAnnotation)('genes', region, isLive),
|
|
668
|
-
flow(loadAnnotation)('repeats', region, isLive),
|
|
669
|
-
])
|
|
670
|
-
}
|
|
671
714
|
}),
|
|
672
715
|
// One cut of a region, laid out with the annotations over it. Whether
|
|
673
716
|
// the region may be cut is the caller's call; overlapping cuts are
|
|
@@ -678,11 +721,8 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
678
721
|
opts: SubgraphCutOptions = {},
|
|
679
722
|
foldBelowBp = 0,
|
|
680
723
|
) {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
self.error = undefined
|
|
684
|
-
self.setStatusMessage('Fetching subgraph')
|
|
685
|
-
try {
|
|
724
|
+
yield* runLoad('cutSubgraph', function* ({ isLive, signal }) {
|
|
725
|
+
self.setStatusMessage('Fetching subgraph')
|
|
686
726
|
const fetchStart = performance.now()
|
|
687
727
|
const cut = (yield getSession(self).rpcManager.call(
|
|
688
728
|
getRpcSessionId(self),
|
|
@@ -700,7 +740,7 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
700
740
|
}
|
|
701
741
|
yield* parseAndLayout(
|
|
702
742
|
cut,
|
|
703
|
-
|
|
743
|
+
regionLabel(region),
|
|
704
744
|
region,
|
|
705
745
|
true,
|
|
706
746
|
namesReads(adapterConfig)
|
|
@@ -734,19 +774,9 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
734
774
|
signal,
|
|
735
775
|
self.foldedBelowBp,
|
|
736
776
|
),
|
|
737
|
-
|
|
738
|
-
flow(loadAnnotation)('repeats', region, isLive, signal),
|
|
777
|
+
...annotationReads(region, isLive, signal),
|
|
739
778
|
])
|
|
740
|
-
}
|
|
741
|
-
if (isLive()) {
|
|
742
|
-
console.error('[GraphGenomeView.cutSubgraph]', e)
|
|
743
|
-
self.error = e
|
|
744
|
-
}
|
|
745
|
-
} finally {
|
|
746
|
-
if (isLive()) {
|
|
747
|
-
endLoad()
|
|
748
|
-
}
|
|
749
|
-
}
|
|
779
|
+
})
|
|
750
780
|
}),
|
|
751
781
|
// A track change re-reads that annotation alone. The graph, its layout
|
|
752
782
|
// and any open bubble stay as they are.
|
|
@@ -754,7 +784,6 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
754
784
|
yield* reloadAnnotation('repeats')
|
|
755
785
|
}),
|
|
756
786
|
reloadGenes: flow(function* () {
|
|
757
|
-
walkGeneCache.clear()
|
|
758
787
|
yield* reloadAnnotation('genes')
|
|
759
788
|
}),
|
|
760
789
|
// The source track's samples TSV, read once per location, for walk
|
|
@@ -866,19 +895,11 @@ export const withLoadActions = withSettingActions.actions(self => {
|
|
|
866
895
|
}
|
|
867
896
|
self.isLoading = true
|
|
868
897
|
self.setStatusMessage('Computing layout')
|
|
869
|
-
|
|
870
898
|
try {
|
|
871
|
-
|
|
872
|
-
// replaced it: clearing it here reports "done" while the layout the
|
|
873
|
-
// user actually asked for is still being computed, which is the
|
|
874
|
-
// common case when a cheap choice follows an expensive one.
|
|
875
|
-
if (yield* layoutInto(graph)) {
|
|
876
|
-
layoutSettled()
|
|
877
|
-
}
|
|
899
|
+
yield* layoutInto(graph)
|
|
878
900
|
} catch (e) {
|
|
879
901
|
console.error('[GraphGenomeView.recomputeLayout]', e)
|
|
880
902
|
self.error = e
|
|
881
|
-
layoutSettled()
|
|
882
903
|
}
|
|
883
904
|
}),
|
|
884
905
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { fadeAbgr } from '@jbrowse/bandage-core/renderer/colorBits'
|
|
2
2
|
import { strandSides } from '@jbrowse/bandage-core/util/geometry'
|
|
3
3
|
|
|
4
|
+
import type { ScreenTransform } from './keepInView'
|
|
4
5
|
import type { RenderBatch, Run } from '@jbrowse/bandage-core/renderer/types'
|
|
5
6
|
import type { Graph, NodeSegment } from '@jbrowse/bandage-core/types'
|
|
6
7
|
import type { EdgeSides } from '@jbrowse/bandage-core/util/geometry'
|
|
@@ -14,13 +15,6 @@ interface Attachment {
|
|
|
14
15
|
side: EdgeSides['from']
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
export interface PaneTransform {
|
|
18
|
-
scaleX: number
|
|
19
|
-
scaleY: number
|
|
20
|
-
translateX: number
|
|
21
|
-
translateY: number
|
|
22
|
-
}
|
|
23
|
-
|
|
24
18
|
// Morphs above this many nodes snap instead: each frame rebuilds the
|
|
25
19
|
// geometry, which past it no longer fits a frame (GRAPH_SCALE_AND_LOD.md)
|
|
26
20
|
export const MORPH_MAX_NODES = 3000
|
|
@@ -84,9 +78,9 @@ const RELAX_TOLERANCE_PX = 0.1
|
|
|
84
78
|
// end's point count, so a frame is a pointwise blend.
|
|
85
79
|
export function morphStarts(
|
|
86
80
|
prev: Positions,
|
|
87
|
-
prevTransform:
|
|
81
|
+
prevTransform: ScreenTransform,
|
|
88
82
|
next: Positions,
|
|
89
|
-
nextTransform:
|
|
83
|
+
nextTransform: ScreenTransform,
|
|
90
84
|
edges: Graph['edges'],
|
|
91
85
|
): Positions {
|
|
92
86
|
const toNext = (p: NodeSegment) => ({
|