UNPKG

@jbrowse/plugin-linear-genome-view

Version:

JBrowse 2 linear genome view

1,110 lines (1,109 loc) 48.3 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.renderToSvg = exports.SearchBox = exports.RefNameAutocomplete = exports.ReactComponent = exports.LinearGenomeView = void 0; exports.stateModelFactory = stateModelFactory; const react_1 = require("react"); const configuration_1 = require("@jbrowse/core/configuration"); const models_1 = require("@jbrowse/core/pluggableElementTypes/models"); const ui_1 = require("@jbrowse/core/ui"); const Icons_1 = require("@jbrowse/core/ui/Icons"); const util_1 = require("@jbrowse/core/util"); const Base1DUtils_1 = require("@jbrowse/core/util/Base1DUtils"); const Base1DViewModel_1 = __importDefault(require("@jbrowse/core/util/Base1DViewModel")); const calculateDynamicBlocks_1 = __importDefault(require("@jbrowse/core/util/calculateDynamicBlocks")); const calculateStaticBlocks_1 = __importDefault(require("@jbrowse/core/util/calculateStaticBlocks")); const tracks_1 = require("@jbrowse/core/util/tracks"); const mst_1 = require("@jbrowse/core/util/types/mst"); const product_core_1 = require("@jbrowse/product-core"); const FolderOpen_1 = __importDefault(require("@mui/icons-material/FolderOpen")); const Label_1 = __importDefault(require("@mui/icons-material/Label")); const MenuOpen_1 = __importDefault(require("@mui/icons-material/MenuOpen")); const Palette_1 = __importDefault(require("@mui/icons-material/Palette")); const PhotoCamera_1 = __importDefault(require("@mui/icons-material/PhotoCamera")); const Search_1 = __importDefault(require("@mui/icons-material/Search")); const SyncAlt_1 = __importDefault(require("@mui/icons-material/SyncAlt")); const Visibility_1 = __importDefault(require("@mui/icons-material/Visibility")); const ZoomIn_1 = __importDefault(require("@mui/icons-material/ZoomIn")); const file_saver_1 = require("file-saver"); const mobx_1 = require("mobx"); const mobx_state_tree_1 = require("mobx-state-tree"); const Header_1 = __importDefault(require("./components/Header")); const util_2 = require("./util"); const searchUtils_1 = require("../searchUtils"); const MiniControls_1 = __importDefault(require("./components/MiniControls")); const consts_1 = require("./consts"); const ReturnToImportFormDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('@jbrowse/core/ui/ReturnToImportFormDialog')))); const SequenceSearchDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SequenceSearchDialog')))); const ExportSvgDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/ExportSvgDialog')))); const GetSequenceDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/GetSequenceDialog')))); const SearchResultsDialog = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/SearchResultsDialog')))); function stateModelFactory(pluginManager) { return mobx_state_tree_1.types .compose('LinearGenomeView', models_1.BaseViewModel, mobx_state_tree_1.types.model({ id: mst_1.ElementId, type: mobx_state_tree_1.types.literal('LinearGenomeView'), offsetPx: 0, bpPerPx: 1, displayedRegions: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.frozen(), []), tracks: mobx_state_tree_1.types.array(pluginManager.pluggableMstType('track', 'stateModel')), hideHeader: false, hideHeaderOverview: false, hideNoTracksActive: false, trackSelectorType: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.enumeration(['hierarchical']), 'hierarchical'), showCenterLine: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-showCenterLine', false)), showCytobandsSetting: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-showCytobands', true)), trackLabels: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.string, () => (0, util_1.localStorageGetItem)('lgv-trackLabels') || ''), showGridlines: true, highlight: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.array(mobx_state_tree_1.types.frozen()), []), colorByCDS: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-colorByCDS', false)), showTrackOutlines: mobx_state_tree_1.types.optional(mobx_state_tree_1.types.boolean, () => (0, util_1.localStorageGetBoolean)('lgv-showTrackOutlines', true)), init: mobx_state_tree_1.types.frozen(), })) .volatile(() => ({ volatileWidth: undefined, minimumBlockWidth: 3, draggingTrackId: undefined, volatileError: undefined, afterDisplayedRegionsSetCallbacks: [], scaleFactor: 1, trackRefs: {}, coarseDynamicBlocks: [], coarseTotalBp: 0, leftOffset: undefined, rightOffset: undefined, })) .views(self => ({ get pinnedTracks() { return self.tracks.filter(t => t.pinned); }, get unpinnedTracks() { return self.tracks.filter(t => !t.pinned); }, get trackLabelsSetting() { const sessionSetting = (0, configuration_1.getConf)((0, util_1.getSession)(self), [ 'LinearGenomeViewPlugin', 'trackLabels', ]); return self.trackLabels || sessionSetting; }, get width() { if (self.volatileWidth === undefined) { throw new Error('width undefined, make sure to check for model.initialized'); } return self.volatileWidth; }, get interRegionPaddingWidth() { return consts_1.INTER_REGION_PADDING_WIDTH; }, get assemblyNames() { return [ ...new Set(self.displayedRegions.map(region => region.assemblyName)), ]; }, get assemblyDisplayNames() { const { assemblyManager } = (0, util_1.getSession)(self); return this.assemblyNames.map(assemblyName => { var _a; const assembly = assemblyManager.get(assemblyName); return (_a = assembly === null || assembly === void 0 ? void 0 : assembly.displayName) !== null && _a !== void 0 ? _a : assemblyName; }); }, get isTopLevelView() { const session = (0, util_1.getSession)(self); return session.views.some(r => r.id === self.id); }, get stickyViewHeaders() { const session = (0, util_1.getSession)(self); return (0, product_core_1.isSessionWithMultipleViews)(session) ? this.isTopLevelView && session.stickyViewHeaders : false; }, get rubberbandTop() { let pinnedTracksTop = 0; if (this.stickyViewHeaders) { pinnedTracksTop = ui_1.VIEW_HEADER_HEIGHT; if (!self.hideHeader) { pinnedTracksTop += consts_1.HEADER_BAR_HEIGHT; if (!self.hideHeaderOverview) { pinnedTracksTop += consts_1.HEADER_OVERVIEW_HEIGHT; } } } return pinnedTracksTop; }, get pinnedTracksTop() { return this.rubberbandTop + consts_1.SCALE_BAR_HEIGHT; }, })) .views(self => ({ scaleBarDisplayPrefix() { return (0, mobx_state_tree_1.getParent)(self, 2).type === 'LinearSyntenyView' ? self.assemblyDisplayNames[0] : ''; }, MiniControlsComponent() { return MiniControls_1.default; }, HeaderComponent() { return Header_1.default; }, get assembliesNotFound() { const { assemblyManager } = (0, util_1.getSession)(self); const r0 = self.assemblyNames .map(a => (!assemblyManager.get(a) ? a : undefined)) .filter(f => !!f) .join(','); return r0 ? `Assemblies ${r0} not found` : undefined; }, get assemblyErrors() { const { assemblyManager } = (0, util_1.getSession)(self); return self.assemblyNames .map(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.error; }) .filter(f => !!f) .join(', '); }, get assembliesInitialized() { const { assemblyManager } = (0, util_1.getSession)(self); return self.assemblyNames.every(a => { var _a; return (_a = assemblyManager.get(a)) === null || _a === void 0 ? void 0 : _a.initialized; }); }, get initialized() { return self.volatileWidth !== undefined && this.assembliesInitialized; }, get hasDisplayedRegions() { return self.displayedRegions.length > 0; }, get scaleBarHeight() { return consts_1.SCALE_BAR_HEIGHT + consts_1.RESIZE_HANDLE_HEIGHT; }, get headerHeight() { if (self.hideHeader) { return 0; } else if (self.hideHeaderOverview) { return consts_1.HEADER_BAR_HEIGHT; } else { return consts_1.HEADER_BAR_HEIGHT + consts_1.HEADER_OVERVIEW_HEIGHT; } }, get trackHeights() { return (0, util_1.sum)(self.tracks.map(t => t.displays[0].height)); }, get trackHeightsWithResizeHandles() { return this.trackHeights + self.tracks.length * consts_1.RESIZE_HANDLE_HEIGHT; }, get height() { return (this.trackHeightsWithResizeHandles + this.headerHeight + this.scaleBarHeight); }, get totalBp() { return (0, util_1.sum)(self.displayedRegions.map(r => r.end - r.start)); }, get maxBpPerPx() { return this.totalBp / (self.width * 0.9); }, get minBpPerPx() { return 1 / 50; }, get error() { return (self.volatileError || this.assemblyErrors || this.assembliesNotFound); }, get maxOffset() { const leftPadding = 10; return this.displayedRegionsTotalPx - leftPadding; }, get minOffset() { const rightPadding = 30; return -self.width + rightPadding; }, get displayedRegionsTotalPx() { return this.totalBp / self.bpPerPx; }, renderProps() { return { ...(0, tracks_1.getParentRenderProps)(self), bpPerPx: self.bpPerPx, colorByCDS: self.colorByCDS, }; }, searchScope(assemblyName) { return { assemblyName, includeAggregateIndexes: true, tracks: self.tracks, }; }, getTrack(id) { return self.tracks.find(t => t.configuration.trackId === id); }, rankSearchResults(results) { return results; }, rewriteOnClicks(trackType, viewMenuActions) { for (const action of viewMenuActions) { if ('subMenu' in action) { this.rewriteOnClicks(trackType, action.subMenu); } if ('onClick' in action) { const holdOnClick = action.onClick; action.onClick = (...args) => { for (const track of self.tracks) { if (track.type === trackType) { holdOnClick.apply(track, [track, ...args]); } } }; } } }, get trackTypeActions() { const allActions = new Map(); for (const track of self.tracks) { const trackInMap = allActions.get(track.type); if (!trackInMap) { const viewMenuActions = structuredClone(track.viewMenuActions); this.rewriteOnClicks(track.type, viewMenuActions); allActions.set(track.type, viewMenuActions); } } return allActions; }, })) .actions(self => ({ setShowTrackOutlines(arg) { self.showTrackOutlines = arg; }, setColorByCDS(flag) { self.colorByCDS = flag; }, setShowCytobands(flag) { self.showCytobandsSetting = flag; }, setWidth(newWidth) { self.volatileWidth = newWidth; }, setError(error) { self.volatileError = error; }, setHideHeader(b) { self.hideHeader = b; }, setHideHeaderOverview(b) { self.hideHeaderOverview = b; }, setHideNoTracksActive(b) { self.hideNoTracksActive = b; }, setShowGridlines(b) { self.showGridlines = b; }, addToHighlights(highlight) { self.highlight.push(highlight); }, setHighlight(highlight) { self.highlight = (0, mobx_state_tree_1.cast)(highlight); }, removeHighlight(highlight) { self.highlight.remove(highlight); }, scrollTo(offsetPx) { const newOffsetPx = (0, util_1.clamp)(offsetPx, self.minOffset, self.maxOffset); self.offsetPx = newOffsetPx; return newOffsetPx; }, zoomTo(bpPerPx, offset = self.width / 2, centerAtOffset = false) { const newBpPerPx = (0, util_1.clamp)(bpPerPx, self.minBpPerPx, self.maxBpPerPx); if (newBpPerPx === self.bpPerPx) { return newBpPerPx; } const oldBpPerPx = self.bpPerPx; if (Math.abs(oldBpPerPx - newBpPerPx) < 0.000001) { console.warn('zoomTo bpPerPx rounding error'); return oldBpPerPx; } self.bpPerPx = newBpPerPx; this.scrollTo(Math.round(((self.offsetPx + offset) * oldBpPerPx) / newBpPerPx - (centerAtOffset ? self.width / 2 : offset))); return newBpPerPx; }, setOffsets(left, right) { self.leftOffset = left; self.rightOffset = right; }, setSearchResults(searchResults, searchQuery, assemblyName) { (0, util_1.getSession)(self).queueDialog(handleClose => [ SearchResultsDialog, { model: self, searchResults, searchQuery, handleClose, assemblyName, }, ]); }, setNewView(bpPerPx, offsetPx) { this.zoomTo(bpPerPx); this.scrollTo(offsetPx); }, horizontallyFlip() { self.displayedRegions = (0, mobx_state_tree_1.cast)([...self.displayedRegions] .reverse() .map(region => ({ ...region, reversed: !region.reversed }))); this.scrollTo(self.totalBp / self.bpPerPx - self.offsetPx - self.width); }, showTrack(trackId, initialSnapshot = {}, displayInitialSnapshot = {}) { const schema = pluginManager.pluggableConfigSchemaType('track'); const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId); if (!conf) { throw new Error(`Could not resolve identifier "${trackId}"`); } const trackType = pluginManager.getTrackType(conf === null || conf === void 0 ? void 0 : conf.type); if (!trackType) { throw new Error(`Unknown track type ${conf.type}`); } const viewType = pluginManager.getViewType(self.type); const supportedDisplays = new Set(viewType.displayTypes.map(d => d.name)); const displayConf = conf.displays.find((d) => supportedDisplays.has(d.type)); if (!displayConf) { throw new Error(`Could not find a compatible display for view type ${self.type}`); } const t = self.tracks.filter(t => t.configuration === conf); if (t.length === 0) { const track = trackType.stateModel.create({ ...initialSnapshot, type: conf.type, configuration: conf, displays: [ { type: displayConf.type, configuration: displayConf, ...displayInitialSnapshot, }, ], }); self.tracks.push(track); return track; } return t[0]; }, hideTrack(trackId) { const schema = pluginManager.pluggableConfigSchemaType('track'); const conf = (0, mobx_state_tree_1.resolveIdentifier)(schema, (0, mobx_state_tree_1.getRoot)(self), trackId); const tracks = self.tracks.filter(t => t.configuration === conf); (0, mobx_1.transaction)(() => { for (const track of tracks) { self.tracks.remove(track); } }); return tracks.length; }, })) .actions(self => ({ moveTrackDown(id) { const idx = self.tracks.findIndex(v => v.id === id); if (idx === -1) { return; } if (idx !== -1 && idx < self.tracks.length - 1) { self.tracks.splice(idx, 2, self.tracks[idx + 1], self.tracks[idx]); } }, moveTrackUp(id) { const idx = self.tracks.findIndex(track => track.id === id); if (idx > 0) { self.tracks.splice(idx - 1, 2, self.tracks[idx], self.tracks[idx - 1]); } }, moveTrackToTop(id) { const idx = self.tracks.findIndex(track => track.id === id); self.tracks = (0, mobx_state_tree_1.cast)([ self.tracks[idx], ...self.tracks.filter(track => track.id !== id), ]); }, moveTrackToBottom(id) { const idx = self.tracks.findIndex(track => track.id === id); self.tracks = (0, mobx_state_tree_1.cast)([ ...self.tracks.filter(track => track.id !== id), self.tracks[idx], ]); }, moveTrack(movingId, targetId) { const oldIndex = self.tracks.findIndex(track => track.id === movingId); if (oldIndex === -1) { throw new Error(`Track ID ${movingId} not found`); } const newIndex = self.tracks.findIndex(track => track.id === targetId); if (newIndex === -1) { throw new Error(`Track ID ${targetId} not found`); } const tracks = self.tracks.filter((_, idx) => idx !== oldIndex); tracks.splice(newIndex, 0, self.tracks[oldIndex]); self.tracks = (0, mobx_state_tree_1.cast)(tracks); }, toggleTrack(trackId) { const hiddenCount = self.hideTrack(trackId); if (!hiddenCount) { self.showTrack(trackId); return true; } return false; }, setTrackLabels(setting) { localStorage.setItem('lgv-trackLabels', setting); self.trackLabels = setting; }, setShowCenterLine(b) { self.showCenterLine = b; }, setDisplayedRegions(regions) { self.displayedRegions = (0, mobx_state_tree_1.cast)(regions); self.zoomTo(self.bpPerPx); }, activateTrackSelector() { if (self.trackSelectorType === 'hierarchical') { const session = (0, util_1.getSession)(self); if ((0, util_1.isSessionModelWithWidgets)(session)) { const selector = session.addWidget('HierarchicalTrackSelectorWidget', 'hierarchicalTrackSelector', { view: self }); session.showWidget(selector); return selector; } } throw new Error(`invalid track selector type ${self.trackSelectorType}`); }, getSelectedRegions(leftOffset, rightOffset) { const snap = (0, mobx_state_tree_1.getSnapshot)(self); const simView = Base1DViewModel_1.default.create({ ...snap, interRegionPaddingWidth: self.interRegionPaddingWidth, }); simView.setVolatileWidth(self.width); simView.moveTo(leftOffset, rightOffset); return simView.dynamicBlocks.contentBlocks.map(region => ({ ...region, start: Math.floor(region.start), end: Math.ceil(region.end), })); }, afterDisplayedRegionsSet(cb) { self.afterDisplayedRegionsSetCallbacks.push(cb); }, horizontalScroll(distance) { const oldOffsetPx = self.offsetPx; const newOffsetPx = self.scrollTo(self.offsetPx + distance); return newOffsetPx - oldOffsetPx; }, center() { const centerBp = self.totalBp / 2; const centerPx = centerBp / self.bpPerPx; self.scrollTo(Math.round(centerPx - self.width / 2)); }, showAllRegions() { self.zoomTo(self.maxBpPerPx); this.center(); }, showAllRegionsInAssembly(assemblyName) { const session = (0, util_1.getSession)(self); const { assemblyManager } = session; if (!assemblyName) { const names = new Set(self.displayedRegions.map(r => r.assemblyName)); if (names.size > 1) { session.notify(`Can't perform operation with multiple assemblies currently`); return; } ; [assemblyName] = [...names]; } const assembly = assemblyManager.get(assemblyName); if (assembly) { const { regions } = assembly; if (regions) { this.setDisplayedRegions(regions); self.zoomTo(self.maxBpPerPx); this.center(); } } }, setDraggingTrackId(idx) { self.draggingTrackId = idx; }, setScaleFactor(factor) { self.scaleFactor = factor; }, clearView() { this.setDisplayedRegions([]); self.tracks.clear(); self.scrollTo(0); self.zoomTo(10); }, setInit(arg) { self.init = arg; }, async exportSvg(opts = {}) { const { renderToSvg } = await Promise.resolve().then(() => __importStar(require('./svgcomponents/SVGLinearGenomeView'))); const html = await renderToSvg(self, opts); const blob = new Blob([html], { type: 'image/svg+xml' }); (0, file_saver_1.saveAs)(blob, opts.filename || 'image.svg'); }, })) .actions(self => { let cancelLastAnimation = () => { }; function slide(viewWidths) { const [animate, cancelAnimation] = (0, util_1.springAnimate)(self.offsetPx, self.offsetPx + self.width * viewWidths, self.scrollTo, undefined, undefined, 200); cancelLastAnimation(); cancelLastAnimation = cancelAnimation; animate(); } return { slide }; }) .actions(self => { let cancelLastAnimation = () => { }; function zoom(targetBpPerPx) { self.zoomTo(self.bpPerPx); if ((targetBpPerPx < self.bpPerPx && self.bpPerPx === self.minBpPerPx) || (targetBpPerPx > self.bpPerPx && self.bpPerPx === self.maxBpPerPx)) { return; } const factor = self.bpPerPx / targetBpPerPx; const [animate, cancelAnimation] = (0, util_1.springAnimate)(1, factor, self.setScaleFactor, () => { self.zoomTo(targetBpPerPx); self.setScaleFactor(1); }); cancelLastAnimation(); cancelLastAnimation = cancelAnimation; animate(); } return { zoom }; }) .views(self => ({ get canShowCytobands() { return self.displayedRegions.length === 1 && this.anyCytobandsExist; }, get showCytobands() { return this.canShowCytobands && self.showCytobandsSetting; }, get anyCytobandsExist() { const { assemblyManager } = (0, util_1.getSession)(self); 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; }); }, get cytobandOffset() { var _a; return this.showCytobands ? (0, util_1.measureText)(((_a = self.displayedRegions[0]) === null || _a === void 0 ? void 0 : _a.refName) || '', 12) + 15 : 0; }, })) .views(self => ({ menuItems() { const { canShowCytobands, showCytobands } = self; const session = (0, util_1.getSession)(self); const menuItems = [ { label: 'Return to import form', onClick: () => { (0, util_1.getSession)(self).queueDialog(handleClose => [ ReturnToImportFormDialog, { model: self, handleClose }, ]); }, icon: FolderOpen_1.default, }, ...((0, util_1.isSessionWithAddTracks)(session) ? [ { label: 'Sequence search', icon: Search_1.default, onClick: () => { (0, util_1.getSession)(self).queueDialog(handleClose => [ SequenceSearchDialog, { model: self, handleClose, }, ]); }, }, ] : []), { label: 'Export SVG', icon: PhotoCamera_1.default, onClick: () => { (0, util_1.getSession)(self).queueDialog(handleClose => [ ExportSvgDialog, { model: self, handleClose, }, ]); }, }, { label: 'Open track selector', onClick: self.activateTrackSelector, icon: Icons_1.TrackSelector, }, { label: 'Horizontally flip', icon: SyncAlt_1.default, onClick: self.horizontallyFlip, }, { label: 'Color by CDS and draw amino acids', type: 'checkbox', checked: self.colorByCDS, icon: Palette_1.default, onClick: () => { self.setColorByCDS(!self.colorByCDS); }, }, { label: 'Show...', icon: Visibility_1.default, subMenu: [ { label: 'Show all regions in assembly', onClick: self.showAllRegionsInAssembly, }, { label: 'Show center line', type: 'checkbox', checked: self.showCenterLine, onClick: () => { self.setShowCenterLine(!self.showCenterLine); }, }, { label: 'Show header', type: 'checkbox', checked: !self.hideHeader, onClick: () => { self.setHideHeader(!self.hideHeader); }, }, { label: 'Show track outlines', type: 'checkbox', checked: self.showTrackOutlines, onClick: () => { self.setShowTrackOutlines(!self.showTrackOutlines); }, }, { label: 'Show header overview', type: 'checkbox', checked: !self.hideHeaderOverview, onClick: () => { self.setHideHeaderOverview(!self.hideHeaderOverview); }, disabled: self.hideHeader, }, { label: 'Show no tracks active button', type: 'checkbox', checked: !self.hideNoTracksActive, onClick: () => { self.setHideNoTracksActive(!self.hideNoTracksActive); }, }, { label: 'Show guidelines', type: 'checkbox', checked: self.showGridlines, onClick: () => { self.setShowGridlines(!self.showGridlines); }, }, ...(canShowCytobands ? [ { label: 'Show ideogram', type: 'checkbox', checked: self.showCytobands, onClick: () => { self.setShowCytobands(!showCytobands); }, }, ] : []), ], }, { label: 'Track labels', icon: Label_1.default, subMenu: [ { label: 'Overlapping', icon: Visibility_1.default, type: 'radio', checked: self.trackLabelsSetting === 'overlapping', onClick: () => { self.setTrackLabels('overlapping'); }, }, { label: 'Offset', icon: Visibility_1.default, type: 'radio', checked: self.trackLabelsSetting === 'offset', onClick: () => { self.setTrackLabels('offset'); }, }, { label: 'Hidden', icon: Visibility_1.default, type: 'radio', checked: self.trackLabelsSetting === 'hidden', onClick: () => { self.setTrackLabels('hidden'); }, }, ], }, ]; for (const [key, value] of self.trackTypeActions.entries()) { if (value.length) { menuItems.push({ type: 'divider' }, { type: 'subHeader', label: key }); for (const action of value) { menuItems.push(action); } } } return menuItems; }, })) .views(self => { let currentlyCalculatedStaticBlocks; let stringifiedCurrentlyCalculatedStaticBlocks = ''; return { get staticBlocks() { const ret = (0, calculateStaticBlocks_1.default)(self); const sret = JSON.stringify(ret); if (stringifiedCurrentlyCalculatedStaticBlocks !== sret) { currentlyCalculatedStaticBlocks = ret; stringifiedCurrentlyCalculatedStaticBlocks = sret; } return currentlyCalculatedStaticBlocks; }, get dynamicBlocks() { return (0, calculateDynamicBlocks_1.default)(self); }, get roundedDynamicBlocks() { return this.dynamicBlocks.contentBlocks.map(block => ({ ...block, start: Math.floor(block.start), end: Math.ceil(block.end), })); }, get visibleLocStrings() { return (0, util_2.calculateVisibleLocStrings)(this.dynamicBlocks.contentBlocks); }, get coarseVisibleLocStrings() { return (0, util_2.calculateVisibleLocStrings)(self.coarseDynamicBlocks); }, }; }) .actions(self => ({ setCoarseDynamicBlocks(blocks) { self.coarseDynamicBlocks = blocks.contentBlocks; self.coarseTotalBp = blocks.totalBp; }, })) .actions(self => ({ moveTo(start, end) { (0, Base1DUtils_1.moveTo)(self, start, end); }, async navToLocString(input, optAssemblyName, grow) { const { assemblyNames } = self; const { assemblyManager } = (0, util_1.getSession)(self); const assemblyName = optAssemblyName || assemblyNames[0]; if (assemblyName) { await assemblyManager.waitForAssembly(assemblyName); } return this.navToLocations((0, util_2.parseLocStrings)(input, assemblyName, (ref, asm) => assemblyManager.isValidRefName(ref, asm)), assemblyName, grow); }, async navToSearchString({ input, assembly, }) { await (0, searchUtils_1.handleSelectedRegion)({ input, assembly, model: self, }); }, async navToLocation(parsedLocString, assemblyName, grow) { return this.navToLocations([parsedLocString], assemblyName, grow); }, async navToLocations(regions, assemblyName, grow) { const { assemblyManager } = (0, util_1.getSession)(self); await (0, mobx_1.when)(() => self.volatileWidth !== undefined); const locations = await (0, util_2.generateLocations)({ regions, assemblyManager, assemblyName, grow, }); if (locations.length === 1) { const location = locations[0]; const { reversed, parentRegion, start, end } = location; self.setDisplayedRegions([ { reversed, ...parentRegion, }, ]); this.navTo({ ...location, start: (0, util_1.clamp)(start !== null && start !== void 0 ? start : 0, 0, parentRegion.end), end: (0, util_1.clamp)(end !== null && end !== void 0 ? end : parentRegion.end, 0, parentRegion.end), }); } else { self.setDisplayedRegions(locations.map(location => { const { start, end } = location; return start === undefined || end === undefined ? location.parentRegion : { ...location, start, end, }; })); self.showAllRegions(); } }, navTo(query) { this.navToMultiple([query]); }, navToMultiple(locations) { if (locations.some(l => l.start !== undefined && l.end !== undefined && l.start > l.end)) { throw new Error('found start greater than end'); } const firstLocation = locations.at(0); const lastLocation = locations.at(-1); if (!firstLocation || !lastLocation) { return; } const defaultAssemblyName = self.assemblyNames[0]; const { assemblyManager } = (0, util_1.getSession)(self); const firstAssembly = assemblyManager.get(firstLocation.assemblyName || defaultAssemblyName); const firstRefName = (firstAssembly === null || firstAssembly === void 0 ? void 0 : firstAssembly.getCanonicalRefName(firstLocation.refName)) || firstLocation.refName; const firstRegion = self.displayedRegions.find(r => r.refName === firstRefName); const lastAssembly = assemblyManager.get(lastLocation.assemblyName || defaultAssemblyName); const lastRefName = (lastAssembly === null || lastAssembly === void 0 ? void 0 : lastAssembly.getCanonicalRefName(lastLocation.refName)) || lastLocation.refName; const lastRegion = (0, util_1.findLast)(self.displayedRegions, r => r.refName === lastRefName); if (!firstRegion) { throw new Error(`could not find a region with refName "${firstRefName}"`); } if (!lastRegion) { throw new Error(`could not find a region with refName "${lastRefName}"`); } const firstStart = firstLocation.start === undefined ? firstRegion.start : firstLocation.start; const firstEnd = firstLocation.end === undefined ? firstRegion.end : firstLocation.end; const lastStart = lastLocation.start === undefined ? lastRegion.start : lastLocation.start; const lastEnd = lastLocation.end === undefined ? lastRegion.end : lastLocation.end; const firstIndex = self.displayedRegions.findIndex(r => firstRefName === r.refName && firstStart >= r.start && firstStart <= r.end && firstEnd <= r.end && firstEnd >= r.start); const lastIndex = self.displayedRegions.findIndex(r => lastRefName === r.refName && lastStart >= r.start && lastStart <= r.end && lastEnd <= r.end && lastEnd >= r.start); if (firstIndex === -1 || lastIndex === -1) { throw new Error(`could not find a region that contained "${locations.map(l => (0, util_1.assembleLocString)(l))}"`); } const startDisplayedRegion = self.displayedRegions[firstIndex]; const endDisplayedRegion = self.displayedRegions[lastIndex]; const startOffset = startDisplayedRegion.reversed ? startDisplayedRegion.end - firstEnd : firstStart - startDisplayedRegion.start; const endOffset = endDisplayedRegion.reversed ? endDisplayedRegion.end - lastStart : lastEnd - endDisplayedRegion.start; this.moveTo({ index: firstIndex, offset: startOffset, }, { index: lastIndex, offset: endOffset, }); }, })) .views(self => ({ rubberBandMenuItems() { return [ { label: 'Zoom to region', icon: ZoomIn_1.default, onClick: () => { self.moveTo(self.leftOffset, self.rightOffset); }, }, { label: 'Get sequence', icon: MenuOpen_1.default, onClick: () => { (0, util_1.getSession)(self).queueDialog(handleClose => [ GetSequenceDialog, { model: self, handleClose }, ]); }, }, ]; }, bpToPx({ refName, coord, regionNumber, }) { return (0, Base1DUtils_1.bpToPx)({ refName, coord, regionNumber, self }); }, centerAt(coord, refName, regionNumber) { const centerPx = this.bpToPx({ refName, coord, regionNumber, }); if (centerPx !== undefined) { self.scrollTo(Math.round(centerPx.offsetPx - self.width / 2)); } }, pxToBp(px) { return (0, Base1DUtils_1.pxToBp)(self, px); }, get centerLineInfo() { return self.displayedRegions.length > 0 ? this.pxToBp(self.width / 2) : undefined; }, })) .actions(self => ({ afterCreate() { function handler(e) { const session = (0, util_1.getSession)(self); if (session.focusedViewId === self.id && (e.ctrlKey || e.metaKey)) { if (e.code === 'ArrowLeft') { e.preventDefault(); self.slide(-0.9); } else if (e.code === 'ArrowRight') { e.preventDefault(); self.slide(0.9); } else if (e.code === 'ArrowUp' && self.scaleFactor === 1) { e.preventDefault(); self.zoom(self.bpPerPx / 2); } else if (e.code === 'ArrowDown' && self.scaleFactor === 1) { e.preventDefault(); self.zoom(self.bpPerPx * 2); } } } document.addEventListener('keydown', handler); (0, mobx_state_tree_1.addDisposer)(self, () => { document.removeEventListener('keydown', handler); }); }, afterAttach() { (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => { var _a; const { init } = self; if (init) { self .navToLocString(init.loc, init.assembly) .catch((e) => { console.error(init, e); (0, util_1.getSession)(self).notifyError(`${e}`, e); }); (_a = init.tracks) === null || _a === void 0 ? void 0 : _a.map(t => self.showTrack(t)); self.setInit(undefined); } })); (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => { if (self.initialized) { self.setCoarseDynamicBlocks(self.dynamicBlocks); } }, { delay: 150 })); (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => { const s = (s) => JSON.stringify(s); const { showCytobandsSetting, showCenterLine, colorByCDS } = self; (0, util_1.localStorageSetItem)('lgv-showCytobands', s(showCytobandsSetting)); (0, util_1.localStorageSetItem)('lgv-showCenterLine', s(showCenterLine)); (0, util_1.localStorageSetItem)('lgv-colorByCDS', s(colorByCDS)); })); }, })) .preProcessSnapshot(snap => { if (!snap) { return snap; } const { highlight, ...rest } = snap; return { highlight: Array.isArray(highlight) || highlight === undefined ? highlight : [highlight], ...rest, }; }) .postProcessSnapshot(snap => { if (!snap) { return snap; } else { const { init, ...rest } = snap; return rest; } }); } var LinearGenomeView_1 = require("./components/LinearGenomeView"); Object.defineProperty(exports, "LinearGenomeView", { enumerable: true, get: function () { return __importDefault(LinearGenomeView_1).default; } }); Object.defineProperty(exports, "ReactComponent", { enumerable: true, get: function () { return __importDefault(LinearGenomeView_1).default; } }); var RefNameAutocomplete_1 = require("./components/RefNameAutocomplete"); Object.defineProperty(exports, "RefNameAutocomplete", { enumerable: true, get: function () { return __importDefault(RefNameAutocomplete_1).default; } }); var SearchBox_1 = require("./components/SearchBox"); Object.defineProperty(exports, "SearchBox", { enumerable: true, get: function () { return __importDefault(SearchBox_1).default; } }); var SVGLinearGenomeView_1 = require("./svgcomponents/SVGLinearGenomeView"); Object.defineProperty(exports, "renderToSvg", { enumerable: true, get: function () { return SVGLinearGenomeView_1.renderToSvg; } });