@jbrowse/plugin-linear-genome-view 2.2.1 → 2.3.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.d.ts +2 -1
- package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js +4 -2
- package/dist/BaseLinearDisplay/components/BaseLinearDisplay.js.map +1 -1
- package/dist/BaseLinearDisplay/components/Block.d.ts +1 -1
- package/dist/BaseLinearDisplay/components/Block.js +1 -1
- package/dist/BaseLinearDisplay/components/Block.js.map +1 -1
- package/dist/BaseLinearDisplay/components/BlockMsg.js +3 -2
- package/dist/BaseLinearDisplay/components/BlockMsg.js.map +1 -1
- package/dist/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -1
- package/dist/BaseLinearDisplay/components/LinearBlocks.js +2 -2
- package/dist/BaseLinearDisplay/components/LinearBlocks.js.map +1 -1
- package/dist/BaseLinearDisplay/{models → components}/TooLargeMessage.d.ts +0 -0
- package/dist/BaseLinearDisplay/{models → components}/TooLargeMessage.js +0 -0
- package/dist/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -0
- package/dist/BaseLinearDisplay/index.d.ts +2 -2
- package/dist/BaseLinearDisplay/index.js +4 -3
- package/dist/BaseLinearDisplay/index.js.map +1 -1
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +6 -14
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js +3 -5
- package/dist/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/dist/BaseLinearDisplay/models/configSchema.d.ts +2 -0
- package/dist/BaseLinearDisplay/models/{baseLinearDisplayConfigSchema.js → configSchema.js} +5 -5
- package/dist/BaseLinearDisplay/models/configSchema.js.map +1 -0
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js +1 -1
- package/dist/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
- package/dist/BaseLinearDisplay/models/util.d.ts +18 -0
- package/dist/BaseLinearDisplay/models/util.js +18 -0
- package/dist/BaseLinearDisplay/models/util.js.map +1 -0
- package/dist/FeatureTrack/index.d.ts +1 -1
- package/dist/FeatureTrack/index.js +5 -4
- package/dist/FeatureTrack/index.js.map +1 -1
- package/dist/LaunchLinearGenomeView/index.d.ts +3 -0
- package/dist/LaunchLinearGenomeView/index.js +44 -0
- package/dist/LaunchLinearGenomeView/index.js.map +1 -0
- package/dist/LinearBareDisplay/index.d.ts +6 -2
- package/dist/LinearBareDisplay/index.js +18 -2
- package/dist/LinearBareDisplay/index.js.map +1 -1
- package/dist/LinearBareDisplay/model.d.ts +1 -1
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js +2 -15
- package/dist/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
- package/dist/LinearBasicDisplay/index.d.ts +6 -2
- package/dist/LinearBasicDisplay/index.js +21 -4
- package/dist/LinearBasicDisplay/index.js.map +1 -1
- package/dist/LinearBasicDisplay/model.d.ts +17 -13
- package/dist/LinearBasicDisplay/model.js +2 -1
- package/dist/LinearBasicDisplay/model.js.map +1 -1
- package/dist/LinearGenomeView/components/ExportSvgDialog.js +1 -19
- package/dist/LinearGenomeView/components/ExportSvgDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/GetSequenceDialog.js +7 -18
- package/dist/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/Header.js +2 -2
- package/dist/LinearGenomeView/components/HelpDialog.js +2 -17
- package/dist/LinearGenomeView/components/HelpDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/ImportForm.js +15 -10
- package/dist/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js +6 -7
- package/dist/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/{esm/LinearGenomeView/components/OverviewRubberBand.d.ts → dist/LinearGenomeView/components/OverviewRubberband.d.ts} +2 -2
- package/dist/LinearGenomeView/components/{OverviewRubberBand.js → OverviewRubberband.js} +27 -79
- package/dist/LinearGenomeView/components/OverviewRubberband.js.map +1 -0
- package/dist/LinearGenomeView/components/{OverviewScaleBar.d.ts → OverviewScalebar.d.ts} +2 -2
- package/dist/LinearGenomeView/components/{OverviewScaleBar.js → OverviewScalebar.js} +25 -24
- package/dist/LinearGenomeView/components/OverviewScalebar.js.map +1 -0
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js +1 -1
- package/dist/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
- package/dist/LinearGenomeView/components/{RubberBand.d.ts → Rubberband.d.ts} +2 -2
- package/dist/LinearGenomeView/components/Rubberband.js +57 -0
- package/dist/LinearGenomeView/components/Rubberband.js.map +1 -0
- package/dist/LinearGenomeView/components/RubberbandSpan.d.ts +14 -0
- package/dist/LinearGenomeView/components/RubberbandSpan.js +90 -0
- package/dist/LinearGenomeView/components/RubberbandSpan.js.map +1 -0
- package/dist/LinearGenomeView/components/Ruler.d.ts +2 -18
- package/dist/LinearGenomeView/components/Ruler.js +9 -25
- package/dist/LinearGenomeView/components/Ruler.js.map +1 -1
- package/dist/LinearGenomeView/components/{ScaleBar.d.ts → Scalebar.d.ts} +2 -2
- package/dist/LinearGenomeView/components/{ScaleBar.js → Scalebar.js} +11 -11
- package/dist/LinearGenomeView/components/{ScaleBar.js.map → Scalebar.js.map} +1 -1
- package/dist/LinearGenomeView/components/SearchBox.js +10 -6
- package/dist/LinearGenomeView/components/SearchBox.js.map +1 -1
- package/dist/LinearGenomeView/components/SearchResultsDialog.js +17 -31
- package/dist/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/SequenceSearchDialog.js +4 -19
- package/dist/LinearGenomeView/components/SequenceSearchDialog.js.map +1 -1
- package/dist/LinearGenomeView/components/TrackContainer.js +2 -2
- package/dist/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/dist/LinearGenomeView/components/TracksContainer.js +21 -118
- package/dist/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/dist/LinearGenomeView/components/VerticalGuide.d.ts +9 -0
- package/dist/LinearGenomeView/components/VerticalGuide.js +29 -0
- package/dist/LinearGenomeView/components/VerticalGuide.js.map +1 -0
- package/dist/LinearGenomeView/components/hooks.d.ts +65 -0
- package/dist/LinearGenomeView/components/hooks.js +264 -0
- package/dist/LinearGenomeView/components/hooks.js.map +1 -0
- package/dist/LinearGenomeView/components/util.d.ts +5 -2
- package/dist/LinearGenomeView/components/util.js +7 -6
- package/dist/LinearGenomeView/components/util.js.map +1 -1
- package/dist/LinearGenomeView/index.d.ts +3 -534
- package/dist/LinearGenomeView/index.js +12 -1327
- package/dist/LinearGenomeView/index.js.map +1 -1
- package/dist/LinearGenomeView/model.d.ts +535 -0
- package/dist/LinearGenomeView/model.js +1357 -0
- package/dist/LinearGenomeView/model.js.map +1 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +12 -73
- package/dist/index.js.map +1 -1
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.d.ts +2 -1
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.js +3 -2
- package/esm/BaseLinearDisplay/components/BaseLinearDisplay.js.map +1 -1
- package/esm/BaseLinearDisplay/components/Block.d.ts +1 -1
- package/esm/BaseLinearDisplay/components/Block.js +1 -1
- package/esm/BaseLinearDisplay/components/Block.js.map +1 -1
- package/esm/BaseLinearDisplay/components/BlockMsg.js +3 -2
- package/esm/BaseLinearDisplay/components/BlockMsg.js.map +1 -1
- package/esm/BaseLinearDisplay/components/LinearBlocks.d.ts +1 -1
- package/esm/BaseLinearDisplay/components/LinearBlocks.js +2 -2
- package/esm/BaseLinearDisplay/components/LinearBlocks.js.map +1 -1
- package/esm/BaseLinearDisplay/{models → components}/TooLargeMessage.d.ts +0 -0
- package/esm/BaseLinearDisplay/{models → components}/TooLargeMessage.js +0 -0
- package/esm/BaseLinearDisplay/components/TooLargeMessage.js.map +1 -0
- package/esm/BaseLinearDisplay/index.d.ts +2 -2
- package/esm/BaseLinearDisplay/index.js +2 -2
- package/esm/BaseLinearDisplay/index.js.map +1 -1
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.d.ts +6 -14
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js +3 -5
- package/esm/BaseLinearDisplay/models/BaseLinearDisplayModel.js.map +1 -1
- package/esm/BaseLinearDisplay/models/configSchema.d.ts +2 -0
- package/esm/BaseLinearDisplay/models/{baseLinearDisplayConfigSchema.js → configSchema.js} +5 -4
- package/esm/BaseLinearDisplay/models/configSchema.js.map +1 -0
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js +1 -1
- package/esm/BaseLinearDisplay/models/serverSideRenderedBlock.js.map +1 -1
- package/esm/BaseLinearDisplay/models/util.d.ts +18 -0
- package/esm/BaseLinearDisplay/models/util.js +14 -0
- package/esm/BaseLinearDisplay/models/util.js.map +1 -0
- package/esm/FeatureTrack/index.d.ts +1 -1
- package/esm/FeatureTrack/index.js +5 -4
- package/esm/FeatureTrack/index.js.map +1 -1
- package/esm/LaunchLinearGenomeView/index.d.ts +3 -0
- package/esm/LaunchLinearGenomeView/index.js +42 -0
- package/esm/LaunchLinearGenomeView/index.js.map +1 -0
- package/esm/LinearBareDisplay/index.d.ts +6 -2
- package/esm/LinearBareDisplay/index.js +19 -2
- package/esm/LinearBareDisplay/index.js.map +1 -1
- package/esm/LinearBareDisplay/model.d.ts +1 -1
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js +3 -13
- package/esm/LinearBasicDisplay/components/SetMaxHeight.js.map +1 -1
- package/esm/LinearBasicDisplay/index.d.ts +6 -2
- package/esm/LinearBasicDisplay/index.js +20 -2
- package/esm/LinearBasicDisplay/index.js.map +1 -1
- package/esm/LinearBasicDisplay/model.d.ts +17 -13
- package/esm/LinearBasicDisplay/model.js +2 -1
- package/esm/LinearBasicDisplay/model.js.map +1 -1
- package/esm/LinearGenomeView/components/ExportSvgDialog.js +3 -18
- package/esm/LinearGenomeView/components/ExportSvgDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/GetSequenceDialog.js +8 -19
- package/esm/LinearGenomeView/components/GetSequenceDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/Header.js +2 -2
- package/esm/LinearGenomeView/components/HelpDialog.js +3 -18
- package/esm/LinearGenomeView/components/HelpDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/ImportForm.js +15 -10
- package/esm/LinearGenomeView/components/ImportForm.js.map +1 -1
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js +4 -5
- package/esm/LinearGenomeView/components/LinearGenomeViewSvg.js.map +1 -1
- package/{dist/LinearGenomeView/components/OverviewRubberBand.d.ts → esm/LinearGenomeView/components/OverviewRubberband.d.ts} +2 -2
- package/esm/LinearGenomeView/components/{OverviewRubberBand.js → OverviewRubberband.js} +25 -80
- package/esm/LinearGenomeView/components/OverviewRubberband.js.map +1 -0
- package/esm/LinearGenomeView/components/{OverviewScaleBar.d.ts → OverviewScalebar.d.ts} +2 -2
- package/esm/LinearGenomeView/components/{OverviewScaleBar.js → OverviewScalebar.js} +25 -24
- package/esm/LinearGenomeView/components/OverviewScalebar.js.map +1 -0
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js +1 -1
- package/esm/LinearGenomeView/components/RefNameAutocomplete.js.map +1 -1
- package/esm/LinearGenomeView/components/{RubberBand.d.ts → Rubberband.d.ts} +2 -2
- package/esm/LinearGenomeView/components/Rubberband.js +29 -0
- package/esm/LinearGenomeView/components/Rubberband.js.map +1 -0
- package/esm/LinearGenomeView/components/RubberbandSpan.d.ts +14 -0
- package/esm/LinearGenomeView/components/RubberbandSpan.js +65 -0
- package/esm/LinearGenomeView/components/RubberbandSpan.js.map +1 -0
- package/esm/LinearGenomeView/components/Ruler.d.ts +2 -18
- package/esm/LinearGenomeView/components/Ruler.js +6 -22
- package/esm/LinearGenomeView/components/Ruler.js.map +1 -1
- package/esm/LinearGenomeView/components/{ScaleBar.d.ts → Scalebar.d.ts} +2 -2
- package/esm/LinearGenomeView/components/{ScaleBar.js → Scalebar.js} +11 -11
- package/esm/LinearGenomeView/components/{ScaleBar.js.map → Scalebar.js.map} +1 -1
- package/esm/LinearGenomeView/components/SearchBox.js +10 -6
- package/esm/LinearGenomeView/components/SearchBox.js.map +1 -1
- package/esm/LinearGenomeView/components/SearchResultsDialog.js +18 -32
- package/esm/LinearGenomeView/components/SearchResultsDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/SequenceSearchDialog.js +5 -17
- package/esm/LinearGenomeView/components/SequenceSearchDialog.js.map +1 -1
- package/esm/LinearGenomeView/components/TrackContainer.js +2 -2
- package/esm/LinearGenomeView/components/TrackContainer.js.map +1 -1
- package/esm/LinearGenomeView/components/TracksContainer.js +22 -119
- package/esm/LinearGenomeView/components/TracksContainer.js.map +1 -1
- package/esm/LinearGenomeView/components/VerticalGuide.d.ts +9 -0
- package/esm/LinearGenomeView/components/VerticalGuide.js +24 -0
- package/esm/LinearGenomeView/components/VerticalGuide.js.map +1 -0
- package/esm/LinearGenomeView/components/hooks.d.ts +65 -0
- package/esm/LinearGenomeView/components/hooks.js +255 -0
- package/esm/LinearGenomeView/components/hooks.js.map +1 -0
- package/esm/LinearGenomeView/components/util.d.ts +5 -2
- package/esm/LinearGenomeView/components/util.js +4 -3
- package/esm/LinearGenomeView/components/util.js.map +1 -1
- package/esm/LinearGenomeView/index.d.ts +3 -534
- package/esm/LinearGenomeView/index.js +10 -1318
- package/esm/LinearGenomeView/index.js.map +1 -1
- package/esm/LinearGenomeView/model.d.ts +535 -0
- package/esm/LinearGenomeView/model.js +1322 -0
- package/esm/LinearGenomeView/model.js.map +1 -0
- package/esm/index.d.ts +6 -6
- package/esm/index.js +12 -74
- package/esm/index.js.map +1 -1
- package/package.json +5 -6
- package/src/BaseLinearDisplay/components/BaseLinearDisplay.tsx +86 -84
- package/src/BaseLinearDisplay/components/Block.tsx +15 -11
- package/src/BaseLinearDisplay/components/BlockMsg.tsx +9 -9
- package/src/BaseLinearDisplay/components/LinearBlocks.tsx +62 -58
- package/src/BaseLinearDisplay/{models → components}/TooLargeMessage.tsx +0 -0
- package/src/BaseLinearDisplay/index.ts +2 -1
- package/src/BaseLinearDisplay/models/BaseLinearDisplayModel.tsx +4 -3
- package/src/BaseLinearDisplay/models/{baseLinearDisplayConfigSchema.ts → configSchema.ts} +5 -3
- package/src/BaseLinearDisplay/models/serverSideRenderedBlock.ts +1 -1
- package/src/BaseLinearDisplay/models/util.ts +24 -0
- package/src/FeatureTrack/index.ts +5 -8
- package/src/LaunchLinearGenomeView/index.ts +66 -0
- package/src/LinearBareDisplay/index.ts +23 -2
- package/src/LinearBasicDisplay/components/SetMaxHeight.tsx +3 -28
- package/src/LinearBasicDisplay/index.ts +24 -2
- package/src/LinearBasicDisplay/model.ts +2 -1
- package/src/LinearGenomeView/README.md +2 -1
- package/src/LinearGenomeView/components/ExportSvgDialog.tsx +2 -23
- package/src/LinearGenomeView/components/GetSequenceDialog.tsx +13 -31
- package/src/LinearGenomeView/components/Header.tsx +3 -3
- package/src/LinearGenomeView/components/HelpDialog.tsx +8 -34
- package/src/LinearGenomeView/components/ImportForm.tsx +13 -9
- package/src/LinearGenomeView/components/LinearGenomeView.test.tsx +132 -134
- package/src/LinearGenomeView/components/LinearGenomeViewSvg.tsx +4 -5
- package/src/LinearGenomeView/components/{OverviewRubberBand.tsx → OverviewRubberband.tsx} +32 -114
- package/src/LinearGenomeView/components/{OverviewScaleBar.tsx → OverviewScalebar.tsx} +26 -25
- package/src/LinearGenomeView/components/RefNameAutocomplete.tsx +2 -1
- package/src/LinearGenomeView/components/Rubberband.tsx +89 -0
- package/src/LinearGenomeView/components/RubberbandSpan.tsx +116 -0
- package/src/LinearGenomeView/components/Ruler.tsx +11 -28
- package/src/LinearGenomeView/components/{ScaleBar.test.tsx → Scalebar.test.tsx} +5 -5
- package/src/LinearGenomeView/components/{ScaleBar.tsx → Scalebar.tsx} +11 -11
- package/src/LinearGenomeView/components/SearchBox.tsx +8 -6
- package/src/LinearGenomeView/components/SearchResultsDialog.tsx +17 -44
- package/src/LinearGenomeView/components/SequenceSearchDialog.tsx +4 -30
- package/src/LinearGenomeView/components/TrackContainer.tsx +4 -2
- package/src/LinearGenomeView/components/TracksContainer.tsx +59 -136
- package/src/LinearGenomeView/components/VerticalGuide.tsx +37 -0
- package/src/LinearGenomeView/components/__snapshots__/LinearGenomeView.test.tsx.snap +39 -44
- package/src/LinearGenomeView/components/hooks.ts +300 -0
- package/src/LinearGenomeView/components/util.ts +8 -11
- package/src/LinearGenomeView/index.test.ts +6 -7
- package/src/LinearGenomeView/index.ts +18 -0
- package/src/LinearGenomeView/{index.tsx → model.ts} +7 -4
- package/src/index.ts +16 -108
- package/dist/BaseLinearDisplay/models/TooLargeMessage.js.map +0 -1
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.d.ts +0 -1
- package/dist/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +0 -1
- package/dist/LinearGenomeView/components/OverviewRubberBand.js.map +0 -1
- package/dist/LinearGenomeView/components/OverviewScaleBar.js.map +0 -1
- package/dist/LinearGenomeView/components/RubberBand.js +0 -221
- package/dist/LinearGenomeView/components/RubberBand.js.map +0 -1
- package/esm/BaseLinearDisplay/models/TooLargeMessage.js.map +0 -1
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.d.ts +0 -1
- package/esm/BaseLinearDisplay/models/baseLinearDisplayConfigSchema.js.map +0 -1
- package/esm/LinearGenomeView/components/OverviewRubberBand.js.map +0 -1
- package/esm/LinearGenomeView/components/OverviewScaleBar.js.map +0 -1
- package/esm/LinearGenomeView/components/RubberBand.js +0 -196
- package/esm/LinearGenomeView/components/RubberBand.js.map +0 -1
- package/src/LinearGenomeView/components/RubberBand.tsx +0 -308
|
@@ -0,0 +1,1357 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
+
if (mod && mod.__esModule) return mod;
|
|
20
|
+
var result = {};
|
|
21
|
+
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
+
__setModuleDefault(result, mod);
|
|
23
|
+
return result;
|
|
24
|
+
};
|
|
25
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
26
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
exports.ReactComponent = exports.LinearGenomeView = exports.ZoomControls = exports.SearchBox = exports.RefNameAutocomplete = exports.renderToSvg = exports.stateModelFactory = exports.WIDGET_HEIGHT = exports.SPACING = exports.INTER_REGION_PADDING_WIDTH = exports.RESIZE_HANDLE_HEIGHT = exports.SCALE_BAR_HEIGHT = exports.HEADER_OVERVIEW_HEIGHT = exports.HEADER_BAR_HEIGHT = void 0;
|
|
30
|
+
const react_1 = require("react");
|
|
31
|
+
const configuration_1 = require("@jbrowse/core/configuration");
|
|
32
|
+
const models_1 = require("@jbrowse/core/pluggableElementTypes/models");
|
|
33
|
+
const mst_1 = require("@jbrowse/core/util/types/mst");
|
|
34
|
+
const ui_1 = require("@jbrowse/core/ui");
|
|
35
|
+
const util_1 = require("@jbrowse/core/util");
|
|
36
|
+
const calculateDynamicBlocks_1 = __importDefault(require("@jbrowse/core/util/calculateDynamicBlocks"));
|
|
37
|
+
const calculateStaticBlocks_1 = __importDefault(require("@jbrowse/core/util/calculateStaticBlocks"));
|
|
38
|
+
const tracks_1 = require("@jbrowse/core/util/tracks");
|
|
39
|
+
const mobx_1 = require("mobx");
|
|
40
|
+
const mobx_state_tree_1 = require("mobx-state-tree");
|
|
41
|
+
const Base1DViewModel_1 = __importDefault(require("@jbrowse/core/util/Base1DViewModel"));
|
|
42
|
+
const Base1DUtils_1 = require("@jbrowse/core/util/Base1DUtils");
|
|
43
|
+
const file_saver_1 = require("file-saver");
|
|
44
|
+
const clone_1 = __importDefault(require("clone"));
|
|
45
|
+
// icons
|
|
46
|
+
const Icons_1 = require("@jbrowse/core/ui/Icons");
|
|
47
|
+
const SyncAlt_1 = __importDefault(require("@mui/icons-material/SyncAlt"));
|
|
48
|
+
const Visibility_1 = __importDefault(require("@mui/icons-material/Visibility"));
|
|
49
|
+
const Label_1 = __importDefault(require("@mui/icons-material/Label"));
|
|
50
|
+
const FolderOpen_1 = __importDefault(require("@mui/icons-material/FolderOpen"));
|
|
51
|
+
const PhotoCamera_1 = __importDefault(require("@mui/icons-material/PhotoCamera"));
|
|
52
|
+
const ZoomIn_1 = __importDefault(require("@mui/icons-material/ZoomIn"));
|
|
53
|
+
const MenuOpen_1 = __importDefault(require("@mui/icons-material/MenuOpen"));
|
|
54
|
+
// locals
|
|
55
|
+
const LinearGenomeViewSvg_1 = require("./components/LinearGenomeViewSvg");
|
|
56
|
+
Object.defineProperty(exports, "renderToSvg", { enumerable: true, get: function () { return LinearGenomeViewSvg_1.renderToSvg; } });
|
|
57
|
+
const RefNameAutocomplete_1 = __importDefault(require("./components/RefNameAutocomplete"));
|
|
58
|
+
exports.RefNameAutocomplete = RefNameAutocomplete_1.default;
|
|
59
|
+
const SearchBox_1 = __importDefault(require("./components/SearchBox"));
|
|
60
|
+
exports.SearchBox = SearchBox_1.default;
|
|
61
|
+
const ExportSvgDialog_1 = __importDefault(require("./components/ExportSvgDialog"));
|
|
62
|
+
const MiniControls_1 = __importDefault(require("./components/MiniControls"));
|
|
63
|
+
const Header_1 = __importDefault(require("./components/Header"));
|
|
64
|
+
const ZoomControls_1 = __importDefault(require("./components/ZoomControls"));
|
|
65
|
+
exports.ZoomControls = ZoomControls_1.default;
|
|
66
|
+
const LinearGenomeView_1 = __importDefault(require("./components/LinearGenomeView"));
|
|
67
|
+
exports.LinearGenomeView = LinearGenomeView_1.default;
|
|
68
|
+
// lazies
|
|
69
|
+
const SequenceSearchDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SequenceSearchDialog'))));
|
|
70
|
+
function calculateVisibleLocStrings(contentBlocks) {
|
|
71
|
+
if (!contentBlocks.length) {
|
|
72
|
+
return '';
|
|
73
|
+
}
|
|
74
|
+
const isSingleAssemblyName = contentBlocks.every(b => b.assemblyName === contentBlocks[0].assemblyName);
|
|
75
|
+
const locs = contentBlocks.map(block => (0, util_1.assembleLocString)({
|
|
76
|
+
...block,
|
|
77
|
+
start: Math.round(block.start),
|
|
78
|
+
end: Math.round(block.end),
|
|
79
|
+
assemblyName: isSingleAssemblyName ? undefined : block.assemblyName,
|
|
80
|
+
}));
|
|
81
|
+
return locs.join(' ');
|
|
82
|
+
}
|
|
83
|
+
exports.HEADER_BAR_HEIGHT = 48;
|
|
84
|
+
exports.HEADER_OVERVIEW_HEIGHT = 20;
|
|
85
|
+
exports.SCALE_BAR_HEIGHT = 17;
|
|
86
|
+
exports.RESIZE_HANDLE_HEIGHT = 3;
|
|
87
|
+
exports.INTER_REGION_PADDING_WIDTH = 2;
|
|
88
|
+
exports.SPACING = 7;
|
|
89
|
+
exports.WIDGET_HEIGHT = 32;
|
|
90
|
+
function localStorageGetItem(item) {
|
|
91
|
+
return typeof localStorage !== 'undefined'
|
|
92
|
+
? localStorage.getItem(item)
|
|
93
|
+
: undefined;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* #stateModel LinearGenomeView
|
|
97
|
+
*/
|
|
98
|
+
function stateModelFactory(pluginManager) {
|
|
99
|
+
return mobx_state_tree_1.types
|
|
100
|
+
.compose(models_1.BaseViewModel, mobx_state_tree_1.types.model('LinearGenomeView', {
|
|
101
|
+
/**
|
|
102
|
+
* #property
|
|
103
|
+
*/
|
|
104
|
+
id: mst_1.ElementId,
|
|
105
|
+
/**
|
|
106
|
+
* #property
|
|
107
|
+
* this is a string instead of the const literal 'LinearGenomeView' to reduce some
|
|
108
|
+
* typescripting strictness, but you should pass the string 'LinearGenomeView' to
|
|
109
|
+
* the model explicitly
|
|
110
|
+
*/
|
|
111
|
+
type: mobx_state_tree_1.types.literal('LinearGenomeView'),
|
|
112
|
+
/**
|
|
113
|
+
* #property
|
|
114
|
+
* corresponds roughly to the horizontal scroll of the LGV
|
|
115
|
+
*/
|
|
116
|
+
offsetPx: 0,
|
|
117
|
+
/**
|
|
118
|
+
* #property
|
|
119
|
+
* corresponds roughly to the zoom level, base-pairs per pixel
|
|
120
|
+
*/
|
|
121
|
+
bpPerPx: 1,
|
|
122
|
+
/**
|
|
123
|
+
* #property
|
|
124
|
+
* currently displayed regions, can be a single chromosome, arbitrary subsections,
|
|
125
|
+
* or the entire set of chromosomes in the genome, but it not advised to use the
|
|
126
|
+
* entire set of chromosomes if your assembly is very fragmented
|
|
127
|
+
*/
|
|
128
|
+
displayedRegions: mobx_state_tree_1.types.array(mst_1.Region),
|
|
129
|
+
/**
|
|
130
|
+
* #property
|
|
131
|
+
* array of currently displayed tracks state models instances
|
|
132
|
+
*/
|
|
133
|
+
tracks: mobx_state_tree_1.types.array(pluginManager.pluggableMstType('track', 'stateModel')),
|
|
134
|
+
/**
|
|
135
|
+
* #property
|
|
136
|
+
* array of currently displayed tracks state model's
|
|
137
|
+
*/
|
|
138
|
+
hideHeader: false,
|
|
139
|
+
/**
|
|
140
|
+
* #property
|
|
141
|
+
*/
|
|
142
|
+
hideHeaderOverview: false,
|
|
143
|
+
/**
|
|
144
|
+
* #property
|
|
145
|
+
*/
|
|
146
|
+
hideNoTracksActive: false,
|
|
147
|
+
/**
|
|
148
|
+
* #property
|
|
149
|
+
*/
|
|
150
|
+
trackSelectorType: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.enumeration(['hierarchical']), 'hierarchical'),
|
|
151
|
+
/**
|
|
152
|
+
* #property
|
|
153
|
+
* how to display the track labels, can be "overlapping", "offset", or "hidden"
|
|
154
|
+
*/
|
|
155
|
+
trackLabels: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.string, () => localStorageGetItem('lgv-trackLabels') || 'overlapping'),
|
|
156
|
+
/**
|
|
157
|
+
* #property
|
|
158
|
+
* show the "center line"
|
|
159
|
+
*/
|
|
160
|
+
showCenterLine: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => {
|
|
161
|
+
const setting = localStorageGetItem('lgv-showCenterLine');
|
|
162
|
+
return setting !== undefined && setting !== null ? !!+setting : false;
|
|
163
|
+
}),
|
|
164
|
+
/**
|
|
165
|
+
* #property
|
|
166
|
+
* show the "cytobands" in the overview scale bar
|
|
167
|
+
*/
|
|
168
|
+
showCytobandsSetting: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => {
|
|
169
|
+
const setting = localStorageGetItem('lgv-showCytobands');
|
|
170
|
+
return setting !== undefined && setting !== null ? !!+setting : true;
|
|
171
|
+
}),
|
|
172
|
+
/**
|
|
173
|
+
* #property
|
|
174
|
+
* show the "gridlines" in the track area
|
|
175
|
+
*/
|
|
176
|
+
showGridlines: true,
|
|
177
|
+
}))
|
|
178
|
+
.volatile(() => ({
|
|
179
|
+
volatileWidth: undefined,
|
|
180
|
+
minimumBlockWidth: 3,
|
|
181
|
+
draggingTrackId: undefined,
|
|
182
|
+
volatileError: undefined,
|
|
183
|
+
// array of callbacks to run after the next set of the displayedRegions,
|
|
184
|
+
// which is basically like an onLoad
|
|
185
|
+
afterDisplayedRegionsSetCallbacks: [],
|
|
186
|
+
scaleFactor: 1,
|
|
187
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
188
|
+
trackRefs: {},
|
|
189
|
+
coarseDynamicBlocks: [],
|
|
190
|
+
coarseTotalBp: 0,
|
|
191
|
+
leftOffset: undefined,
|
|
192
|
+
rightOffset: undefined,
|
|
193
|
+
searchResults: undefined,
|
|
194
|
+
searchQuery: undefined,
|
|
195
|
+
seqDialogDisplayed: false,
|
|
196
|
+
}))
|
|
197
|
+
.views(self => ({
|
|
198
|
+
/**
|
|
199
|
+
* #getter
|
|
200
|
+
*/
|
|
201
|
+
get width() {
|
|
202
|
+
if (self.volatileWidth === undefined) {
|
|
203
|
+
throw new Error('width undefined, make sure to check for model.initialized');
|
|
204
|
+
}
|
|
205
|
+
return self.volatileWidth;
|
|
206
|
+
},
|
|
207
|
+
/**
|
|
208
|
+
* #getter
|
|
209
|
+
*/
|
|
210
|
+
get interRegionPaddingWidth() {
|
|
211
|
+
return exports.INTER_REGION_PADDING_WIDTH;
|
|
212
|
+
},
|
|
213
|
+
/**
|
|
214
|
+
* #getter
|
|
215
|
+
*/
|
|
216
|
+
get assemblyNames() {
|
|
217
|
+
return [
|
|
218
|
+
...new Set(self.displayedRegions.map(region => region.assemblyName)),
|
|
219
|
+
];
|
|
220
|
+
},
|
|
221
|
+
}))
|
|
222
|
+
.views(self => ({
|
|
223
|
+
/**
|
|
224
|
+
* #method
|
|
225
|
+
*/
|
|
226
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
227
|
+
MiniControlsComponent() {
|
|
228
|
+
return MiniControls_1.default;
|
|
229
|
+
},
|
|
230
|
+
/**
|
|
231
|
+
* #method
|
|
232
|
+
*/
|
|
233
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
234
|
+
HeaderComponent() {
|
|
235
|
+
return Header_1.default;
|
|
236
|
+
},
|
|
237
|
+
/**
|
|
238
|
+
* #getter
|
|
239
|
+
*/
|
|
240
|
+
get assemblyErrors() {
|
|
241
|
+
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
242
|
+
const { assemblyNames } = self;
|
|
243
|
+
return assemblyNames
|
|
244
|
+
.map(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.error; })
|
|
245
|
+
.filter(f => !!f)
|
|
246
|
+
.join(', ');
|
|
247
|
+
},
|
|
248
|
+
/**
|
|
249
|
+
* #getter
|
|
250
|
+
*/
|
|
251
|
+
get assembliesInitialized() {
|
|
252
|
+
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
253
|
+
const { assemblyNames } = self;
|
|
254
|
+
return assemblyNames.every(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.initialized; });
|
|
255
|
+
},
|
|
256
|
+
/**
|
|
257
|
+
* #getter
|
|
258
|
+
*/
|
|
259
|
+
get initialized() {
|
|
260
|
+
return self.volatileWidth !== undefined && this.assembliesInitialized;
|
|
261
|
+
},
|
|
262
|
+
/**
|
|
263
|
+
* #getter
|
|
264
|
+
*/
|
|
265
|
+
get hasDisplayedRegions() {
|
|
266
|
+
return self.displayedRegions.length > 0;
|
|
267
|
+
},
|
|
268
|
+
/**
|
|
269
|
+
* #getter
|
|
270
|
+
*/
|
|
271
|
+
get isSearchDialogDisplayed() {
|
|
272
|
+
return self.searchResults !== undefined;
|
|
273
|
+
},
|
|
274
|
+
/**
|
|
275
|
+
* #getter
|
|
276
|
+
*/
|
|
277
|
+
get scaleBarHeight() {
|
|
278
|
+
return exports.SCALE_BAR_HEIGHT + exports.RESIZE_HANDLE_HEIGHT;
|
|
279
|
+
},
|
|
280
|
+
/**
|
|
281
|
+
* #getter
|
|
282
|
+
*/
|
|
283
|
+
get headerHeight() {
|
|
284
|
+
if (self.hideHeader) {
|
|
285
|
+
return 0;
|
|
286
|
+
}
|
|
287
|
+
if (self.hideHeaderOverview) {
|
|
288
|
+
return exports.HEADER_BAR_HEIGHT;
|
|
289
|
+
}
|
|
290
|
+
return exports.HEADER_BAR_HEIGHT + exports.HEADER_OVERVIEW_HEIGHT;
|
|
291
|
+
},
|
|
292
|
+
/**
|
|
293
|
+
* #getter
|
|
294
|
+
*/
|
|
295
|
+
get trackHeights() {
|
|
296
|
+
return self.tracks
|
|
297
|
+
.map(t => t.displays[0].height)
|
|
298
|
+
.reduce((a, b) => a + b, 0);
|
|
299
|
+
},
|
|
300
|
+
/**
|
|
301
|
+
* #getter
|
|
302
|
+
*/
|
|
303
|
+
get trackHeightsWithResizeHandles() {
|
|
304
|
+
return this.trackHeights + self.tracks.length * exports.RESIZE_HANDLE_HEIGHT;
|
|
305
|
+
},
|
|
306
|
+
/**
|
|
307
|
+
* #getter
|
|
308
|
+
*/
|
|
309
|
+
get height() {
|
|
310
|
+
return (this.trackHeightsWithResizeHandles +
|
|
311
|
+
this.headerHeight +
|
|
312
|
+
this.scaleBarHeight);
|
|
313
|
+
},
|
|
314
|
+
/**
|
|
315
|
+
* #getter
|
|
316
|
+
*/
|
|
317
|
+
get totalBp() {
|
|
318
|
+
return self.displayedRegions.reduce((a, b) => a + b.end - b.start, 0);
|
|
319
|
+
},
|
|
320
|
+
/**
|
|
321
|
+
* #getter
|
|
322
|
+
*/
|
|
323
|
+
get maxBpPerPx() {
|
|
324
|
+
return this.totalBp / (self.width * 0.9);
|
|
325
|
+
},
|
|
326
|
+
/**
|
|
327
|
+
* #getter
|
|
328
|
+
*/
|
|
329
|
+
get minBpPerPx() {
|
|
330
|
+
return 1 / 50;
|
|
331
|
+
},
|
|
332
|
+
/**
|
|
333
|
+
* #getter
|
|
334
|
+
*/
|
|
335
|
+
get error() {
|
|
336
|
+
return self.volatileError || this.assemblyErrors;
|
|
337
|
+
},
|
|
338
|
+
/**
|
|
339
|
+
* #getter
|
|
340
|
+
*/
|
|
341
|
+
get maxOffset() {
|
|
342
|
+
// objectively determined to keep the linear genome on the main screen
|
|
343
|
+
const leftPadding = 10;
|
|
344
|
+
return this.displayedRegionsTotalPx - leftPadding;
|
|
345
|
+
},
|
|
346
|
+
/**
|
|
347
|
+
* #getter
|
|
348
|
+
*/
|
|
349
|
+
get minOffset() {
|
|
350
|
+
// objectively determined to keep the linear genome on the main screen
|
|
351
|
+
const rightPadding = 30;
|
|
352
|
+
return -self.width + rightPadding;
|
|
353
|
+
},
|
|
354
|
+
/**
|
|
355
|
+
* #getter
|
|
356
|
+
*/
|
|
357
|
+
get displayedRegionsTotalPx() {
|
|
358
|
+
return this.totalBp / self.bpPerPx;
|
|
359
|
+
},
|
|
360
|
+
/**
|
|
361
|
+
* #method
|
|
362
|
+
*/
|
|
363
|
+
renderProps() {
|
|
364
|
+
return {
|
|
365
|
+
...(0, tracks_1.getParentRenderProps)(self),
|
|
366
|
+
bpPerPx: self.bpPerPx,
|
|
367
|
+
highResolutionScaling: (0, configuration_1.getConf)((0, util_1.getSession)(self), 'highResolutionScaling'),
|
|
368
|
+
};
|
|
369
|
+
},
|
|
370
|
+
/**
|
|
371
|
+
* #method
|
|
372
|
+
*/
|
|
373
|
+
searchScope(assemblyName) {
|
|
374
|
+
return {
|
|
375
|
+
assemblyName,
|
|
376
|
+
includeAggregateIndexes: true,
|
|
377
|
+
tracks: self.tracks,
|
|
378
|
+
};
|
|
379
|
+
},
|
|
380
|
+
/**
|
|
381
|
+
* #method
|
|
382
|
+
*/
|
|
383
|
+
getTrack(id) {
|
|
384
|
+
return self.tracks.find(t => t.configuration.trackId === id);
|
|
385
|
+
},
|
|
386
|
+
/**
|
|
387
|
+
* #method
|
|
388
|
+
*/
|
|
389
|
+
rankSearchResults(results) {
|
|
390
|
+
// order of rank
|
|
391
|
+
const openTrackIds = self.tracks.map(track => track.configuration.trackId);
|
|
392
|
+
results.forEach(result => {
|
|
393
|
+
if (openTrackIds.includes(result.trackId)) {
|
|
394
|
+
result.updateScore(result.getScore() + 1);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
return results;
|
|
398
|
+
},
|
|
399
|
+
/**
|
|
400
|
+
* #method
|
|
401
|
+
* modifies view menu action onClick to apply to all tracks of same type
|
|
402
|
+
*/
|
|
403
|
+
rewriteOnClicks(trackType, viewMenuActions) {
|
|
404
|
+
viewMenuActions.forEach(action => {
|
|
405
|
+
// go to lowest level menu
|
|
406
|
+
if ('subMenu' in action) {
|
|
407
|
+
this.rewriteOnClicks(trackType, action.subMenu);
|
|
408
|
+
}
|
|
409
|
+
if ('onClick' in action) {
|
|
410
|
+
const holdOnClick = action.onClick;
|
|
411
|
+
action.onClick = (...args) => {
|
|
412
|
+
self.tracks.forEach(track => {
|
|
413
|
+
if (track.type === trackType) {
|
|
414
|
+
holdOnClick.apply(track, [track, ...args]);
|
|
415
|
+
}
|
|
416
|
+
});
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
},
|
|
421
|
+
/**
|
|
422
|
+
* #getter
|
|
423
|
+
*/
|
|
424
|
+
get trackTypeActions() {
|
|
425
|
+
const allActions = new Map();
|
|
426
|
+
self.tracks.forEach(track => {
|
|
427
|
+
const trackInMap = allActions.get(track.type);
|
|
428
|
+
if (!trackInMap) {
|
|
429
|
+
const viewMenuActions = (0, clone_1.default)(track.viewMenuActions);
|
|
430
|
+
this.rewriteOnClicks(track.type, viewMenuActions);
|
|
431
|
+
allActions.set(track.type, viewMenuActions);
|
|
432
|
+
}
|
|
433
|
+
});
|
|
434
|
+
return allActions;
|
|
435
|
+
},
|
|
436
|
+
}))
|
|
437
|
+
.actions(self => ({
|
|
438
|
+
/**
|
|
439
|
+
* #action
|
|
440
|
+
*/
|
|
441
|
+
setShowCytobands(flag) {
|
|
442
|
+
self.showCytobandsSetting = flag;
|
|
443
|
+
localStorage.setItem('lgv-showCytobands', `${+flag}`);
|
|
444
|
+
},
|
|
445
|
+
/**
|
|
446
|
+
* #action
|
|
447
|
+
*/
|
|
448
|
+
setWidth(newWidth) {
|
|
449
|
+
self.volatileWidth = newWidth;
|
|
450
|
+
},
|
|
451
|
+
/**
|
|
452
|
+
* #action
|
|
453
|
+
*/
|
|
454
|
+
setError(error) {
|
|
455
|
+
self.volatileError = error;
|
|
456
|
+
},
|
|
457
|
+
/**
|
|
458
|
+
* #action
|
|
459
|
+
*/
|
|
460
|
+
toggleHeader() {
|
|
461
|
+
self.hideHeader = !self.hideHeader;
|
|
462
|
+
},
|
|
463
|
+
/**
|
|
464
|
+
* #action
|
|
465
|
+
*/
|
|
466
|
+
toggleHeaderOverview() {
|
|
467
|
+
self.hideHeaderOverview = !self.hideHeaderOverview;
|
|
468
|
+
},
|
|
469
|
+
/**
|
|
470
|
+
* #action
|
|
471
|
+
*/
|
|
472
|
+
toggleNoTracksActive() {
|
|
473
|
+
self.hideNoTracksActive = !self.hideNoTracksActive;
|
|
474
|
+
},
|
|
475
|
+
/**
|
|
476
|
+
* #action
|
|
477
|
+
*/
|
|
478
|
+
toggleShowGridlines() {
|
|
479
|
+
self.showGridlines = !self.showGridlines;
|
|
480
|
+
},
|
|
481
|
+
/**
|
|
482
|
+
* #action
|
|
483
|
+
*/
|
|
484
|
+
scrollTo(offsetPx) {
|
|
485
|
+
const newOffsetPx = (0, util_1.clamp)(offsetPx, self.minOffset, self.maxOffset);
|
|
486
|
+
self.offsetPx = newOffsetPx;
|
|
487
|
+
return newOffsetPx;
|
|
488
|
+
},
|
|
489
|
+
/**
|
|
490
|
+
* #action
|
|
491
|
+
*/
|
|
492
|
+
zoomTo(bpPerPx) {
|
|
493
|
+
const newBpPerPx = (0, util_1.clamp)(bpPerPx, self.minBpPerPx, self.maxBpPerPx);
|
|
494
|
+
if (newBpPerPx === self.bpPerPx) {
|
|
495
|
+
return newBpPerPx;
|
|
496
|
+
}
|
|
497
|
+
const oldBpPerPx = self.bpPerPx;
|
|
498
|
+
self.bpPerPx = newBpPerPx;
|
|
499
|
+
if (Math.abs(oldBpPerPx - newBpPerPx) < 0.000001) {
|
|
500
|
+
console.warn('zoomTo bpPerPx rounding error');
|
|
501
|
+
return oldBpPerPx;
|
|
502
|
+
}
|
|
503
|
+
// tweak the offset so that the center of the view remains at the same coordinate
|
|
504
|
+
const viewWidth = self.width;
|
|
505
|
+
this.scrollTo(Math.round(((self.offsetPx + viewWidth / 2) * oldBpPerPx) / newBpPerPx -
|
|
506
|
+
viewWidth / 2));
|
|
507
|
+
return newBpPerPx;
|
|
508
|
+
},
|
|
509
|
+
/**
|
|
510
|
+
* #action
|
|
511
|
+
* sets offsets used in the get sequence dialog
|
|
512
|
+
*/
|
|
513
|
+
setOffsets(left, right) {
|
|
514
|
+
self.leftOffset = left;
|
|
515
|
+
self.rightOffset = right;
|
|
516
|
+
},
|
|
517
|
+
/**
|
|
518
|
+
* #action
|
|
519
|
+
*/
|
|
520
|
+
setSearchResults(results, query) {
|
|
521
|
+
self.searchResults = results;
|
|
522
|
+
self.searchQuery = query;
|
|
523
|
+
},
|
|
524
|
+
/**
|
|
525
|
+
* #action
|
|
526
|
+
*/
|
|
527
|
+
setGetSequenceDialogOpen(open) {
|
|
528
|
+
self.seqDialogDisplayed = open;
|
|
529
|
+
},
|
|
530
|
+
/**
|
|
531
|
+
* #action
|
|
532
|
+
*/
|
|
533
|
+
setNewView(bpPerPx, offsetPx) {
|
|
534
|
+
this.zoomTo(bpPerPx);
|
|
535
|
+
this.scrollTo(offsetPx);
|
|
536
|
+
},
|
|
537
|
+
/**
|
|
538
|
+
* #action
|
|
539
|
+
*/
|
|
540
|
+
horizontallyFlip() {
|
|
541
|
+
self.displayedRegions = (0, mobx_state_tree_1.cast)(self.displayedRegions
|
|
542
|
+
.slice()
|
|
543
|
+
.reverse()
|
|
544
|
+
.map(region => ({ ...region, reversed: !region.reversed })));
|
|
545
|
+
this.scrollTo(self.totalBp / self.bpPerPx - self.offsetPx - self.width);
|
|
546
|
+
},
|
|
547
|
+
/**
|
|
548
|
+
* #action
|
|
549
|
+
*/
|
|
550
|
+
showTrack(trackId, initialSnapshot = {}, displayInitialSnapshot = {}) {
|
|
551
|
+
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
552
|
+
const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId);
|
|
553
|
+
if (!conf) {
|
|
554
|
+
throw new Error(`Could not resolve identifier "${trackId}"`);
|
|
555
|
+
}
|
|
556
|
+
const trackType = pluginManager.getTrackType(conf === null || conf === void 0 ? void 0 : conf.type);
|
|
557
|
+
if (!trackType) {
|
|
558
|
+
throw new Error(`Unknown track type ${conf.type}`);
|
|
559
|
+
}
|
|
560
|
+
const viewType = pluginManager.getViewType(self.type);
|
|
561
|
+
const supportedDisplays = viewType.displayTypes.map(d => d.name);
|
|
562
|
+
const displayConf = conf.displays.find((d) => supportedDisplays.includes(d.type));
|
|
563
|
+
if (!displayConf) {
|
|
564
|
+
throw new Error(`Could not find a compatible display for view type ${self.type}`);
|
|
565
|
+
}
|
|
566
|
+
const t = self.tracks.filter(t => t.configuration === conf);
|
|
567
|
+
if (t.length === 0) {
|
|
568
|
+
const track = trackType.stateModel.create({
|
|
569
|
+
...initialSnapshot,
|
|
570
|
+
type: conf.type,
|
|
571
|
+
configuration: conf,
|
|
572
|
+
displays: [
|
|
573
|
+
{
|
|
574
|
+
type: displayConf.type,
|
|
575
|
+
configuration: displayConf,
|
|
576
|
+
...displayInitialSnapshot,
|
|
577
|
+
},
|
|
578
|
+
],
|
|
579
|
+
});
|
|
580
|
+
self.tracks.push(track);
|
|
581
|
+
return track;
|
|
582
|
+
}
|
|
583
|
+
return t[0];
|
|
584
|
+
},
|
|
585
|
+
/**
|
|
586
|
+
* #action
|
|
587
|
+
*/
|
|
588
|
+
hideTrack(trackId) {
|
|
589
|
+
const schema = pluginManager.pluggableConfigSchemaType('track');
|
|
590
|
+
const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId);
|
|
591
|
+
const t = self.tracks.filter(t => t.configuration === conf);
|
|
592
|
+
(0, mobx_1.transaction)(() => t.forEach(t => self.tracks.remove(t)));
|
|
593
|
+
return t.length;
|
|
594
|
+
},
|
|
595
|
+
}))
|
|
596
|
+
.actions(self => ({
|
|
597
|
+
/**
|
|
598
|
+
* #action
|
|
599
|
+
*/
|
|
600
|
+
moveTrack(movingId, targetId) {
|
|
601
|
+
const oldIndex = self.tracks.findIndex(track => track.id === movingId);
|
|
602
|
+
if (oldIndex === -1) {
|
|
603
|
+
throw new Error(`Track ID ${movingId} not found`);
|
|
604
|
+
}
|
|
605
|
+
const newIndex = self.tracks.findIndex(track => track.id === targetId);
|
|
606
|
+
if (newIndex === -1) {
|
|
607
|
+
throw new Error(`Track ID ${targetId} not found`);
|
|
608
|
+
}
|
|
609
|
+
const track = (0, mobx_state_tree_1.getSnapshot)(self.tracks[oldIndex]);
|
|
610
|
+
self.tracks.splice(oldIndex, 1);
|
|
611
|
+
self.tracks.splice(newIndex, 0, track);
|
|
612
|
+
},
|
|
613
|
+
/**
|
|
614
|
+
* #action
|
|
615
|
+
*/
|
|
616
|
+
closeView() {
|
|
617
|
+
const parent = (0, util_1.getContainingView)(self);
|
|
618
|
+
if (parent) {
|
|
619
|
+
// I am embedded in a some other view
|
|
620
|
+
if ((0, util_1.isViewContainer)(parent)) {
|
|
621
|
+
parent.removeView(self);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
else {
|
|
625
|
+
// I am part of a session
|
|
626
|
+
(0, util_1.getSession)(self).removeView(self);
|
|
627
|
+
}
|
|
628
|
+
},
|
|
629
|
+
/**
|
|
630
|
+
* #action
|
|
631
|
+
*/
|
|
632
|
+
toggleTrack(trackId) {
|
|
633
|
+
// if we have any tracks with that configuration, turn them off
|
|
634
|
+
const hiddenCount = self.hideTrack(trackId);
|
|
635
|
+
// if none had that configuration, turn one on
|
|
636
|
+
if (!hiddenCount) {
|
|
637
|
+
self.showTrack(trackId);
|
|
638
|
+
}
|
|
639
|
+
},
|
|
640
|
+
/**
|
|
641
|
+
* #action
|
|
642
|
+
*/
|
|
643
|
+
setTrackLabels(setting) {
|
|
644
|
+
self.trackLabels = setting;
|
|
645
|
+
localStorage.setItem('lgv-trackLabels', setting);
|
|
646
|
+
},
|
|
647
|
+
/**
|
|
648
|
+
* #action
|
|
649
|
+
*/
|
|
650
|
+
toggleCenterLine() {
|
|
651
|
+
self.showCenterLine = !self.showCenterLine;
|
|
652
|
+
localStorage.setItem('lgv-showCenterLine', `${+self.showCenterLine}`);
|
|
653
|
+
},
|
|
654
|
+
/**
|
|
655
|
+
* #action
|
|
656
|
+
*/
|
|
657
|
+
setDisplayedRegions(regions) {
|
|
658
|
+
self.displayedRegions = (0, mobx_state_tree_1.cast)(regions);
|
|
659
|
+
self.zoomTo(self.bpPerPx);
|
|
660
|
+
},
|
|
661
|
+
/**
|
|
662
|
+
* #action
|
|
663
|
+
*/
|
|
664
|
+
activateTrackSelector() {
|
|
665
|
+
if (self.trackSelectorType === 'hierarchical') {
|
|
666
|
+
const session = (0, util_1.getSession)(self);
|
|
667
|
+
if ((0, util_1.isSessionModelWithWidgets)(session)) {
|
|
668
|
+
const selector = session.addWidget('HierarchicalTrackSelectorWidget', 'hierarchicalTrackSelector', { view: self });
|
|
669
|
+
session.showWidget(selector);
|
|
670
|
+
return selector;
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
throw new Error(`invalid track selector type ${self.trackSelectorType}`);
|
|
674
|
+
},
|
|
675
|
+
/**
|
|
676
|
+
* #method
|
|
677
|
+
* Helper method for the fetchSequence.
|
|
678
|
+
* Retrieves the corresponding regions that were selected by the rubberband
|
|
679
|
+
*
|
|
680
|
+
* @param leftOffset - `object as {start, end, index, offset}`, offset = start of user drag
|
|
681
|
+
* @param rightOffset - `object as {start, end, index, offset}`, offset = end of user drag
|
|
682
|
+
* @returns array of Region[]
|
|
683
|
+
*/
|
|
684
|
+
getSelectedRegions(leftOffset, rightOffset) {
|
|
685
|
+
const snap = (0, mobx_state_tree_1.getSnapshot)(self);
|
|
686
|
+
const simView = Base1DViewModel_1.default.create({
|
|
687
|
+
...snap,
|
|
688
|
+
interRegionPaddingWidth: self.interRegionPaddingWidth,
|
|
689
|
+
});
|
|
690
|
+
simView.setVolatileWidth(self.width);
|
|
691
|
+
simView.moveTo(leftOffset, rightOffset);
|
|
692
|
+
return simView.dynamicBlocks.contentBlocks.map(region => ({
|
|
693
|
+
...region,
|
|
694
|
+
start: Math.floor(region.start),
|
|
695
|
+
end: Math.ceil(region.end),
|
|
696
|
+
}));
|
|
697
|
+
},
|
|
698
|
+
/**
|
|
699
|
+
* #action
|
|
700
|
+
* schedule something to be run after the next time displayedRegions is set
|
|
701
|
+
*/
|
|
702
|
+
afterDisplayedRegionsSet(cb) {
|
|
703
|
+
self.afterDisplayedRegionsSetCallbacks.push(cb);
|
|
704
|
+
},
|
|
705
|
+
/**
|
|
706
|
+
* #action
|
|
707
|
+
*/
|
|
708
|
+
horizontalScroll(distance) {
|
|
709
|
+
const oldOffsetPx = self.offsetPx;
|
|
710
|
+
// newOffsetPx is the actual offset after the scroll is clamped
|
|
711
|
+
const newOffsetPx = self.scrollTo(self.offsetPx + distance);
|
|
712
|
+
return newOffsetPx - oldOffsetPx;
|
|
713
|
+
},
|
|
714
|
+
/**
|
|
715
|
+
* #action
|
|
716
|
+
*/
|
|
717
|
+
center() {
|
|
718
|
+
const centerBp = self.totalBp / 2;
|
|
719
|
+
const centerPx = centerBp / self.bpPerPx;
|
|
720
|
+
self.scrollTo(Math.round(centerPx - self.width / 2));
|
|
721
|
+
},
|
|
722
|
+
/**
|
|
723
|
+
* #action
|
|
724
|
+
*/
|
|
725
|
+
showAllRegions() {
|
|
726
|
+
self.zoomTo(self.maxBpPerPx);
|
|
727
|
+
this.center();
|
|
728
|
+
},
|
|
729
|
+
/**
|
|
730
|
+
* #action
|
|
731
|
+
*/
|
|
732
|
+
showAllRegionsInAssembly(assemblyName) {
|
|
733
|
+
const session = (0, util_1.getSession)(self);
|
|
734
|
+
const { assemblyManager } = session;
|
|
735
|
+
if (!assemblyName) {
|
|
736
|
+
const names = new Set(self.displayedRegions.map(r => r.assemblyName));
|
|
737
|
+
if (names.size > 1) {
|
|
738
|
+
session.notify(`Can't perform operation with multiple assemblies currently`);
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
;
|
|
742
|
+
[assemblyName] = [...names];
|
|
743
|
+
}
|
|
744
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
745
|
+
if (assembly) {
|
|
746
|
+
const { regions } = assembly;
|
|
747
|
+
if (regions) {
|
|
748
|
+
this.setDisplayedRegions(regions);
|
|
749
|
+
self.zoomTo(self.maxBpPerPx);
|
|
750
|
+
this.center();
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
/**
|
|
755
|
+
* #action
|
|
756
|
+
*/
|
|
757
|
+
setDraggingTrackId(idx) {
|
|
758
|
+
self.draggingTrackId = idx;
|
|
759
|
+
},
|
|
760
|
+
/**
|
|
761
|
+
* #action
|
|
762
|
+
*/
|
|
763
|
+
setScaleFactor(factor) {
|
|
764
|
+
self.scaleFactor = factor;
|
|
765
|
+
},
|
|
766
|
+
/**
|
|
767
|
+
* #action
|
|
768
|
+
* this "clears the view" and makes the view return to the import form
|
|
769
|
+
*/
|
|
770
|
+
clearView() {
|
|
771
|
+
this.setDisplayedRegions([]);
|
|
772
|
+
self.tracks.clear();
|
|
773
|
+
// it is necessary to run these after setting displayed regions empty
|
|
774
|
+
// or else model.offsetPx gets set to Infinity and breaks
|
|
775
|
+
// mobx-state-tree snapshot
|
|
776
|
+
self.scrollTo(0);
|
|
777
|
+
self.zoomTo(10);
|
|
778
|
+
},
|
|
779
|
+
/**
|
|
780
|
+
* #action
|
|
781
|
+
* creates an svg export and save using FileSaver
|
|
782
|
+
*/
|
|
783
|
+
async exportSvg(opts = {}) {
|
|
784
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
785
|
+
const html = await (0, LinearGenomeViewSvg_1.renderToSvg)(self, opts);
|
|
786
|
+
const blob = new Blob([html], { type: 'image/svg+xml' });
|
|
787
|
+
(0, file_saver_1.saveAs)(blob, opts.filename || 'image.svg');
|
|
788
|
+
},
|
|
789
|
+
}))
|
|
790
|
+
.actions(self => {
|
|
791
|
+
let cancelLastAnimation = () => { };
|
|
792
|
+
/**
|
|
793
|
+
* #action
|
|
794
|
+
* perform animated slide
|
|
795
|
+
*/
|
|
796
|
+
function slide(viewWidths) {
|
|
797
|
+
const [animate, cancelAnimation] = (0, util_1.springAnimate)(self.offsetPx, self.offsetPx + self.width * viewWidths, self.scrollTo);
|
|
798
|
+
cancelLastAnimation();
|
|
799
|
+
cancelLastAnimation = cancelAnimation;
|
|
800
|
+
animate();
|
|
801
|
+
}
|
|
802
|
+
return { slide };
|
|
803
|
+
})
|
|
804
|
+
.actions(self => {
|
|
805
|
+
let cancelLastAnimation = () => { };
|
|
806
|
+
/**
|
|
807
|
+
* #action
|
|
808
|
+
* perform animated zoom
|
|
809
|
+
*/
|
|
810
|
+
function zoom(targetBpPerPx) {
|
|
811
|
+
self.zoomTo(self.bpPerPx);
|
|
812
|
+
if (
|
|
813
|
+
// already zoomed all the way in
|
|
814
|
+
(targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx) ||
|
|
815
|
+
// already zoomed all the way out
|
|
816
|
+
(targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx)) {
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
const factor = self.bpPerPx / targetBpPerPx;
|
|
820
|
+
const [animate, cancelAnimation] = (0, util_1.springAnimate)(1, factor, self.setScaleFactor, () => {
|
|
821
|
+
self.zoomTo(targetBpPerPx);
|
|
822
|
+
self.setScaleFactor(1);
|
|
823
|
+
});
|
|
824
|
+
cancelLastAnimation();
|
|
825
|
+
cancelLastAnimation = cancelAnimation;
|
|
826
|
+
animate();
|
|
827
|
+
}
|
|
828
|
+
return { zoom };
|
|
829
|
+
})
|
|
830
|
+
.views(self => ({
|
|
831
|
+
/**
|
|
832
|
+
* #getter
|
|
833
|
+
*/
|
|
834
|
+
get canShowCytobands() {
|
|
835
|
+
return self.displayedRegions.length === 1 && this.anyCytobandsExist;
|
|
836
|
+
},
|
|
837
|
+
/**
|
|
838
|
+
* #getter
|
|
839
|
+
*/
|
|
840
|
+
get showCytobands() {
|
|
841
|
+
return this.canShowCytobands && self.showCytobandsSetting;
|
|
842
|
+
},
|
|
843
|
+
/**
|
|
844
|
+
* #getter
|
|
845
|
+
*/
|
|
846
|
+
get anyCytobandsExist() {
|
|
847
|
+
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
848
|
+
return self.assemblyNames.some(a => { var _a, _b; return (_b = (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.cytobands) === null || _b === void 0 ? void 0 : _b.length; });
|
|
849
|
+
},
|
|
850
|
+
/**
|
|
851
|
+
* #getter
|
|
852
|
+
* the cytoband is displayed to the right of the chromosome name,
|
|
853
|
+
* and that offset is calculated manually with this method
|
|
854
|
+
*/
|
|
855
|
+
get cytobandOffset() {
|
|
856
|
+
return this.showCytobands
|
|
857
|
+
? (0, util_1.measureText)(self.displayedRegions[0].refName, 12) + 15
|
|
858
|
+
: 0;
|
|
859
|
+
},
|
|
860
|
+
}))
|
|
861
|
+
.views(self => ({
|
|
862
|
+
/**
|
|
863
|
+
* #method
|
|
864
|
+
* return the view menu items
|
|
865
|
+
*/
|
|
866
|
+
menuItems() {
|
|
867
|
+
const { canShowCytobands, showCytobands } = self;
|
|
868
|
+
const session = (0, util_1.getSession)(self);
|
|
869
|
+
const menuItems = [
|
|
870
|
+
{
|
|
871
|
+
label: 'Return to import form',
|
|
872
|
+
onClick: () => {
|
|
873
|
+
(0, util_1.getSession)(self).queueDialog(handleClose => [
|
|
874
|
+
ui_1.ReturnToImportFormDialog,
|
|
875
|
+
{ model: self, handleClose },
|
|
876
|
+
]);
|
|
877
|
+
},
|
|
878
|
+
icon: FolderOpen_1.default,
|
|
879
|
+
},
|
|
880
|
+
...((0, util_1.isSessionWithAddTracks)(session)
|
|
881
|
+
? [
|
|
882
|
+
{
|
|
883
|
+
label: 'Sequence search',
|
|
884
|
+
onClick: () => {
|
|
885
|
+
(0, util_1.getSession)(self).queueDialog(handleClose => [
|
|
886
|
+
SequenceSearchDialog,
|
|
887
|
+
{ model: self, handleClose },
|
|
888
|
+
]);
|
|
889
|
+
},
|
|
890
|
+
},
|
|
891
|
+
]
|
|
892
|
+
: []),
|
|
893
|
+
{
|
|
894
|
+
label: 'Export SVG',
|
|
895
|
+
icon: PhotoCamera_1.default,
|
|
896
|
+
onClick: () => {
|
|
897
|
+
(0, util_1.getSession)(self).queueDialog(handleClose => [
|
|
898
|
+
ExportSvgDialog_1.default,
|
|
899
|
+
{ model: self, handleClose },
|
|
900
|
+
]);
|
|
901
|
+
},
|
|
902
|
+
},
|
|
903
|
+
{
|
|
904
|
+
label: 'Open track selector',
|
|
905
|
+
onClick: self.activateTrackSelector,
|
|
906
|
+
icon: Icons_1.TrackSelector,
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
label: 'Horizontally flip',
|
|
910
|
+
icon: SyncAlt_1.default,
|
|
911
|
+
onClick: self.horizontallyFlip,
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
label: 'Show...',
|
|
915
|
+
icon: Visibility_1.default,
|
|
916
|
+
subMenu: [
|
|
917
|
+
{
|
|
918
|
+
label: 'Show all regions in assembly',
|
|
919
|
+
onClick: self.showAllRegionsInAssembly,
|
|
920
|
+
},
|
|
921
|
+
{
|
|
922
|
+
label: 'Show center line',
|
|
923
|
+
type: 'checkbox',
|
|
924
|
+
checked: self.showCenterLine,
|
|
925
|
+
onClick: self.toggleCenterLine,
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
label: 'Show header',
|
|
929
|
+
type: 'checkbox',
|
|
930
|
+
checked: !self.hideHeader,
|
|
931
|
+
onClick: self.toggleHeader,
|
|
932
|
+
},
|
|
933
|
+
{
|
|
934
|
+
label: 'Show header overview',
|
|
935
|
+
type: 'checkbox',
|
|
936
|
+
checked: !self.hideHeaderOverview,
|
|
937
|
+
onClick: self.toggleHeaderOverview,
|
|
938
|
+
disabled: self.hideHeader,
|
|
939
|
+
},
|
|
940
|
+
{
|
|
941
|
+
label: 'Show no tracks active button',
|
|
942
|
+
type: 'checkbox',
|
|
943
|
+
checked: !self.hideNoTracksActive,
|
|
944
|
+
onClick: self.toggleNoTracksActive,
|
|
945
|
+
},
|
|
946
|
+
{
|
|
947
|
+
label: 'Show guidelines',
|
|
948
|
+
type: 'checkbox',
|
|
949
|
+
checked: self.showGridlines,
|
|
950
|
+
onClick: self.toggleShowGridlines,
|
|
951
|
+
},
|
|
952
|
+
...(canShowCytobands
|
|
953
|
+
? [
|
|
954
|
+
{
|
|
955
|
+
label: 'Show ideogram',
|
|
956
|
+
type: 'checkbox',
|
|
957
|
+
checked: self.showCytobands,
|
|
958
|
+
onClick: () => self.setShowCytobands(!showCytobands),
|
|
959
|
+
},
|
|
960
|
+
]
|
|
961
|
+
: []),
|
|
962
|
+
],
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
label: 'Track labels',
|
|
966
|
+
icon: Label_1.default,
|
|
967
|
+
subMenu: [
|
|
968
|
+
{
|
|
969
|
+
label: 'Overlapping',
|
|
970
|
+
icon: Visibility_1.default,
|
|
971
|
+
type: 'radio',
|
|
972
|
+
checked: self.trackLabels === 'overlapping',
|
|
973
|
+
onClick: () => self.setTrackLabels('overlapping'),
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
label: 'Offset',
|
|
977
|
+
icon: Visibility_1.default,
|
|
978
|
+
type: 'radio',
|
|
979
|
+
checked: self.trackLabels === 'offset',
|
|
980
|
+
onClick: () => self.setTrackLabels('offset'),
|
|
981
|
+
},
|
|
982
|
+
{
|
|
983
|
+
label: 'Hidden',
|
|
984
|
+
icon: Visibility_1.default,
|
|
985
|
+
type: 'radio',
|
|
986
|
+
checked: self.trackLabels === 'hidden',
|
|
987
|
+
onClick: () => self.setTrackLabels('hidden'),
|
|
988
|
+
},
|
|
989
|
+
],
|
|
990
|
+
},
|
|
991
|
+
];
|
|
992
|
+
// add track's view level menu options
|
|
993
|
+
for (const [key, value] of self.trackTypeActions.entries()) {
|
|
994
|
+
if (value.length) {
|
|
995
|
+
menuItems.push({ type: 'divider' }, { type: 'subHeader', label: key });
|
|
996
|
+
value.forEach(action => menuItems.push(action));
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return menuItems;
|
|
1000
|
+
},
|
|
1001
|
+
}))
|
|
1002
|
+
.views(self => {
|
|
1003
|
+
let currentlyCalculatedStaticBlocks;
|
|
1004
|
+
let stringifiedCurrentlyCalculatedStaticBlocks = '';
|
|
1005
|
+
return {
|
|
1006
|
+
/**
|
|
1007
|
+
* #getter
|
|
1008
|
+
* static blocks are an important concept jbrowse uses to avoid
|
|
1009
|
+
* re-rendering when you scroll to the side. when you horizontally
|
|
1010
|
+
* scroll to the right, old blocks to the left may be removed, and
|
|
1011
|
+
* new blocks may be instantiated on the right. tracks may use the
|
|
1012
|
+
* static blocks to render their data for the region represented by
|
|
1013
|
+
* the block
|
|
1014
|
+
*/
|
|
1015
|
+
get staticBlocks() {
|
|
1016
|
+
const ret = (0, calculateStaticBlocks_1.default)(self);
|
|
1017
|
+
const sret = JSON.stringify(ret);
|
|
1018
|
+
if (stringifiedCurrentlyCalculatedStaticBlocks !== sret) {
|
|
1019
|
+
currentlyCalculatedStaticBlocks = ret;
|
|
1020
|
+
stringifiedCurrentlyCalculatedStaticBlocks = sret;
|
|
1021
|
+
}
|
|
1022
|
+
return currentlyCalculatedStaticBlocks;
|
|
1023
|
+
},
|
|
1024
|
+
/**
|
|
1025
|
+
* #getter
|
|
1026
|
+
* dynamic blocks represent the exact coordinates of the currently
|
|
1027
|
+
* visible genome regions on the screen. they are similar to static
|
|
1028
|
+
* blocks, but statcic blocks can go offscreen while dynamic blocks
|
|
1029
|
+
* represent exactly what is on screen
|
|
1030
|
+
*/
|
|
1031
|
+
get dynamicBlocks() {
|
|
1032
|
+
return (0, calculateDynamicBlocks_1.default)(self);
|
|
1033
|
+
},
|
|
1034
|
+
/**
|
|
1035
|
+
* #getter
|
|
1036
|
+
* rounded dynamic blocks are dynamic blocks without fractions of bp
|
|
1037
|
+
*/
|
|
1038
|
+
get roundedDynamicBlocks() {
|
|
1039
|
+
return this.dynamicBlocks.contentBlocks.map(block => ({
|
|
1040
|
+
...block,
|
|
1041
|
+
start: Math.floor(block.start),
|
|
1042
|
+
end: Math.ceil(block.end),
|
|
1043
|
+
}));
|
|
1044
|
+
},
|
|
1045
|
+
/**
|
|
1046
|
+
* #getter
|
|
1047
|
+
* a single "combo-locstring" representing all the regions visible
|
|
1048
|
+
* on the screen
|
|
1049
|
+
*/
|
|
1050
|
+
get visibleLocStrings() {
|
|
1051
|
+
return calculateVisibleLocStrings(this.dynamicBlocks.contentBlocks);
|
|
1052
|
+
},
|
|
1053
|
+
/**
|
|
1054
|
+
* #getter
|
|
1055
|
+
* same as visibleLocStrings, but only updated every 300ms
|
|
1056
|
+
*/
|
|
1057
|
+
get coarseVisibleLocStrings() {
|
|
1058
|
+
return calculateVisibleLocStrings(self.coarseDynamicBlocks);
|
|
1059
|
+
},
|
|
1060
|
+
};
|
|
1061
|
+
})
|
|
1062
|
+
.actions(self => ({
|
|
1063
|
+
/**
|
|
1064
|
+
* #action
|
|
1065
|
+
*/
|
|
1066
|
+
setCoarseDynamicBlocks(blocks) {
|
|
1067
|
+
self.coarseDynamicBlocks = blocks.contentBlocks;
|
|
1068
|
+
self.coarseTotalBp = blocks.totalBp;
|
|
1069
|
+
},
|
|
1070
|
+
afterAttach() {
|
|
1071
|
+
(0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => {
|
|
1072
|
+
if (self.initialized) {
|
|
1073
|
+
this.setCoarseDynamicBlocks(self.dynamicBlocks);
|
|
1074
|
+
}
|
|
1075
|
+
}, { delay: 150 }));
|
|
1076
|
+
},
|
|
1077
|
+
}))
|
|
1078
|
+
.actions(self => ({
|
|
1079
|
+
/**
|
|
1080
|
+
* #action
|
|
1081
|
+
* offset is the base-pair-offset in the displayed region, index is the index of the
|
|
1082
|
+
* displayed region in the linear genome view
|
|
1083
|
+
*
|
|
1084
|
+
* @param start - object as `{start, end, offset, index}`
|
|
1085
|
+
* @param end - object as `{start, end, offset, index}`
|
|
1086
|
+
*/
|
|
1087
|
+
moveTo(start, end) {
|
|
1088
|
+
(0, Base1DUtils_1.moveTo)(self, start, end);
|
|
1089
|
+
},
|
|
1090
|
+
/**
|
|
1091
|
+
* #action
|
|
1092
|
+
* navigate to the given locstring
|
|
1093
|
+
*
|
|
1094
|
+
* @param locString - e.g. "chr1:1-100"
|
|
1095
|
+
* @param optAssemblyName - (optional) the assembly name to use when navigating to the locstring
|
|
1096
|
+
*/
|
|
1097
|
+
async navToLocString(locString, optAssemblyName) {
|
|
1098
|
+
const { assemblyNames } = self;
|
|
1099
|
+
const { assemblyManager } = (0, util_1.getSession)(self);
|
|
1100
|
+
const { isValidRefName } = assemblyManager;
|
|
1101
|
+
await (0, mobx_1.when)(() => self.volatileWidth !== undefined);
|
|
1102
|
+
const assemblyName = optAssemblyName || assemblyNames[0];
|
|
1103
|
+
let parsedLocStrings;
|
|
1104
|
+
const inputs = locString
|
|
1105
|
+
.split(/(\s+)/)
|
|
1106
|
+
.map(f => f.trim())
|
|
1107
|
+
.filter(f => !!f);
|
|
1108
|
+
if (assemblyName) {
|
|
1109
|
+
await assemblyManager.waitForAssembly(assemblyName);
|
|
1110
|
+
}
|
|
1111
|
+
// first try interpreting as a whitespace-separated sequence of
|
|
1112
|
+
// multiple locstrings
|
|
1113
|
+
try {
|
|
1114
|
+
parsedLocStrings = inputs.map(loc => (0, util_1.parseLocString)(loc, ref => isValidRefName(ref, assemblyName)));
|
|
1115
|
+
}
|
|
1116
|
+
catch (e) {
|
|
1117
|
+
// if this fails, try interpreting as a whitespace-separated refname,
|
|
1118
|
+
// start, end if start and end are integer inputs
|
|
1119
|
+
const [refName, start, end] = inputs;
|
|
1120
|
+
if (`${e}`.match(/Unknown reference sequence/) &&
|
|
1121
|
+
Number.isInteger(+start) &&
|
|
1122
|
+
Number.isInteger(+end)) {
|
|
1123
|
+
parsedLocStrings = [
|
|
1124
|
+
(0, util_1.parseLocString)(refName + ':' + start + '..' + end, ref => isValidRefName(ref, assemblyName)),
|
|
1125
|
+
];
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
throw e;
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
const locations = await Promise.all(parsedLocStrings === null || parsedLocStrings === void 0 ? void 0 : parsedLocStrings.map(async (region) => {
|
|
1132
|
+
const asmName = region.assemblyName || assemblyName;
|
|
1133
|
+
const asm = await assemblyManager.waitForAssembly(asmName);
|
|
1134
|
+
const { refName } = region;
|
|
1135
|
+
if (!asm) {
|
|
1136
|
+
throw new Error(`assembly ${asmName} not found`);
|
|
1137
|
+
}
|
|
1138
|
+
const { regions } = asm;
|
|
1139
|
+
if (!regions) {
|
|
1140
|
+
throw new Error(`regions not loaded yet for ${asmName}`);
|
|
1141
|
+
}
|
|
1142
|
+
const canonicalRefName = asm.getCanonicalRefName(region.refName);
|
|
1143
|
+
if (!canonicalRefName) {
|
|
1144
|
+
throw new Error(`Could not find refName ${refName} in ${asm.name}`);
|
|
1145
|
+
}
|
|
1146
|
+
const parentRegion = regions.find(r => r.refName === canonicalRefName);
|
|
1147
|
+
if (!parentRegion) {
|
|
1148
|
+
throw new Error(`Could not find refName ${refName} in ${asmName}`);
|
|
1149
|
+
}
|
|
1150
|
+
return {
|
|
1151
|
+
...region,
|
|
1152
|
+
assemblyName: asmName,
|
|
1153
|
+
parentRegion,
|
|
1154
|
+
};
|
|
1155
|
+
}));
|
|
1156
|
+
if (locations.length === 1) {
|
|
1157
|
+
const loc = locations[0];
|
|
1158
|
+
self.setDisplayedRegions([
|
|
1159
|
+
{ reversed: loc.reversed, ...loc.parentRegion },
|
|
1160
|
+
]);
|
|
1161
|
+
const { start, end, parentRegion } = loc;
|
|
1162
|
+
this.navTo({
|
|
1163
|
+
...loc,
|
|
1164
|
+
start: (0, util_1.clamp)(start !== null && start !== void 0 ? start : 0, 0, parentRegion.end),
|
|
1165
|
+
end: (0, util_1.clamp)(end !== null && end !== void 0 ? end : parentRegion.end, 0, parentRegion.end),
|
|
1166
|
+
});
|
|
1167
|
+
}
|
|
1168
|
+
else {
|
|
1169
|
+
self.setDisplayedRegions(
|
|
1170
|
+
// @ts-ignore
|
|
1171
|
+
locations.map(r => (r.start === undefined ? r.parentRegion : r)));
|
|
1172
|
+
self.showAllRegions();
|
|
1173
|
+
}
|
|
1174
|
+
},
|
|
1175
|
+
/**
|
|
1176
|
+
* #action
|
|
1177
|
+
* Navigate to a location based on its refName and optionally start, end,
|
|
1178
|
+
* and assemblyName. Can handle if there are multiple displayedRegions
|
|
1179
|
+
* from same refName. Only navigates to a location if it is entirely
|
|
1180
|
+
* within a displayedRegion. Navigates to the first matching location
|
|
1181
|
+
* encountered.
|
|
1182
|
+
*
|
|
1183
|
+
* Throws an error if navigation was unsuccessful
|
|
1184
|
+
*
|
|
1185
|
+
* @param query - a proposed location to navigate to
|
|
1186
|
+
*/
|
|
1187
|
+
navTo(query) {
|
|
1188
|
+
this.navToMultiple([query]);
|
|
1189
|
+
},
|
|
1190
|
+
/**
|
|
1191
|
+
* #action
|
|
1192
|
+
*/
|
|
1193
|
+
navToMultiple(locations) {
|
|
1194
|
+
const firstLocation = locations[0];
|
|
1195
|
+
let { refName } = firstLocation;
|
|
1196
|
+
const { start, end, assemblyName = self.assemblyNames[0], } = firstLocation;
|
|
1197
|
+
if (start !== undefined && end !== undefined && start > end) {
|
|
1198
|
+
throw new Error(`start "${start + 1}" is greater than end "${end}"`);
|
|
1199
|
+
}
|
|
1200
|
+
const session = (0, util_1.getSession)(self);
|
|
1201
|
+
const { assemblyManager } = session;
|
|
1202
|
+
const assembly = assemblyManager.get(assemblyName);
|
|
1203
|
+
if (assembly) {
|
|
1204
|
+
const canonicalRefName = assembly.getCanonicalRefName(refName);
|
|
1205
|
+
if (canonicalRefName) {
|
|
1206
|
+
refName = canonicalRefName;
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
let s = start;
|
|
1210
|
+
let e = end;
|
|
1211
|
+
let refNameMatched = false;
|
|
1212
|
+
const predicate = (r) => {
|
|
1213
|
+
if (refName === r.refName) {
|
|
1214
|
+
refNameMatched = true;
|
|
1215
|
+
if (s === undefined) {
|
|
1216
|
+
s = r.start;
|
|
1217
|
+
}
|
|
1218
|
+
if (e === undefined) {
|
|
1219
|
+
e = r.end;
|
|
1220
|
+
}
|
|
1221
|
+
if (s >= r.start && s <= r.end && e <= r.end && e >= r.start) {
|
|
1222
|
+
return true;
|
|
1223
|
+
}
|
|
1224
|
+
s = start;
|
|
1225
|
+
e = end;
|
|
1226
|
+
}
|
|
1227
|
+
return false;
|
|
1228
|
+
};
|
|
1229
|
+
const lastIndex = (0, util_1.findLastIndex)(self.displayedRegions, predicate);
|
|
1230
|
+
let index;
|
|
1231
|
+
while (index !== lastIndex) {
|
|
1232
|
+
try {
|
|
1233
|
+
const previousIndex = index;
|
|
1234
|
+
index = self.displayedRegions
|
|
1235
|
+
.slice(previousIndex === undefined ? 0 : previousIndex + 1)
|
|
1236
|
+
.findIndex(predicate);
|
|
1237
|
+
if (previousIndex !== undefined) {
|
|
1238
|
+
index += previousIndex + 1;
|
|
1239
|
+
}
|
|
1240
|
+
if (!refNameMatched) {
|
|
1241
|
+
throw new Error(`could not find a region with refName "${refName}"`);
|
|
1242
|
+
}
|
|
1243
|
+
if (s === undefined) {
|
|
1244
|
+
throw new Error(`could not find a region with refName "${refName}" that contained an end position ${e}`);
|
|
1245
|
+
}
|
|
1246
|
+
if (e === undefined) {
|
|
1247
|
+
throw new Error(`could not find a region with refName "${refName}" that contained a start position ${s + 1}`);
|
|
1248
|
+
}
|
|
1249
|
+
if (index === -1) {
|
|
1250
|
+
throw new Error(`could not find a region that completely contained "${(0, util_1.assembleLocString)(firstLocation)}"`);
|
|
1251
|
+
}
|
|
1252
|
+
if (locations.length === 1) {
|
|
1253
|
+
const f = self.displayedRegions[index];
|
|
1254
|
+
this.moveTo({ index, offset: f.reversed ? f.end - e : s - f.start }, { index, offset: f.reversed ? f.end - s : e - f.start });
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
let idx = 0;
|
|
1258
|
+
let start = 0;
|
|
1259
|
+
let end = 0;
|
|
1260
|
+
for (idx; idx < locations.length; idx++) {
|
|
1261
|
+
const location = locations[idx];
|
|
1262
|
+
const region = self.displayedRegions[index + idx];
|
|
1263
|
+
start = location.start || region.start;
|
|
1264
|
+
end = location.end || region.end;
|
|
1265
|
+
if (location.refName !== region.refName) {
|
|
1266
|
+
throw new Error(`Entered location ${(0, util_1.assembleLocString)(location)} does not match with displayed regions`);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
idx -= 1;
|
|
1270
|
+
const startDisplayedRegion = self.displayedRegions[index];
|
|
1271
|
+
const endDisplayedRegion = self.displayedRegions[index + idx];
|
|
1272
|
+
this.moveTo({
|
|
1273
|
+
index,
|
|
1274
|
+
offset: startDisplayedRegion.reversed
|
|
1275
|
+
? startDisplayedRegion.end - e
|
|
1276
|
+
: s - startDisplayedRegion.start,
|
|
1277
|
+
}, {
|
|
1278
|
+
index: index + idx,
|
|
1279
|
+
offset: endDisplayedRegion.reversed
|
|
1280
|
+
? endDisplayedRegion.end - start
|
|
1281
|
+
: end - endDisplayedRegion.start,
|
|
1282
|
+
});
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
catch (error) {
|
|
1286
|
+
if (index === lastIndex) {
|
|
1287
|
+
throw error;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
}
|
|
1291
|
+
},
|
|
1292
|
+
}))
|
|
1293
|
+
.views(self => ({
|
|
1294
|
+
/**
|
|
1295
|
+
* #method
|
|
1296
|
+
*/
|
|
1297
|
+
rubberBandMenuItems() {
|
|
1298
|
+
return [
|
|
1299
|
+
{
|
|
1300
|
+
label: 'Zoom to region',
|
|
1301
|
+
icon: ZoomIn_1.default,
|
|
1302
|
+
onClick: () => {
|
|
1303
|
+
const { leftOffset, rightOffset } = self;
|
|
1304
|
+
self.moveTo(leftOffset, rightOffset);
|
|
1305
|
+
},
|
|
1306
|
+
},
|
|
1307
|
+
{
|
|
1308
|
+
label: 'Get sequence',
|
|
1309
|
+
icon: MenuOpen_1.default,
|
|
1310
|
+
onClick: () => self.setGetSequenceDialogOpen(true),
|
|
1311
|
+
},
|
|
1312
|
+
];
|
|
1313
|
+
},
|
|
1314
|
+
/**
|
|
1315
|
+
* #method
|
|
1316
|
+
*/
|
|
1317
|
+
bpToPx({ refName, coord, regionNumber, }) {
|
|
1318
|
+
return (0, Base1DUtils_1.bpToPx)({ refName, coord, regionNumber, self });
|
|
1319
|
+
},
|
|
1320
|
+
/**
|
|
1321
|
+
* #method
|
|
1322
|
+
* scrolls the view to center on the given bp. if that is not in any
|
|
1323
|
+
* of the displayed regions, does nothing
|
|
1324
|
+
* @param coord - basepair at which you want to center the view
|
|
1325
|
+
* @param refName - refName of the displayedRegion you are centering at
|
|
1326
|
+
* @param regionNumber - index of the displayedRegion
|
|
1327
|
+
*/
|
|
1328
|
+
centerAt(coord, refName, regionNumber) {
|
|
1329
|
+
const centerPx = this.bpToPx({
|
|
1330
|
+
refName,
|
|
1331
|
+
coord,
|
|
1332
|
+
regionNumber,
|
|
1333
|
+
});
|
|
1334
|
+
if (centerPx) {
|
|
1335
|
+
self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2));
|
|
1336
|
+
}
|
|
1337
|
+
},
|
|
1338
|
+
/**
|
|
1339
|
+
* #method
|
|
1340
|
+
*/
|
|
1341
|
+
pxToBp(px) {
|
|
1342
|
+
return (0, Base1DUtils_1.pxToBp)(self, px);
|
|
1343
|
+
},
|
|
1344
|
+
/**
|
|
1345
|
+
* #getter
|
|
1346
|
+
*/
|
|
1347
|
+
get centerLineInfo() {
|
|
1348
|
+
return self.displayedRegions.length
|
|
1349
|
+
? this.pxToBp(self.width / 2)
|
|
1350
|
+
: undefined;
|
|
1351
|
+
},
|
|
1352
|
+
}));
|
|
1353
|
+
}
|
|
1354
|
+
exports.stateModelFactory = stateModelFactory;
|
|
1355
|
+
var LinearGenomeView_2 = require("./components/LinearGenomeView");
|
|
1356
|
+
Object.defineProperty(exports, "ReactComponent", { enumerable: true, get: function () { return __importDefault(LinearGenomeView_2).default; } });
|
|
1357
|
+
//# sourceMappingURL=model.js.map
|