UNPKG

@jbrowse/plugin-linear-genome-view

Version:

JBrowse 2 linear genome view

341 lines (340 loc) 13.5 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.BaseLinearDisplay = void 0; const react_1 = require("react"); const configuration_1 = require("@jbrowse/core/configuration"); const models_1 = require("@jbrowse/core/pluggableElementTypes/models"); const util_1 = require("@jbrowse/core/util"); const compositeMap_1 = __importDefault(require("@jbrowse/core/util/compositeMap")); const tracks_1 = require("@jbrowse/core/util/tracks"); const CenterFocusStrong_1 = __importDefault(require("@mui/icons-material/CenterFocusStrong")); const ContentCopy_1 = __importDefault(require("@mui/icons-material/ContentCopy")); const MenuOpen_1 = __importDefault(require("@mui/icons-material/MenuOpen")); const copy_to_clipboard_1 = __importDefault(require("copy-to-clipboard")); const mobx_1 = require("mobx"); const mobx_state_tree_1 = require("mobx-state-tree"); const FeatureDensityMixin_1 = __importDefault(require("./models/FeatureDensityMixin")); const TrackHeightMixin_1 = __importDefault(require("./models/TrackHeightMixin")); const configSchema_1 = __importDefault(require("./models/configSchema")); const serverSideRenderedBlock_1 = __importDefault(require("./models/serverSideRenderedBlock")); const Tooltip = (0, react_1.lazy)(() => Promise.resolve().then(() => __importStar(require('./components/Tooltip')))); function stateModelFactory() { return mobx_state_tree_1.types .compose('BaseLinearDisplay', models_1.BaseDisplay, (0, TrackHeightMixin_1.default)(), (0, FeatureDensityMixin_1.default)(), mobx_state_tree_1.types.model({ blockState: mobx_state_tree_1.types.map(serverSideRenderedBlock_1.default), configuration: (0, configuration_1.ConfigurationReference)(configSchema_1.default), })) .volatile(() => ({ mouseoverExtraInformation: undefined, featureIdUnderMouse: undefined, contextMenuFeature: undefined, })) .views(self => ({ get DisplayMessageComponent() { return undefined; }, get blockType() { return 'staticBlocks'; }, get blockDefinitions() { const view = (0, util_1.getContainingView)(self); if (!view.initialized) { throw new Error('view not initialized yet'); } return view[this.blockType]; }, })) .views(self => ({ get renderDelay() { return 50; }, get TooltipComponent() { return Tooltip; }, get selectedFeatureId() { if ((0, mobx_state_tree_1.isAlive)(self)) { const { selection } = (0, util_1.getSession)(self); if ((0, util_1.isFeature)(selection)) { return selection.id(); } } return undefined; }, copyInfoToClipboard(feature) { const { uniqueId, ...rest } = feature.toJSON(); const session = (0, util_1.getSession)(self); (0, copy_to_clipboard_1.default)(JSON.stringify(rest, null, 4)); session.notify('Copied to clipboard', 'success'); }, })) .views(self => ({ get features() { const featureMaps = []; for (const block of self.blockState.values()) { if (block.features) { featureMaps.push(block.features); } } return new compositeMap_1.default(featureMaps); }, get featureUnderMouse() { const feat = self.featureIdUnderMouse; return feat ? this.features.get(feat) : undefined; }, get layoutFeatures() { const featureMaps = []; for (const block of self.blockState.values()) { if (block.layout) { featureMaps.push(block.layout.rectangles); } } return new compositeMap_1.default(featureMaps); }, getFeatureOverlapping(blockKey, x, y) { var _a, _b; return (_b = (_a = self.blockState.get(blockKey)) === null || _a === void 0 ? void 0 : _a.layout) === null || _b === void 0 ? void 0 : _b.getByCoord(x, y); }, getFeatureByID(blockKey, id) { var _a, _b; return (_b = (_a = self.blockState.get(blockKey)) === null || _a === void 0 ? void 0 : _a.layout) === null || _b === void 0 ? void 0 : _b.getByID(id); }, searchFeatureByID(id) { var _a; let ret; for (const block of self.blockState.values()) { const val = (_a = block.layout) === null || _a === void 0 ? void 0 : _a.getByID(id); if (val) { ret = val; } } return ret; }, })) .actions(self => ({ addBlock(key, block) { self.blockState.set(key, serverSideRenderedBlock_1.default.create({ key, region: block.toRegion(), })); }, deleteBlock(key) { self.blockState.delete(key); }, selectFeature(feature) { const session = (0, util_1.getSession)(self); if ((0, util_1.isSessionModelWithWidgets)(session)) { const { rpcManager } = session; const sessionId = (0, tracks_1.getRpcSessionId)(self); const track = (0, util_1.getContainingTrack)(self); const view = (0, util_1.getContainingView)(self); const adapterConfig = (0, configuration_1.getConf)(track, 'adapter'); (async () => { try { const descriptions = await rpcManager.call(sessionId, 'CoreGetMetadata', { adapterConfig, }); session.showWidget(session.addWidget('BaseFeatureWidget', 'baseFeature', { featureData: feature.toJSON(), view, track, descriptions, })); } catch (e) { console.error(e); (0, util_1.getSession)(e).notifyError(`${e}`, e); } })(); } if ((0, util_1.isSelectionContainer)(session)) { session.setSelection(feature); } }, navToFeature(feature) { const view = (0, util_1.getContainingView)(self); view.navTo({ refName: feature.get('refName'), start: feature.get('start'), end: feature.get('end'), }); }, clearFeatureSelection() { (0, util_1.getSession)(self).clearSelection(); }, setFeatureIdUnderMouse(feature) { self.featureIdUnderMouse = feature; }, setContextMenuFeature(feature) { self.contextMenuFeature = feature; }, setMouseoverExtraInformation(extra) { self.mouseoverExtraInformation = extra; }, })) .actions(self => { const { reload: superReload } = self; return { async reload() { self.setError(); self.setCurrStatsBpPerPx(0); self.clearFeatureDensityStats(); for (const val of self.blockState.values()) { val.doReload(); } superReload(); }, }; }) .views(self => ({ trackMenuItems() { return []; }, contextMenuItems() { const feat = self.contextMenuFeature; return feat ? [ { label: 'Open feature details', icon: MenuOpen_1.default, onClick: () => { self.selectFeature(feat); }, }, { label: 'Zoom to feature', icon: CenterFocusStrong_1.default, onClick: () => { self.navToFeature(feat); }, }, { label: 'Copy info to clipboard', icon: ContentCopy_1.default, onClick: () => { self.copyInfoToClipboard(feat); }, }, ] : []; }, renderProps() { return { ...(0, tracks_1.getParentRenderProps)(self), notReady: !self.featureDensityStatsReady, rpcDriverName: self.rpcDriverName, displayModel: self, onFeatureClick(_, featureId) { const f = featureId || self.featureIdUnderMouse; if (!f) { self.clearFeatureSelection(); } else { const feature = self.features.get(f); if (feature) { self.selectFeature(feature); } } }, onClick() { self.clearFeatureSelection(); }, onFeatureContextMenu(_, featureId) { const f = featureId || self.featureIdUnderMouse; if (!f) { self.clearFeatureSelection(); } else { self.setContextMenuFeature(self.features.get(f)); } }, onMouseMove(_, featureId, extra) { self.setFeatureIdUnderMouse(featureId); self.setMouseoverExtraInformation(extra); }, onMouseLeave(_) { self.setFeatureIdUnderMouse(undefined); self.setMouseoverExtraInformation(undefined); }, onContextMenu() { self.setContextMenuFeature(undefined); self.clearFeatureSelection(); }, }; }, })) .actions(self => ({ async renderSvg(opts) { const { renderBaseLinearDisplaySvg } = await Promise.resolve().then(() => __importStar(require('./models/renderSvg'))); return renderBaseLinearDisplaySvg(self, opts); }, afterAttach() { (0, mobx_state_tree_1.addDisposer)(self, (0, mobx_1.autorun)(() => { const blocksPresent = {}; const view = (0, util_1.getContainingView)(self); if (!view.initialized) { return; } for (const block of self.blockDefinitions.contentBlocks) { blocksPresent[block.key] = true; if (!self.blockState.has(block.key)) { self.addBlock(block.key, block); } } for (const key of self.blockState.keys()) { if (!blocksPresent[key]) { self.deleteBlock(key); } } })); }, })) .preProcessSnapshot(snap => { if (!snap) { return snap; } const { height, ...rest } = snap; return { heightPreConfig: height, ...rest }; }) .postProcessSnapshot(snap => { const r = snap; const { blockState, ...rest } = r; return rest; }); } exports.BaseLinearDisplay = stateModelFactory();