@jbrowse/plugin-linear-genome-view 1.7.11 → 2.1.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/dist/BaseLinearDisplay/components/BaseLinearDisplay.js +119 -139
- package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js.map +1 -0
- package/dist/BaseLinearDisplay/components/Block.js +53 -74
- package/dist/BaseLinearDisplay/components/Block.js.map +1 -0
- package/dist/BaseLinearDisplay/components/LinearBlocks.d.ts +11 -1
- package/dist/BaseLinearDisplay/components/LinearBlocks.js +64 -103
- package/dist/BaseLinearDisplay/components/LinearBlocks.js.map +1 -0
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +146 -175
- package/dist/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -0
- package/dist/BaseLinearDisplay/components/Tooltip.js +109 -116
- package/dist/BaseLinearDisplay/components/Tooltip.js.map +1 -0
- package/dist/BaseLinearDisplay/index.js +13 -40
- package/dist/BaseLinearDisplay/index.js.map +1 -0
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +19 -14
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +605 -684
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -0
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js +15 -22
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +1 -0
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +7 -8
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js +266 -312
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -0
- package/dist/LinearBareDisplay/configSchema.js +11 -17
- package/dist/LinearBareDisplay/configSchema.js.map +1 -0
- package/dist/LinearBareDisplay/index.js +7 -20
- package/dist/LinearBareDisplay/index.js.map +1 -0
- package/dist/LinearBareDisplay/model.d.ts +15 -13
- package/dist/LinearBareDisplay/model.js +36 -42
- package/dist/LinearBareDisplay/model.js.map +1 -0
- package/dist/LinearBasicDisplay/components/SetMaxHeight.d.ts +1 -1
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js +76 -85
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -0
- package/dist/LinearBasicDisplay/configSchema.js +15 -23
- package/dist/LinearBasicDisplay/configSchema.js.map +1 -0
- package/dist/LinearBasicDisplay/index.js +10 -22
- package/dist/LinearBasicDisplay/index.js.map +1 -0
- package/dist/LinearBasicDisplay/model.d.ts +20 -14
- package/dist/LinearBasicDisplay/model.js +180 -159
- package/dist/LinearBasicDisplay/model.js.map +1 -0
- package/dist/LinearGenomeView/components/CenterLine.d.ts +2 -8
- package/dist/LinearGenomeView/components/CenterLine.js +60 -74
- package/dist/LinearGenomeView/components/CenterLine.js.map +1 -0
- package/dist/LinearGenomeView/components/ExportSvgDialog.js +141 -141
- package/dist/LinearGenomeView/components/ExportSvgDialog.js.map +1 -0
- package/dist/LinearGenomeView/components/Gridlines.d.ts +8 -0
- package/dist/LinearGenomeView/components/Gridlines.js +78 -0
- package/dist/LinearGenomeView/components/Gridlines.js.map +1 -0
- package/dist/LinearGenomeView/components/Header.d.ts +1 -0
- package/dist/LinearGenomeView/components/Header.js +70 -125
- package/dist/LinearGenomeView/components/Header.js.map +1 -0
- package/dist/LinearGenomeView/components/HelpDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/HelpDialog.js +62 -44
- package/dist/LinearGenomeView/components/HelpDialog.js.map +1 -0
- package/dist/LinearGenomeView/components/ImportForm.d.ts +1 -0
- package/dist/LinearGenomeView/components/ImportForm.js +222 -289
- package/dist/LinearGenomeView/components/ImportForm.js.map +1 -0
- package/dist/LinearGenomeView/components/LinearGenomeView.js +60 -124
- package/dist/LinearGenomeView/components/LinearGenomeView.js.map +1 -0
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js +198 -337
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -0
- package/dist/LinearGenomeView/components/MiniControls.js +64 -78
- package/dist/LinearGenomeView/components/MiniControls.js.map +1 -0
- package/dist/LinearGenomeView/components/OverviewRubberBand.js +229 -293
- package/dist/LinearGenomeView/components/OverviewRubberBand.js.map +1 -0
- package/dist/LinearGenomeView/components/OverviewScaleBar.d.ts +3 -3
- package/dist/LinearGenomeView/components/OverviewScaleBar.js +275 -370
- package/dist/LinearGenomeView/components/OverviewScaleBar.js.map +1 -0
- package/dist/LinearGenomeView/components/RefNameAutocomplete.d.ts +1 -1
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js +237 -324
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -0
- package/dist/LinearGenomeView/components/RubberBand.js +228 -296
- package/dist/LinearGenomeView/components/RubberBand.js.map +1 -0
- package/dist/LinearGenomeView/components/Ruler.js +45 -90
- package/dist/LinearGenomeView/components/Ruler.js.map +1 -0
- package/dist/LinearGenomeView/components/ScaleBar.d.ts +8 -403
- package/dist/LinearGenomeView/components/ScaleBar.js +121 -172
- package/dist/LinearGenomeView/components/ScaleBar.js.map +1 -0
- package/dist/LinearGenomeView/components/SearchBox.js +155 -166
- package/dist/LinearGenomeView/components/SearchBox.js.map +1 -0
- package/dist/LinearGenomeView/components/SearchResultsDialog.d.ts +0 -1
- package/dist/LinearGenomeView/components/SearchResultsDialog.js +105 -149
- package/dist/LinearGenomeView/components/SearchResultsDialog.js.map +1 -0
- package/dist/LinearGenomeView/components/SequenceDialog.js +219 -272
- package/dist/LinearGenomeView/components/SequenceDialog.js.map +1 -0
- package/dist/LinearGenomeView/components/TrackContainer.d.ts +2 -1
- package/dist/LinearGenomeView/components/TrackContainer.js +113 -158
- package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -0
- package/dist/LinearGenomeView/components/TrackLabel.d.ts +6 -42
- package/dist/LinearGenomeView/components/TrackLabel.js +113 -133
- package/dist/LinearGenomeView/components/TrackLabel.js.map +1 -0
- package/dist/LinearGenomeView/components/TracksContainer.d.ts +1 -1
- package/dist/LinearGenomeView/components/TracksContainer.js +172 -199
- package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -0
- package/dist/LinearGenomeView/components/ZoomControls.js +72 -87
- package/dist/LinearGenomeView/components/ZoomControls.js.map +1 -0
- package/dist/LinearGenomeView/components/util.js +94 -71
- package/dist/LinearGenomeView/components/util.js.map +1 -0
- package/dist/LinearGenomeView/index.d.ts +64 -77
- package/dist/LinearGenomeView/index.js +1035 -1412
- package/dist/LinearGenomeView/index.js.map +1 -0
- package/dist/LinearGenomeView/util.js +76 -83
- package/dist/LinearGenomeView/util.js.map +1 -0
- package/dist/index.d.ts +98 -48
- package/dist/index.js +225 -295
- package/dist/index.js.map +1 -0
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +9 -0
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.js +68 -0
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.js.map +1 -0
- package/esm/BaseLinearDisplay/components/Block.d.ts +15 -0
- package/esm/BaseLinearDisplay/components/Block.js +46 -0
- package/esm/BaseLinearDisplay/components/Block.js.map +1 -0
- package/esm/BaseLinearDisplay/components/LinearBlocks.d.ts +22 -0
- package/esm/BaseLinearDisplay/components/LinearBlocks.js +62 -0
- package/esm/BaseLinearDisplay/components/LinearBlocks.js.map +1 -0
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.d.ts +4 -0
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js +114 -0
- package/esm/BaseLinearDisplay/components/ServerSideRenderedBlockContent.js.map +1 -0
- package/esm/BaseLinearDisplay/components/Tooltip.d.ts +8 -0
- package/esm/BaseLinearDisplay/components/Tooltip.js +64 -0
- package/esm/BaseLinearDisplay/components/Tooltip.js.map +1 -0
- package/esm/BaseLinearDisplay/index.d.ts +5 -0
- package/esm/BaseLinearDisplay/index.js +4 -0
- package/esm/BaseLinearDisplay/index.js.map +1 -0
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +232 -0
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +541 -0
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -0
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.d.ts +1 -0
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js +14 -0
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +1 -0
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.d.ts +96 -0
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js +225 -0
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -0
- package/esm/LinearBareDisplay/configSchema.d.ts +2 -0
- package/esm/LinearBareDisplay/configSchema.js +9 -0
- package/esm/LinearBareDisplay/configSchema.js.map +1 -0
- package/esm/LinearBareDisplay/index.d.ts +2 -0
- package/esm/LinearBareDisplay/index.js +3 -0
- package/esm/LinearBareDisplay/index.js.map +1 -0
- package/esm/LinearBareDisplay/model.d.ts +194 -0
- package/esm/LinearBareDisplay/model.js +28 -0
- package/esm/LinearBareDisplay/model.js.map +1 -0
- package/esm/LinearBasicDisplay/components/SetMaxHeight.d.ts +10 -0
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js +40 -0
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -0
- package/esm/LinearBasicDisplay/configSchema.d.ts +2 -0
- package/esm/LinearBasicDisplay/configSchema.js +14 -0
- package/esm/LinearBasicDisplay/configSchema.js.map +1 -0
- package/esm/LinearBasicDisplay/index.d.ts +2 -0
- package/esm/LinearBasicDisplay/index.js +3 -0
- package/esm/LinearBasicDisplay/index.js.map +1 -0
- package/esm/LinearBasicDisplay/model.d.ts +218 -0
- package/esm/LinearBasicDisplay/model.js +127 -0
- package/esm/LinearBasicDisplay/model.js.map +1 -0
- package/esm/LinearGenomeView/components/CenterLine.d.ts +8 -0
- package/esm/LinearGenomeView/components/CenterLine.js +40 -0
- package/esm/LinearGenomeView/components/CenterLine.js.map +1 -0
- package/esm/LinearGenomeView/components/ExportSvgDialog.d.ts +6 -0
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +52 -0
- package/esm/LinearGenomeView/components/ExportSvgDialog.js.map +1 -0
- package/esm/LinearGenomeView/components/Gridlines.d.ts +8 -0
- package/esm/LinearGenomeView/components/Gridlines.js +71 -0
- package/esm/LinearGenomeView/components/Gridlines.js.map +1 -0
- package/esm/LinearGenomeView/components/Header.d.ts +7 -0
- package/esm/LinearGenomeView/components/Header.js +81 -0
- package/esm/LinearGenomeView/components/Header.js.map +1 -0
- package/esm/LinearGenomeView/components/HelpDialog.d.ts +4 -0
- package/esm/LinearGenomeView/components/HelpDialog.js +58 -0
- package/esm/LinearGenomeView/components/HelpDialog.js.map +1 -0
- package/esm/LinearGenomeView/components/ImportForm.d.ts +7 -0
- package/esm/LinearGenomeView/components/ImportForm.js +141 -0
- package/esm/LinearGenomeView/components/ImportForm.js.map +1 -0
- package/esm/LinearGenomeView/components/LinearGenomeView.d.ts +7 -0
- package/esm/LinearGenomeView/components/LinearGenomeView.js +63 -0
- package/esm/LinearGenomeView/components/LinearGenomeView.js.map +1 -0
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.d.ts +4 -0
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js +132 -0
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -0
- package/esm/LinearGenomeView/components/MiniControls.d.ts +6 -0
- package/esm/LinearGenomeView/components/MiniControls.js +25 -0
- package/esm/LinearGenomeView/components/MiniControls.js.map +1 -0
- package/esm/LinearGenomeView/components/OverviewRubberBand.d.ts +22 -0
- package/esm/LinearGenomeView/components/OverviewRubberBand.js +197 -0
- package/esm/LinearGenomeView/components/OverviewRubberBand.js.map +1 -0
- package/esm/LinearGenomeView/components/OverviewScaleBar.d.ts +148 -0
- package/esm/LinearGenomeView/components/OverviewScaleBar.js +287 -0
- package/esm/LinearGenomeView/components/OverviewScaleBar.js.map +1 -0
- package/esm/LinearGenomeView/components/RefNameAutocomplete.d.ts +22 -0
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js +136 -0
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -0
- package/esm/LinearGenomeView/components/RubberBand.d.ts +9 -0
- package/esm/LinearGenomeView/components/RubberBand.js +197 -0
- package/esm/LinearGenomeView/components/RubberBand.js.map +1 -0
- package/esm/LinearGenomeView/components/Ruler.d.ts +27 -0
- package/esm/LinearGenomeView/components/Ruler.js +50 -0
- package/esm/LinearGenomeView/components/Ruler.js.map +1 -0
- package/esm/LinearGenomeView/components/ScaleBar.d.ts +10 -0
- package/esm/LinearGenomeView/components/ScaleBar.js +112 -0
- package/esm/LinearGenomeView/components/ScaleBar.js.map +1 -0
- package/esm/LinearGenomeView/components/SearchBox.d.ts +8 -0
- package/esm/LinearGenomeView/components/SearchBox.js +94 -0
- package/esm/LinearGenomeView/components/SearchBox.js.map +1 -0
- package/esm/LinearGenomeView/components/SearchResultsDialog.d.ts +7 -0
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +107 -0
- package/esm/LinearGenomeView/components/SearchResultsDialog.js.map +1 -0
- package/esm/LinearGenomeView/components/SequenceDialog.d.ts +8 -0
- package/esm/LinearGenomeView/components/SequenceDialog.js +147 -0
- package/esm/LinearGenomeView/components/SequenceDialog.js.map +1 -0
- package/esm/LinearGenomeView/components/TrackContainer.d.ts +10 -0
- package/esm/LinearGenomeView/components/TrackContainer.js +104 -0
- package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -0
- package/esm/LinearGenomeView/components/TrackLabel.d.ts +8 -0
- package/esm/LinearGenomeView/components/TrackLabel.js +88 -0
- package/esm/LinearGenomeView/components/TrackLabel.js.map +1 -0
- package/{dist/LinearGenomeView/components/VerticalGuides.d.ts → esm/LinearGenomeView/components/TracksContainer.d.ts} +4 -3
- package/esm/LinearGenomeView/components/TracksContainer.js +142 -0
- package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -0
- package/esm/LinearGenomeView/components/ZoomControls.d.ts +7 -0
- package/esm/LinearGenomeView/components/ZoomControls.js +32 -0
- package/esm/LinearGenomeView/components/ZoomControls.js.map +1 -0
- package/esm/LinearGenomeView/components/util.d.ts +14 -0
- package/esm/LinearGenomeView/components/util.js +17 -0
- package/esm/LinearGenomeView/components/util.js.map +1 -0
- package/esm/LinearGenomeView/index.d.ts +275 -0
- package/esm/LinearGenomeView/index.js +978 -0
- package/esm/LinearGenomeView/index.js.map +1 -0
- package/esm/LinearGenomeView/util.d.ts +14 -0
- package/esm/LinearGenomeView/util.js +62 -0
- package/esm/LinearGenomeView/util.js.map +1 -0
- package/esm/index.d.ts +615 -0
- package/esm/index.js +127 -0
- package/esm/index.js.map +1 -0
- package/package.json +22 -15
- package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +4 -4
- package/src/BaseLinearDisplay/components/Block.tsx +5 -5
- package/src/BaseLinearDisplay/components/LinearBlocks.tsx +4 -4
- package/src/BaseLinearDisplay/components/ServerSideRenderedBlockContent.tsx +9 -9
- package/src/BaseLinearDisplay/components/Tooltip.tsx +14 -4
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +6 -4
- package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +1 -1
- package/src/LinearBasicDisplay/components/SetMaxHeight.tsx +10 -7
- package/src/LinearBasicDisplay/model.ts +19 -11
- package/src/LinearGenomeView/components/CenterLine.tsx +6 -11
- package/src/LinearGenomeView/components/ExportSvgDialog.tsx +5 -5
- package/src/LinearGenomeView/components/{VerticalGuides.tsx → Gridlines.tsx} +9 -11
- package/src/LinearGenomeView/components/Header.tsx +10 -15
- package/src/LinearGenomeView/components/HelpDialog.tsx +5 -5
- package/src/LinearGenomeView/components/ImportForm.tsx +6 -12
- package/src/LinearGenomeView/components/LinearGenomeView.test.js +16 -6
- package/src/LinearGenomeView/components/LinearGenomeView.tsx +6 -9
- package/src/LinearGenomeView/components/MiniControls.tsx +29 -40
- package/src/LinearGenomeView/components/OverviewRubberBand.tsx +20 -29
- package/src/LinearGenomeView/components/OverviewScaleBar.tsx +61 -59
- package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +13 -44
- package/src/LinearGenomeView/components/RubberBand.tsx +12 -18
- package/src/LinearGenomeView/components/Ruler.tsx +5 -11
- package/src/LinearGenomeView/components/ScaleBar.tsx +23 -27
- package/src/LinearGenomeView/components/SearchBox.tsx +4 -3
- package/src/LinearGenomeView/components/SearchResultsDialog.tsx +7 -6
- package/src/LinearGenomeView/components/SequenceDialog.tsx +10 -10
- package/src/LinearGenomeView/components/TrackContainer.tsx +29 -39
- package/src/LinearGenomeView/components/TrackLabel.tsx +76 -79
- package/src/LinearGenomeView/components/TracksContainer.tsx +10 -15
- package/src/LinearGenomeView/components/ZoomControls.tsx +12 -13
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.js.snap +500 -550
- package/src/LinearGenomeView/index.test.ts +15 -36
- package/src/LinearGenomeView/index.tsx +390 -564
- package/src/index.ts +1 -1
- package/dist/LinearBareDisplay/index.test.js +0 -33
- package/dist/LinearGenomeView/components/LinearGenomeView.test.js +0 -234
- package/dist/LinearGenomeView/components/ScaleBar.test.js +0 -180
- package/dist/LinearGenomeView/components/VerticalGuides.js +0 -116
- package/dist/LinearGenomeView/index.test.js +0 -1187
- package/dist/LinearGenomeView/util.test.js +0 -78
|
@@ -14,7 +14,6 @@ import {
|
|
|
14
14
|
measureText,
|
|
15
15
|
parseLocString,
|
|
16
16
|
springAnimate,
|
|
17
|
-
viewBpToPx,
|
|
18
17
|
} from '@jbrowse/core/util'
|
|
19
18
|
import BaseResult from '@jbrowse/core/TextSearch/BaseResults'
|
|
20
19
|
import { BlockSet, BaseBlock } from '@jbrowse/core/util/blockTypes'
|
|
@@ -33,19 +32,20 @@ import {
|
|
|
33
32
|
} from 'mobx-state-tree'
|
|
34
33
|
|
|
35
34
|
import Base1DView from '@jbrowse/core/util/Base1DViewModel'
|
|
36
|
-
import
|
|
37
|
-
import clone from 'clone'
|
|
35
|
+
import { moveTo, pxToBp, bpToPx } from '@jbrowse/core/util/Base1DUtils'
|
|
38
36
|
import { saveAs } from 'file-saver'
|
|
37
|
+
import clone from 'clone'
|
|
38
|
+
import PluginManager from '@jbrowse/core/PluginManager'
|
|
39
39
|
|
|
40
40
|
// icons
|
|
41
41
|
import { TrackSelector as TrackSelectorIcon } from '@jbrowse/core/ui/Icons'
|
|
42
|
-
import SyncAltIcon from '@
|
|
43
|
-
import VisibilityIcon from '@
|
|
44
|
-
import LabelIcon from '@
|
|
45
|
-
import FolderOpenIcon from '@
|
|
46
|
-
import PhotoCameraIcon from '@
|
|
47
|
-
import ZoomInIcon from '@
|
|
48
|
-
import MenuOpenIcon from '@
|
|
42
|
+
import SyncAltIcon from '@mui/icons-material/SyncAlt'
|
|
43
|
+
import VisibilityIcon from '@mui/icons-material/Visibility'
|
|
44
|
+
import LabelIcon from '@mui/icons-material/Label'
|
|
45
|
+
import FolderOpenIcon from '@mui/icons-material/FolderOpen'
|
|
46
|
+
import PhotoCameraIcon from '@mui/icons-material/PhotoCamera'
|
|
47
|
+
import ZoomInIcon from '@mui/icons-material/ZoomIn'
|
|
48
|
+
import MenuOpenIcon from '@mui/icons-material/MenuOpen'
|
|
49
49
|
|
|
50
50
|
// locals
|
|
51
51
|
import { renderToSvg } from './components/LinearGenomeViewSvg'
|
|
@@ -144,6 +144,7 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
144
144
|
const setting = localStorageGetItem('lgv-showCytobands')
|
|
145
145
|
return setting !== undefined && setting !== null ? !!+setting : true
|
|
146
146
|
}),
|
|
147
|
+
showGridlines: true,
|
|
147
148
|
}),
|
|
148
149
|
)
|
|
149
150
|
.volatile(() => ({
|
|
@@ -288,99 +289,6 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
288
289
|
}
|
|
289
290
|
},
|
|
290
291
|
|
|
291
|
-
bpToPx({
|
|
292
|
-
refName,
|
|
293
|
-
coord,
|
|
294
|
-
regionNumber,
|
|
295
|
-
}: {
|
|
296
|
-
refName: string
|
|
297
|
-
coord: number
|
|
298
|
-
regionNumber?: number
|
|
299
|
-
}) {
|
|
300
|
-
return viewBpToPx({ refName, coord, regionNumber, self })
|
|
301
|
-
},
|
|
302
|
-
/**
|
|
303
|
-
*
|
|
304
|
-
* @param px - px in the view area, return value is the displayed regions
|
|
305
|
-
* @returns BpOffset of the displayed region that it lands in
|
|
306
|
-
*/
|
|
307
|
-
pxToBp(px: number) {
|
|
308
|
-
let bpSoFar = 0
|
|
309
|
-
const bp = (self.offsetPx + px) * self.bpPerPx
|
|
310
|
-
const n = self.displayedRegions.length
|
|
311
|
-
if (bp < 0) {
|
|
312
|
-
const region = self.displayedRegions[0]
|
|
313
|
-
const offset = bp
|
|
314
|
-
return {
|
|
315
|
-
...getSnapshot(region),
|
|
316
|
-
oob: true,
|
|
317
|
-
coord: region.reversed
|
|
318
|
-
? Math.floor(region.end - offset) + 1
|
|
319
|
-
: Math.floor(region.start + offset) + 1,
|
|
320
|
-
offset,
|
|
321
|
-
index: 0,
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
const interRegionPaddingBp = self.interRegionPaddingWidth * self.bpPerPx
|
|
326
|
-
const minimumBlockBp = self.minimumBlockWidth * self.bpPerPx
|
|
327
|
-
|
|
328
|
-
for (let index = 0; index < self.displayedRegions.length; index += 1) {
|
|
329
|
-
const region = self.displayedRegions[index]
|
|
330
|
-
const len = region.end - region.start
|
|
331
|
-
const offset = bp - bpSoFar
|
|
332
|
-
if (len + bpSoFar > bp && bpSoFar <= bp) {
|
|
333
|
-
return {
|
|
334
|
-
...getSnapshot(region),
|
|
335
|
-
oob: false,
|
|
336
|
-
offset,
|
|
337
|
-
coord: region.reversed
|
|
338
|
-
? Math.floor(region.end - offset) + 1
|
|
339
|
-
: Math.floor(region.start + offset) + 1,
|
|
340
|
-
index,
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// add the interRegionPaddingWidth if the boundary is in the screen
|
|
345
|
-
// e.g. offset>0 && offset<width
|
|
346
|
-
if (
|
|
347
|
-
region.end - region.start > minimumBlockBp &&
|
|
348
|
-
offset / self.bpPerPx > 0 &&
|
|
349
|
-
offset / self.bpPerPx < self.width
|
|
350
|
-
) {
|
|
351
|
-
bpSoFar += len + interRegionPaddingBp
|
|
352
|
-
} else {
|
|
353
|
-
bpSoFar += len
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
if (bp >= bpSoFar) {
|
|
358
|
-
const region = self.displayedRegions[n - 1]
|
|
359
|
-
const len = region.end - region.start
|
|
360
|
-
const offset = bp - bpSoFar + len
|
|
361
|
-
return {
|
|
362
|
-
...getSnapshot(region),
|
|
363
|
-
oob: true,
|
|
364
|
-
offset,
|
|
365
|
-
coord: region.reversed
|
|
366
|
-
? Math.floor(region.end - offset) + 1
|
|
367
|
-
: Math.floor(region.start + offset) + 1,
|
|
368
|
-
index: n - 1,
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
return {
|
|
372
|
-
coord: 0,
|
|
373
|
-
index: 0,
|
|
374
|
-
refName: '',
|
|
375
|
-
oob: true,
|
|
376
|
-
assemblyName: '',
|
|
377
|
-
offset: 0,
|
|
378
|
-
start: 0,
|
|
379
|
-
end: 0,
|
|
380
|
-
reversed: false,
|
|
381
|
-
}
|
|
382
|
-
},
|
|
383
|
-
|
|
384
292
|
getTrack(id: string) {
|
|
385
293
|
return self.tracks.find(t => t.configuration.trackId === id)
|
|
386
294
|
},
|
|
@@ -431,12 +339,6 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
431
339
|
|
|
432
340
|
return allActions
|
|
433
341
|
},
|
|
434
|
-
|
|
435
|
-
get centerLineInfo() {
|
|
436
|
-
return self.displayedRegions.length
|
|
437
|
-
? this.pxToBp(self.width / 2)
|
|
438
|
-
: undefined
|
|
439
|
-
},
|
|
440
342
|
}))
|
|
441
343
|
.actions(self => ({
|
|
442
344
|
setShowCytobands(flag: boolean) {
|
|
@@ -460,6 +362,9 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
460
362
|
toggleNoTracksActive() {
|
|
461
363
|
self.hideNoTracksActive = !self.hideNoTracksActive
|
|
462
364
|
},
|
|
365
|
+
toggleShowGridlines() {
|
|
366
|
+
self.showGridlines = !self.showGridlines
|
|
367
|
+
},
|
|
463
368
|
|
|
464
369
|
scrollTo(offsetPx: number) {
|
|
465
370
|
const newOffsetPx = clamp(offsetPx, self.minOffset, self.maxOffset)
|
|
@@ -529,26 +434,19 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
529
434
|
initialSnapshot = {},
|
|
530
435
|
displayInitialSnapshot = {},
|
|
531
436
|
) {
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
trackConfigSchema,
|
|
536
|
-
getRoot(self),
|
|
537
|
-
trackId,
|
|
538
|
-
)
|
|
539
|
-
if (!configuration) {
|
|
437
|
+
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
438
|
+
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
439
|
+
if (!conf) {
|
|
540
440
|
throw new Error(`Could not resolve identifier "${trackId}"`)
|
|
541
441
|
}
|
|
542
|
-
const trackType = pluginManager.getTrackType(
|
|
442
|
+
const trackType = pluginManager.getTrackType(conf?.type)
|
|
543
443
|
if (!trackType) {
|
|
544
|
-
throw new Error(`Unknown track type ${
|
|
444
|
+
throw new Error(`Unknown track type ${conf.type}`)
|
|
545
445
|
}
|
|
546
446
|
const viewType = pluginManager.getViewType(self.type)
|
|
547
|
-
const supportedDisplays = viewType.displayTypes.map(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const displayConf = configuration.displays.find(
|
|
551
|
-
(d: AnyConfigurationModel) => supportedDisplays.includes(d.type),
|
|
447
|
+
const supportedDisplays = viewType.displayTypes.map(d => d.name)
|
|
448
|
+
const displayConf = conf.displays.find((d: AnyConfigurationModel) =>
|
|
449
|
+
supportedDisplays.includes(d.type),
|
|
552
450
|
)
|
|
553
451
|
if (!displayConf) {
|
|
554
452
|
throw new Error(
|
|
@@ -556,14 +454,12 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
556
454
|
)
|
|
557
455
|
}
|
|
558
456
|
|
|
559
|
-
const
|
|
560
|
-
|
|
561
|
-
)
|
|
562
|
-
if (shownTracks.length === 0) {
|
|
457
|
+
const t = self.tracks.filter(t => t.configuration === conf)
|
|
458
|
+
if (t.length === 0) {
|
|
563
459
|
const track = trackType.stateModel.create({
|
|
564
460
|
...initialSnapshot,
|
|
565
|
-
type:
|
|
566
|
-
configuration,
|
|
461
|
+
type: conf.type,
|
|
462
|
+
configuration: conf,
|
|
567
463
|
displays: [
|
|
568
464
|
{
|
|
569
465
|
type: displayConf.type,
|
|
@@ -575,38 +471,26 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
575
471
|
self.tracks.push(track)
|
|
576
472
|
return track
|
|
577
473
|
}
|
|
578
|
-
return
|
|
474
|
+
return t[0]
|
|
579
475
|
},
|
|
580
476
|
|
|
581
477
|
hideTrack(trackId: string) {
|
|
582
|
-
const
|
|
583
|
-
|
|
584
|
-
const
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
trackId,
|
|
588
|
-
)
|
|
589
|
-
// if we have any tracks with that configuration, turn them off
|
|
590
|
-
const shownTracks = self.tracks.filter(
|
|
591
|
-
t => t.configuration === configuration,
|
|
592
|
-
)
|
|
593
|
-
transaction(() => shownTracks.forEach(t => self.tracks.remove(t)))
|
|
594
|
-
return shownTracks.length
|
|
478
|
+
const schema = pluginManager.pluggableConfigSchemaType('track')
|
|
479
|
+
const conf = resolveIdentifier(schema, getRoot(self), trackId)
|
|
480
|
+
const t = self.tracks.filter(t => t.configuration === conf)
|
|
481
|
+
transaction(() => t.forEach(t => self.tracks.remove(t)))
|
|
482
|
+
return t.length
|
|
595
483
|
},
|
|
596
484
|
}))
|
|
597
485
|
.actions(self => ({
|
|
598
|
-
moveTrack(
|
|
599
|
-
const oldIndex = self.tracks.findIndex(
|
|
600
|
-
track => track.id === movingTrackId,
|
|
601
|
-
)
|
|
486
|
+
moveTrack(movingId: string, targetId: string) {
|
|
487
|
+
const oldIndex = self.tracks.findIndex(track => track.id === movingId)
|
|
602
488
|
if (oldIndex === -1) {
|
|
603
|
-
throw new Error(`Track ID ${
|
|
489
|
+
throw new Error(`Track ID ${movingId} not found`)
|
|
604
490
|
}
|
|
605
|
-
const newIndex = self.tracks.findIndex(
|
|
606
|
-
track => track.id === targetTrackId,
|
|
607
|
-
)
|
|
491
|
+
const newIndex = self.tracks.findIndex(track => track.id === targetId)
|
|
608
492
|
if (newIndex === -1) {
|
|
609
|
-
throw new Error(`Track ID ${
|
|
493
|
+
throw new Error(`Track ID ${targetId} not found`)
|
|
610
494
|
}
|
|
611
495
|
const track = getSnapshot(self.tracks[oldIndex])
|
|
612
496
|
self.tracks.splice(oldIndex, 1)
|
|
@@ -666,429 +550,83 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
666
550
|
throw new Error(`invalid track selector type ${self.trackSelectorType}`)
|
|
667
551
|
},
|
|
668
552
|
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
parseLocString(l, ref => isValidRefName(ref, assemblyName)),
|
|
685
|
-
)
|
|
686
|
-
} catch (e) {
|
|
687
|
-
// if this fails, try interpreting as a whitespace-separated refname,
|
|
688
|
-
// start, end if start and end are integer inputs
|
|
689
|
-
const [refName, start, end] = inputs
|
|
690
|
-
if (
|
|
691
|
-
`${e}`.match(/Unknown reference sequence/) &&
|
|
692
|
-
Number.isInteger(+start) &&
|
|
693
|
-
Number.isInteger(+end)
|
|
694
|
-
) {
|
|
695
|
-
parsedLocStrings = [
|
|
696
|
-
parseLocString(refName + ':' + start + '..' + end, ref =>
|
|
697
|
-
isValidRefName(ref, assemblyName),
|
|
698
|
-
),
|
|
699
|
-
]
|
|
700
|
-
} else {
|
|
701
|
-
throw e
|
|
702
|
-
}
|
|
703
|
-
}
|
|
553
|
+
/**
|
|
554
|
+
* Helper method for the fetchSequence.
|
|
555
|
+
* Retrieves the corresponding regions that were selected by the rubberband
|
|
556
|
+
*
|
|
557
|
+
* @param leftOffset - `object as {start, end, index, offset}`, offset = start of user drag
|
|
558
|
+
* @param rightOffset - `object as {start, end, index, offset}`, offset = end of user drag
|
|
559
|
+
* @returns array of Region[]
|
|
560
|
+
*/
|
|
561
|
+
getSelectedRegions(leftOffset?: BpOffset, rightOffset?: BpOffset) {
|
|
562
|
+
const snap = getSnapshot(self)
|
|
563
|
+
const simView = Base1DView.create({
|
|
564
|
+
// xref https://github.com/mobxjs/mobx-state-tree/issues/1524 for Omit
|
|
565
|
+
...(snap as Omit<typeof self, symbol>),
|
|
566
|
+
interRegionPaddingWidth: self.interRegionPaddingWidth,
|
|
567
|
+
})
|
|
704
568
|
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
const asm = assemblyManager.get(asmName)
|
|
708
|
-
const { refName } = region
|
|
709
|
-
if (!asm) {
|
|
710
|
-
throw new Error(`assembly ${asmName} not found`)
|
|
711
|
-
}
|
|
712
|
-
const { regions } = asm
|
|
713
|
-
if (!regions) {
|
|
714
|
-
throw new Error(`regions not loaded yet for ${asmName}`)
|
|
715
|
-
}
|
|
716
|
-
const canonicalRefName = asm.getCanonicalRefName(region.refName)
|
|
717
|
-
if (!canonicalRefName) {
|
|
718
|
-
throw new Error(`Could not find refName ${refName} in ${asm.name}`)
|
|
719
|
-
}
|
|
720
|
-
const parentRegion = regions.find(
|
|
721
|
-
region => region.refName === canonicalRefName,
|
|
722
|
-
)
|
|
723
|
-
if (!parentRegion) {
|
|
724
|
-
throw new Error(`Could not find refName ${refName} in ${asmName}`)
|
|
725
|
-
}
|
|
569
|
+
simView.setVolatileWidth(self.width)
|
|
570
|
+
simView.moveTo(leftOffset, rightOffset)
|
|
726
571
|
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
572
|
+
return simView.dynamicBlocks.contentBlocks.map(region => ({
|
|
573
|
+
...region,
|
|
574
|
+
start: Math.floor(region.start),
|
|
575
|
+
end: Math.ceil(region.end),
|
|
576
|
+
}))
|
|
577
|
+
},
|
|
733
578
|
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
])
|
|
739
|
-
const { start, end, parentRegion } = loc
|
|
579
|
+
// schedule something to be run after the next time displayedRegions is set
|
|
580
|
+
afterDisplayedRegionsSet(cb: Function) {
|
|
581
|
+
self.afterDisplayedRegionsSetCallbacks.push(cb)
|
|
582
|
+
},
|
|
740
583
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
} else {
|
|
747
|
-
this.setDisplayedRegions(
|
|
748
|
-
// @ts-ignore
|
|
749
|
-
locations.map(r => (r.start === undefined ? r.parentRegion : r)),
|
|
750
|
-
)
|
|
751
|
-
this.showAllRegions()
|
|
752
|
-
}
|
|
584
|
+
horizontalScroll(distance: number) {
|
|
585
|
+
const oldOffsetPx = self.offsetPx
|
|
586
|
+
// newOffsetPx is the actual offset after the scroll is clamped
|
|
587
|
+
const newOffsetPx = self.scrollTo(self.offsetPx + distance)
|
|
588
|
+
return newOffsetPx - oldOffsetPx
|
|
753
589
|
},
|
|
754
590
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
* within a displayedRegion. Navigates to the first matching location
|
|
760
|
-
* encountered.
|
|
761
|
-
*
|
|
762
|
-
* Throws an error if navigation was unsuccessful
|
|
763
|
-
*
|
|
764
|
-
* @param location - a proposed location to navigate to
|
|
765
|
-
*/
|
|
766
|
-
navTo(query: NavLocation) {
|
|
767
|
-
this.navToMultiple([query])
|
|
591
|
+
center() {
|
|
592
|
+
const centerBp = self.totalBp / 2
|
|
593
|
+
const centerPx = centerBp / self.bpPerPx
|
|
594
|
+
self.scrollTo(Math.round(centerPx - self.width / 2))
|
|
768
595
|
},
|
|
769
596
|
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
start,
|
|
775
|
-
end,
|
|
776
|
-
assemblyName = self.assemblyNames[0],
|
|
777
|
-
} = firstLocation
|
|
597
|
+
showAllRegions() {
|
|
598
|
+
self.zoomTo(self.maxBpPerPx)
|
|
599
|
+
this.center()
|
|
600
|
+
},
|
|
778
601
|
|
|
779
|
-
|
|
780
|
-
throw new Error(`start "${start + 1}" is greater than end "${end}"`)
|
|
781
|
-
}
|
|
602
|
+
showAllRegionsInAssembly(assemblyName?: string) {
|
|
782
603
|
const session = getSession(self)
|
|
783
604
|
const { assemblyManager } = session
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
605
|
+
if (!assemblyName) {
|
|
606
|
+
const assemblyNames = [
|
|
607
|
+
...new Set(
|
|
608
|
+
self.displayedRegions.map(region => region.assemblyName),
|
|
609
|
+
),
|
|
610
|
+
]
|
|
611
|
+
if (assemblyNames.length > 1) {
|
|
612
|
+
session.notify(
|
|
613
|
+
`Can't perform this with multiple assemblies currently`,
|
|
614
|
+
)
|
|
615
|
+
return
|
|
789
616
|
}
|
|
617
|
+
|
|
618
|
+
;[assemblyName] = assemblyNames
|
|
790
619
|
}
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
s = r.start
|
|
799
|
-
}
|
|
800
|
-
if (e === undefined) {
|
|
801
|
-
e = r.end
|
|
802
|
-
}
|
|
803
|
-
if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
|
|
804
|
-
return true
|
|
805
|
-
}
|
|
806
|
-
s = start
|
|
807
|
-
e = end
|
|
620
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
621
|
+
if (assembly) {
|
|
622
|
+
const { regions } = assembly
|
|
623
|
+
if (regions) {
|
|
624
|
+
this.setDisplayedRegions(regions)
|
|
625
|
+
self.zoomTo(self.maxBpPerPx)
|
|
626
|
+
this.center()
|
|
808
627
|
}
|
|
809
|
-
return false
|
|
810
628
|
}
|
|
811
|
-
|
|
812
|
-
const lastIndex = findLastIndex(self.displayedRegions, predicate)
|
|
813
|
-
let index
|
|
814
|
-
while (index !== lastIndex) {
|
|
815
|
-
try {
|
|
816
|
-
const previousIndex: number | undefined = index
|
|
817
|
-
index = self.displayedRegions
|
|
818
|
-
.slice(previousIndex === undefined ? 0 : previousIndex + 1)
|
|
819
|
-
.findIndex(predicate)
|
|
820
|
-
if (previousIndex !== undefined) {
|
|
821
|
-
index += previousIndex + 1
|
|
822
|
-
}
|
|
823
|
-
if (!refNameMatched) {
|
|
824
|
-
throw new Error(
|
|
825
|
-
`could not find a region with refName "${refName}"`,
|
|
826
|
-
)
|
|
827
|
-
}
|
|
828
|
-
if (s === undefined) {
|
|
829
|
-
throw new Error(
|
|
830
|
-
`could not find a region with refName "${refName}" that contained an end position ${e}`,
|
|
831
|
-
)
|
|
832
|
-
}
|
|
833
|
-
if (e === undefined) {
|
|
834
|
-
throw new Error(
|
|
835
|
-
`could not find a region with refName "${refName}" that contained a start position ${
|
|
836
|
-
s + 1
|
|
837
|
-
}`,
|
|
838
|
-
)
|
|
839
|
-
}
|
|
840
|
-
if (index === -1) {
|
|
841
|
-
throw new Error(
|
|
842
|
-
`could not find a region that completely contained "${assembleLocString(
|
|
843
|
-
firstLocation,
|
|
844
|
-
)}"`,
|
|
845
|
-
)
|
|
846
|
-
}
|
|
847
|
-
if (locations.length === 1) {
|
|
848
|
-
const f = self.displayedRegions[index]
|
|
849
|
-
this.moveTo(
|
|
850
|
-
{ index, offset: f.reversed ? f.end - e : s - f.start },
|
|
851
|
-
{ index, offset: f.reversed ? f.end - s : e - f.start },
|
|
852
|
-
)
|
|
853
|
-
return
|
|
854
|
-
}
|
|
855
|
-
let locationIndex = 0
|
|
856
|
-
let locationStart = 0
|
|
857
|
-
let locationEnd = 0
|
|
858
|
-
for (
|
|
859
|
-
locationIndex;
|
|
860
|
-
locationIndex < locations.length;
|
|
861
|
-
locationIndex++
|
|
862
|
-
) {
|
|
863
|
-
const location = locations[locationIndex]
|
|
864
|
-
const region = self.displayedRegions[index + locationIndex]
|
|
865
|
-
locationStart = location.start || region.start
|
|
866
|
-
locationEnd = location.end || region.end
|
|
867
|
-
if (location.refName !== region.refName) {
|
|
868
|
-
throw new Error(
|
|
869
|
-
`Entered location ${assembleLocString(
|
|
870
|
-
location,
|
|
871
|
-
)} does not match with displayed regions`,
|
|
872
|
-
)
|
|
873
|
-
}
|
|
874
|
-
}
|
|
875
|
-
locationIndex -= 1
|
|
876
|
-
const startDisplayedRegion = self.displayedRegions[index]
|
|
877
|
-
const endDisplayedRegion =
|
|
878
|
-
self.displayedRegions[index + locationIndex]
|
|
879
|
-
this.moveTo(
|
|
880
|
-
{
|
|
881
|
-
index,
|
|
882
|
-
offset: startDisplayedRegion.reversed
|
|
883
|
-
? startDisplayedRegion.end - e
|
|
884
|
-
: s - startDisplayedRegion.start,
|
|
885
|
-
},
|
|
886
|
-
{
|
|
887
|
-
index: index + locationIndex,
|
|
888
|
-
offset: endDisplayedRegion.reversed
|
|
889
|
-
? endDisplayedRegion.end - locationStart
|
|
890
|
-
: locationEnd - endDisplayedRegion.start,
|
|
891
|
-
},
|
|
892
|
-
)
|
|
893
|
-
return
|
|
894
|
-
} catch (error) {
|
|
895
|
-
if (index === lastIndex) {
|
|
896
|
-
throw error
|
|
897
|
-
}
|
|
898
|
-
}
|
|
899
|
-
}
|
|
900
|
-
},
|
|
901
|
-
|
|
902
|
-
/**
|
|
903
|
-
* Navigate to a location based on user clicking and dragging on the
|
|
904
|
-
* overview scale bar to select a region to zoom into.
|
|
905
|
-
* Can handle if there are multiple displayedRegions from same refName.
|
|
906
|
-
* Only navigates to a location if it is entirely within a displayedRegion.
|
|
907
|
-
*
|
|
908
|
-
* @param leftPx- `object as {start, end, index, offset}`, offset = start of user drag
|
|
909
|
-
* @param rightPx- `object as {start, end, index, offset}`, offset = end of user drag
|
|
910
|
-
*/
|
|
911
|
-
zoomToDisplayedRegions(leftPx: BpOffset, rightPx: BpOffset) {
|
|
912
|
-
if (leftPx === undefined || rightPx === undefined) {
|
|
913
|
-
return
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
const singleRefSeq =
|
|
917
|
-
leftPx.refName === rightPx.refName && leftPx.index === rightPx.index
|
|
918
|
-
// zooming into one displayed Region
|
|
919
|
-
if (
|
|
920
|
-
(singleRefSeq && rightPx.offset < leftPx.offset) ||
|
|
921
|
-
leftPx.index > rightPx.index
|
|
922
|
-
) {
|
|
923
|
-
;[leftPx, rightPx] = [rightPx, leftPx]
|
|
924
|
-
}
|
|
925
|
-
const startOffset = {
|
|
926
|
-
start: leftPx.start,
|
|
927
|
-
end: leftPx.end,
|
|
928
|
-
index: leftPx.index,
|
|
929
|
-
offset: leftPx.offset,
|
|
930
|
-
}
|
|
931
|
-
const endOffset = {
|
|
932
|
-
start: rightPx.start,
|
|
933
|
-
end: rightPx.end,
|
|
934
|
-
index: rightPx.index,
|
|
935
|
-
offset: rightPx.offset,
|
|
936
|
-
}
|
|
937
|
-
if (startOffset && endOffset) {
|
|
938
|
-
this.moveTo(startOffset, endOffset)
|
|
939
|
-
} else {
|
|
940
|
-
const session = getSession(self)
|
|
941
|
-
session.notify('No regions found to navigate to', 'warning')
|
|
942
|
-
}
|
|
943
|
-
},
|
|
944
|
-
/**
|
|
945
|
-
* Helper method for the fetchSequence.
|
|
946
|
-
* Retrieves the corresponding regions that were selected by the rubberband
|
|
947
|
-
*
|
|
948
|
-
* @param leftOffset - `object as {start, end, index, offset}`, offset = start of user drag
|
|
949
|
-
* @param rightOffset - `object as {start, end, index, offset}`, offset = end of user drag
|
|
950
|
-
* @returns array of Region[]
|
|
951
|
-
*/
|
|
952
|
-
getSelectedRegions(
|
|
953
|
-
leftOffset: BpOffset | undefined,
|
|
954
|
-
rightOffset: BpOffset | undefined,
|
|
955
|
-
) {
|
|
956
|
-
const simView = Base1DView.create({
|
|
957
|
-
...getSnapshot(self),
|
|
958
|
-
interRegionPaddingWidth: self.interRegionPaddingWidth,
|
|
959
|
-
})
|
|
960
|
-
|
|
961
|
-
simView.setVolatileWidth(self.width)
|
|
962
|
-
simView.zoomToDisplayedRegions(leftOffset, rightOffset)
|
|
963
|
-
|
|
964
|
-
return simView.dynamicBlocks.contentBlocks.map(region => {
|
|
965
|
-
return {
|
|
966
|
-
...region,
|
|
967
|
-
start: Math.floor(region.start),
|
|
968
|
-
end: Math.ceil(region.end),
|
|
969
|
-
}
|
|
970
|
-
})
|
|
971
|
-
},
|
|
972
|
-
|
|
973
|
-
// schedule something to be run after the next time displayedRegions is set
|
|
974
|
-
afterDisplayedRegionsSet(cb: Function) {
|
|
975
|
-
self.afterDisplayedRegionsSetCallbacks.push(cb)
|
|
976
|
-
},
|
|
977
|
-
/**
|
|
978
|
-
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
979
|
-
* displayed region in the linear genome view
|
|
980
|
-
*
|
|
981
|
-
* @param start - object as `{start, end, offset, index}`
|
|
982
|
-
* @param end - object as `{start, end, offset, index}`
|
|
983
|
-
*/
|
|
984
|
-
moveTo(start: BpOffset, end: BpOffset) {
|
|
985
|
-
// find locations in the modellist
|
|
986
|
-
let bpSoFar = 0
|
|
987
|
-
|
|
988
|
-
if (start.index === end.index) {
|
|
989
|
-
bpSoFar += end.offset - start.offset
|
|
990
|
-
} else {
|
|
991
|
-
const s = self.displayedRegions[start.index]
|
|
992
|
-
bpSoFar += s.end - s.start - start.offset
|
|
993
|
-
if (end.index - start.index >= 2) {
|
|
994
|
-
for (let i = start.index + 1; i < end.index; i += 1) {
|
|
995
|
-
bpSoFar +=
|
|
996
|
-
self.displayedRegions[i].end - self.displayedRegions[i].start
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
bpSoFar += end.offset
|
|
1000
|
-
}
|
|
1001
|
-
const targetBpPerPx =
|
|
1002
|
-
bpSoFar /
|
|
1003
|
-
(self.width -
|
|
1004
|
-
self.interRegionPaddingWidth * (end.index - start.index))
|
|
1005
|
-
const newBpPerPx = self.zoomTo(targetBpPerPx)
|
|
1006
|
-
// If our target bpPerPx was smaller than the allowed minBpPerPx, adjust
|
|
1007
|
-
// the scroll so the requested range is in the middle of the screen
|
|
1008
|
-
let extraBp = 0
|
|
1009
|
-
if (targetBpPerPx < newBpPerPx) {
|
|
1010
|
-
extraBp = ((newBpPerPx - targetBpPerPx) * self.width) / 2
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
let bpToStart = -extraBp
|
|
1014
|
-
for (let i = 0; i < self.displayedRegions.length; i += 1) {
|
|
1015
|
-
const region = self.displayedRegions[i]
|
|
1016
|
-
if (start.index === i) {
|
|
1017
|
-
bpToStart += start.offset
|
|
1018
|
-
break
|
|
1019
|
-
} else {
|
|
1020
|
-
bpToStart += region.end - region.start
|
|
1021
|
-
}
|
|
1022
|
-
}
|
|
1023
|
-
self.scrollTo(
|
|
1024
|
-
Math.round(bpToStart / self.bpPerPx) +
|
|
1025
|
-
self.interRegionPaddingWidth * start.index,
|
|
1026
|
-
)
|
|
1027
|
-
},
|
|
1028
|
-
|
|
1029
|
-
horizontalScroll(distance: number) {
|
|
1030
|
-
const oldOffsetPx = self.offsetPx
|
|
1031
|
-
// newOffsetPx is the actual offset after the scroll is clamped
|
|
1032
|
-
const newOffsetPx = self.scrollTo(self.offsetPx + distance)
|
|
1033
|
-
return newOffsetPx - oldOffsetPx
|
|
1034
|
-
},
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* scrolls the view to center on the given bp. if that is not in any
|
|
1038
|
-
* of the displayed regions, does nothing
|
|
1039
|
-
* @param bp - basepair at which you want to center the view
|
|
1040
|
-
* @param refName - refName of the displayedRegion you are centering at
|
|
1041
|
-
* @param regionIndex - index of the displayedRegion
|
|
1042
|
-
*/
|
|
1043
|
-
centerAt(bp: number, refName: string, regionIndex: number) {
|
|
1044
|
-
const centerPx = self.bpToPx({
|
|
1045
|
-
refName,
|
|
1046
|
-
coord: bp,
|
|
1047
|
-
regionNumber: regionIndex,
|
|
1048
|
-
})
|
|
1049
|
-
if (centerPx) {
|
|
1050
|
-
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2))
|
|
1051
|
-
}
|
|
1052
|
-
},
|
|
1053
|
-
|
|
1054
|
-
center() {
|
|
1055
|
-
const centerBp = self.totalBp / 2
|
|
1056
|
-
self.scrollTo(Math.round(centerBp / self.bpPerPx - self.width / 2))
|
|
1057
|
-
},
|
|
1058
|
-
|
|
1059
|
-
showAllRegions() {
|
|
1060
|
-
self.zoomTo(self.maxBpPerPx)
|
|
1061
|
-
this.center()
|
|
1062
|
-
},
|
|
1063
|
-
|
|
1064
|
-
showAllRegionsInAssembly(assemblyName?: string) {
|
|
1065
|
-
const session = getSession(self)
|
|
1066
|
-
const { assemblyManager } = session
|
|
1067
|
-
if (!assemblyName) {
|
|
1068
|
-
const assemblyNames = [
|
|
1069
|
-
...new Set(
|
|
1070
|
-
self.displayedRegions.map(region => region.assemblyName),
|
|
1071
|
-
),
|
|
1072
|
-
]
|
|
1073
|
-
if (assemblyNames.length > 1) {
|
|
1074
|
-
session.notify(
|
|
1075
|
-
`Can't perform this with multiple assemblies currently`,
|
|
1076
|
-
)
|
|
1077
|
-
return
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
;[assemblyName] = assemblyNames
|
|
1081
|
-
}
|
|
1082
|
-
const assembly = assemblyManager.get(assemblyName)
|
|
1083
|
-
if (assembly) {
|
|
1084
|
-
const { regions } = assembly
|
|
1085
|
-
if (regions) {
|
|
1086
|
-
this.setDisplayedRegions(regions)
|
|
1087
|
-
self.zoomTo(self.maxBpPerPx)
|
|
1088
|
-
this.center()
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
},
|
|
629
|
+
},
|
|
1092
630
|
|
|
1093
631
|
setDraggingTrackId(idx?: string) {
|
|
1094
632
|
self.draggingTrackId = idx
|
|
@@ -1235,6 +773,13 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
1235
773
|
checked: !self.hideNoTracksActive,
|
|
1236
774
|
onClick: self.toggleNoTracksActive,
|
|
1237
775
|
},
|
|
776
|
+
{
|
|
777
|
+
label: 'Show gridlines',
|
|
778
|
+
icon: VisibilityIcon,
|
|
779
|
+
type: 'checkbox',
|
|
780
|
+
checked: self.showGridlines,
|
|
781
|
+
onClick: self.toggleShowGridlines,
|
|
782
|
+
},
|
|
1238
783
|
{
|
|
1239
784
|
label: 'Track labels',
|
|
1240
785
|
icon: LabelIcon,
|
|
@@ -1361,6 +906,249 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
1361
906
|
const blob = new Blob([html], { type: 'image/svg+xml' })
|
|
1362
907
|
saveAs(blob, opts.filename || 'image.svg')
|
|
1363
908
|
},
|
|
909
|
+
/**
|
|
910
|
+
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
911
|
+
* displayed region in the linear genome view
|
|
912
|
+
*
|
|
913
|
+
* @param start - object as `{start, end, offset, index}`
|
|
914
|
+
* @param end - object as `{start, end, offset, index}`
|
|
915
|
+
*/
|
|
916
|
+
moveTo(start?: BpOffset, end?: BpOffset) {
|
|
917
|
+
moveTo(self, start, end)
|
|
918
|
+
},
|
|
919
|
+
|
|
920
|
+
navToLocString(locString: string, optAssemblyName?: string) {
|
|
921
|
+
const { assemblyNames } = self
|
|
922
|
+
const { assemblyManager } = getSession(self)
|
|
923
|
+
const { isValidRefName } = assemblyManager
|
|
924
|
+
const assemblyName = optAssemblyName || assemblyNames[0]
|
|
925
|
+
let parsedLocStrings
|
|
926
|
+
const inputs = locString
|
|
927
|
+
.split(/(\s+)/)
|
|
928
|
+
.map(f => f.trim())
|
|
929
|
+
.filter(f => !!f)
|
|
930
|
+
|
|
931
|
+
// first try interpreting as a whitespace-separated sequence of
|
|
932
|
+
// multiple locstrings
|
|
933
|
+
try {
|
|
934
|
+
parsedLocStrings = inputs.map(l =>
|
|
935
|
+
parseLocString(l, ref => isValidRefName(ref, assemblyName)),
|
|
936
|
+
)
|
|
937
|
+
} catch (e) {
|
|
938
|
+
// if this fails, try interpreting as a whitespace-separated refname,
|
|
939
|
+
// start, end if start and end are integer inputs
|
|
940
|
+
const [refName, start, end] = inputs
|
|
941
|
+
if (
|
|
942
|
+
`${e}`.match(/Unknown reference sequence/) &&
|
|
943
|
+
Number.isInteger(+start) &&
|
|
944
|
+
Number.isInteger(+end)
|
|
945
|
+
) {
|
|
946
|
+
parsedLocStrings = [
|
|
947
|
+
parseLocString(refName + ':' + start + '..' + end, ref =>
|
|
948
|
+
isValidRefName(ref, assemblyName),
|
|
949
|
+
),
|
|
950
|
+
]
|
|
951
|
+
} else {
|
|
952
|
+
throw e
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
const locations = parsedLocStrings?.map(region => {
|
|
957
|
+
const asmName = region.assemblyName || assemblyName
|
|
958
|
+
const asm = assemblyManager.get(asmName)
|
|
959
|
+
const { refName } = region
|
|
960
|
+
if (!asm) {
|
|
961
|
+
throw new Error(`assembly ${asmName} not found`)
|
|
962
|
+
}
|
|
963
|
+
const { regions } = asm
|
|
964
|
+
if (!regions) {
|
|
965
|
+
throw new Error(`regions not loaded yet for ${asmName}`)
|
|
966
|
+
}
|
|
967
|
+
const canonicalRefName = asm.getCanonicalRefName(region.refName)
|
|
968
|
+
if (!canonicalRefName) {
|
|
969
|
+
throw new Error(`Could not find refName ${refName} in ${asm.name}`)
|
|
970
|
+
}
|
|
971
|
+
const parentRegion = regions.find(
|
|
972
|
+
region => region.refName === canonicalRefName,
|
|
973
|
+
)
|
|
974
|
+
if (!parentRegion) {
|
|
975
|
+
throw new Error(`Could not find refName ${refName} in ${asmName}`)
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
return {
|
|
979
|
+
...region,
|
|
980
|
+
assemblyName: asmName,
|
|
981
|
+
parentRegion,
|
|
982
|
+
}
|
|
983
|
+
})
|
|
984
|
+
|
|
985
|
+
if (locations.length === 1) {
|
|
986
|
+
const loc = locations[0]
|
|
987
|
+
self.setDisplayedRegions([
|
|
988
|
+
{ reversed: loc.reversed, ...loc.parentRegion },
|
|
989
|
+
])
|
|
990
|
+
const { start, end, parentRegion } = loc
|
|
991
|
+
|
|
992
|
+
this.navTo({
|
|
993
|
+
...loc,
|
|
994
|
+
start: clamp(start ?? 0, 0, parentRegion.end),
|
|
995
|
+
end: clamp(end ?? parentRegion.end, 0, parentRegion.end),
|
|
996
|
+
})
|
|
997
|
+
} else {
|
|
998
|
+
self.setDisplayedRegions(
|
|
999
|
+
// @ts-ignore
|
|
1000
|
+
locations.map(r => (r.start === undefined ? r.parentRegion : r)),
|
|
1001
|
+
)
|
|
1002
|
+
self.showAllRegions()
|
|
1003
|
+
}
|
|
1004
|
+
},
|
|
1005
|
+
|
|
1006
|
+
/**
|
|
1007
|
+
* Navigate to a location based on its refName and optionally start, end,
|
|
1008
|
+
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
1009
|
+
* from same refName. Only navigates to a location if it is entirely
|
|
1010
|
+
* within a displayedRegion. Navigates to the first matching location
|
|
1011
|
+
* encountered.
|
|
1012
|
+
*
|
|
1013
|
+
* Throws an error if navigation was unsuccessful
|
|
1014
|
+
*
|
|
1015
|
+
* @param location - a proposed location to navigate to
|
|
1016
|
+
*/
|
|
1017
|
+
navTo(query: NavLocation) {
|
|
1018
|
+
this.navToMultiple([query])
|
|
1019
|
+
},
|
|
1020
|
+
|
|
1021
|
+
navToMultiple(locations: NavLocation[]) {
|
|
1022
|
+
const firstLocation = locations[0]
|
|
1023
|
+
let { refName } = firstLocation
|
|
1024
|
+
const {
|
|
1025
|
+
start,
|
|
1026
|
+
end,
|
|
1027
|
+
assemblyName = self.assemblyNames[0],
|
|
1028
|
+
} = firstLocation
|
|
1029
|
+
|
|
1030
|
+
if (start !== undefined && end !== undefined && start > end) {
|
|
1031
|
+
throw new Error(`start "${start + 1}" is greater than end "${end}"`)
|
|
1032
|
+
}
|
|
1033
|
+
const session = getSession(self)
|
|
1034
|
+
const { assemblyManager } = session
|
|
1035
|
+
const assembly = assemblyManager.get(assemblyName)
|
|
1036
|
+
if (assembly) {
|
|
1037
|
+
const canonicalRefName = assembly.getCanonicalRefName(refName)
|
|
1038
|
+
if (canonicalRefName) {
|
|
1039
|
+
refName = canonicalRefName
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
let s = start
|
|
1043
|
+
let e = end
|
|
1044
|
+
let refNameMatched = false
|
|
1045
|
+
const predicate = (r: Region) => {
|
|
1046
|
+
if (refName === r.refName) {
|
|
1047
|
+
refNameMatched = true
|
|
1048
|
+
if (s === undefined) {
|
|
1049
|
+
s = r.start
|
|
1050
|
+
}
|
|
1051
|
+
if (e === undefined) {
|
|
1052
|
+
e = r.end
|
|
1053
|
+
}
|
|
1054
|
+
if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
|
|
1055
|
+
return true
|
|
1056
|
+
}
|
|
1057
|
+
s = start
|
|
1058
|
+
e = end
|
|
1059
|
+
}
|
|
1060
|
+
return false
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
const lastIndex = findLastIndex(self.displayedRegions, predicate)
|
|
1064
|
+
let index
|
|
1065
|
+
while (index !== lastIndex) {
|
|
1066
|
+
try {
|
|
1067
|
+
const previousIndex: number | undefined = index
|
|
1068
|
+
index = self.displayedRegions
|
|
1069
|
+
.slice(previousIndex === undefined ? 0 : previousIndex + 1)
|
|
1070
|
+
.findIndex(predicate)
|
|
1071
|
+
if (previousIndex !== undefined) {
|
|
1072
|
+
index += previousIndex + 1
|
|
1073
|
+
}
|
|
1074
|
+
if (!refNameMatched) {
|
|
1075
|
+
throw new Error(
|
|
1076
|
+
`could not find a region with refName "${refName}"`,
|
|
1077
|
+
)
|
|
1078
|
+
}
|
|
1079
|
+
if (s === undefined) {
|
|
1080
|
+
throw new Error(
|
|
1081
|
+
`could not find a region with refName "${refName}" that contained an end position ${e}`,
|
|
1082
|
+
)
|
|
1083
|
+
}
|
|
1084
|
+
if (e === undefined) {
|
|
1085
|
+
throw new Error(
|
|
1086
|
+
`could not find a region with refName "${refName}" that contained a start position ${
|
|
1087
|
+
s + 1
|
|
1088
|
+
}`,
|
|
1089
|
+
)
|
|
1090
|
+
}
|
|
1091
|
+
if (index === -1) {
|
|
1092
|
+
throw new Error(
|
|
1093
|
+
`could not find a region that completely contained "${assembleLocString(
|
|
1094
|
+
firstLocation,
|
|
1095
|
+
)}"`,
|
|
1096
|
+
)
|
|
1097
|
+
}
|
|
1098
|
+
if (locations.length === 1) {
|
|
1099
|
+
const f = self.displayedRegions[index]
|
|
1100
|
+
this.moveTo(
|
|
1101
|
+
{ index, offset: f.reversed ? f.end - e : s - f.start },
|
|
1102
|
+
{ index, offset: f.reversed ? f.end - s : e - f.start },
|
|
1103
|
+
)
|
|
1104
|
+
return
|
|
1105
|
+
}
|
|
1106
|
+
let locationIndex = 0
|
|
1107
|
+
let locationStart = 0
|
|
1108
|
+
let locationEnd = 0
|
|
1109
|
+
for (
|
|
1110
|
+
locationIndex;
|
|
1111
|
+
locationIndex < locations.length;
|
|
1112
|
+
locationIndex++
|
|
1113
|
+
) {
|
|
1114
|
+
const location = locations[locationIndex]
|
|
1115
|
+
const region = self.displayedRegions[index + locationIndex]
|
|
1116
|
+
locationStart = location.start || region.start
|
|
1117
|
+
locationEnd = location.end || region.end
|
|
1118
|
+
if (location.refName !== region.refName) {
|
|
1119
|
+
throw new Error(
|
|
1120
|
+
`Entered location ${assembleLocString(
|
|
1121
|
+
location,
|
|
1122
|
+
)} does not match with displayed regions`,
|
|
1123
|
+
)
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
locationIndex -= 1
|
|
1127
|
+
const startDisplayedRegion = self.displayedRegions[index]
|
|
1128
|
+
const endDisplayedRegion =
|
|
1129
|
+
self.displayedRegions[index + locationIndex]
|
|
1130
|
+
this.moveTo(
|
|
1131
|
+
{
|
|
1132
|
+
index,
|
|
1133
|
+
offset: startDisplayedRegion.reversed
|
|
1134
|
+
? startDisplayedRegion.end - e
|
|
1135
|
+
: s - startDisplayedRegion.start,
|
|
1136
|
+
},
|
|
1137
|
+
{
|
|
1138
|
+
index: index + locationIndex,
|
|
1139
|
+
offset: endDisplayedRegion.reversed
|
|
1140
|
+
? endDisplayedRegion.end - locationStart
|
|
1141
|
+
: locationEnd - endDisplayedRegion.start,
|
|
1142
|
+
},
|
|
1143
|
+
)
|
|
1144
|
+
return
|
|
1145
|
+
} catch (error) {
|
|
1146
|
+
if (index === lastIndex) {
|
|
1147
|
+
throw error
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
},
|
|
1364
1152
|
}))
|
|
1365
1153
|
.views(self => ({
|
|
1366
1154
|
rubberBandMenuItems(): MenuItem[] {
|
|
@@ -1370,9 +1158,7 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
1370
1158
|
icon: ZoomInIcon,
|
|
1371
1159
|
onClick: () => {
|
|
1372
1160
|
const { leftOffset, rightOffset } = self
|
|
1373
|
-
|
|
1374
|
-
self.moveTo(leftOffset, rightOffset)
|
|
1375
|
-
}
|
|
1161
|
+
self.moveTo(leftOffset, rightOffset)
|
|
1376
1162
|
},
|
|
1377
1163
|
},
|
|
1378
1164
|
{
|
|
@@ -1384,6 +1170,46 @@ export function stateModelFactory(pluginManager: PluginManager) {
|
|
|
1384
1170
|
},
|
|
1385
1171
|
]
|
|
1386
1172
|
},
|
|
1173
|
+
|
|
1174
|
+
bpToPx({
|
|
1175
|
+
refName,
|
|
1176
|
+
coord,
|
|
1177
|
+
regionNumber,
|
|
1178
|
+
}: {
|
|
1179
|
+
refName: string
|
|
1180
|
+
coord: number
|
|
1181
|
+
regionNumber?: number
|
|
1182
|
+
}) {
|
|
1183
|
+
return bpToPx({ refName, coord, regionNumber, self })
|
|
1184
|
+
},
|
|
1185
|
+
|
|
1186
|
+
/**
|
|
1187
|
+
* scrolls the view to center on the given bp. if that is not in any
|
|
1188
|
+
* of the displayed regions, does nothing
|
|
1189
|
+
* @param coord - basepair at which you want to center the view
|
|
1190
|
+
* @param refName - refName of the displayedRegion you are centering at
|
|
1191
|
+
* @param regionNumber - index of the displayedRegion
|
|
1192
|
+
*/
|
|
1193
|
+
centerAt(coord: number, refName: string, regionNumber: number) {
|
|
1194
|
+
const centerPx = this.bpToPx({
|
|
1195
|
+
refName,
|
|
1196
|
+
coord,
|
|
1197
|
+
regionNumber,
|
|
1198
|
+
})
|
|
1199
|
+
if (centerPx) {
|
|
1200
|
+
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2))
|
|
1201
|
+
}
|
|
1202
|
+
},
|
|
1203
|
+
|
|
1204
|
+
pxToBp(px: number) {
|
|
1205
|
+
return pxToBp(self, px)
|
|
1206
|
+
},
|
|
1207
|
+
|
|
1208
|
+
get centerLineInfo() {
|
|
1209
|
+
return self.displayedRegions.length
|
|
1210
|
+
? this.pxToBp(self.width / 2)
|
|
1211
|
+
: undefined
|
|
1212
|
+
},
|
|
1387
1213
|
}))
|
|
1388
1214
|
}
|
|
1389
1215
|
|