UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

130 lines (129 loc) 3.81 kB
import { cast, types } from '@jbrowse/mobx-state-tree'; import { bpToPx, moveTo, pxToBp } from "./Base1DUtils.js"; import calculateDynamicBlocks from "./calculateDynamicBlocks.js"; import calculateStaticBlocks from "./calculateStaticBlocks.js"; import { clamp, sum } from "./index.js"; import { ElementId } from "./types/mst.js"; function x() { } const Base1DView = types .model('Base1DView', { id: ElementId, displayedRegions: types.optional(types.frozen(), []), bpPerPx: 0, offsetPx: 0, interRegionPaddingWidth: types.optional(types.number, 0), minimumBlockWidth: types.optional(types.number, 0), }) .volatile(() => ({ features: undefined, volatileWidth: 0, })) .actions(self => ({ setDisplayedRegions(regions) { self.displayedRegions = cast(regions); }, setBpPerPx(val) { self.bpPerPx = val; }, setVolatileWidth(width) { self.volatileWidth = width; }, })) .views(self => ({ get width() { return self.volatileWidth; }, get assemblyNames() { return [...new Set(self.displayedRegions.map(r => r.assemblyName))]; }, get displayedRegionsTotalPx() { return this.totalBp / self.bpPerPx; }, get maxOffset() { const leftPadding = 10; return this.displayedRegionsTotalPx - leftPadding; }, get minOffset() { const rightPadding = 30; return -this.width + rightPadding; }, get totalBp() { return sum(self.displayedRegions.map(a => a.end - a.start)); }, })) .views(self => ({ get dynamicBlocks() { return calculateDynamicBlocks(self); }, get staticBlocks() { return calculateStaticBlocks(self); }, get currBp() { return sum(this.dynamicBlocks.map(a => a.end - a.start)); }, })) .views(self => ({ pxToBp(px) { return pxToBp(self, px); }, bpToPx({ refName, coord, regionNumber, }) { return bpToPx({ refName, coord, regionNumber, self })?.offsetPx; }, })) .actions(self => ({ setFeatures(features) { self.features = features; }, showAllRegions() { self.bpPerPx = self.totalBp / self.width; self.offsetPx = 0; }, zoomOut() { this.zoomTo(self.bpPerPx * 2); }, zoomIn() { this.zoomTo(self.bpPerPx / 2); }, zoomTo(bpPerPx, offset = self.width / 2) { const newBpPerPx = clamp(bpPerPx, 'minBpPerPx' in self ? self.minBpPerPx : 0, 'maxBpPerPx' in self ? self.maxBpPerPx : Number.POSITIVE_INFINITY); const oldBpPerPx = self.bpPerPx; if (Math.abs(oldBpPerPx - newBpPerPx) < 0.000001) { return oldBpPerPx; } self.bpPerPx = newBpPerPx; self.offsetPx = clamp(Math.round(((self.offsetPx + offset) * oldBpPerPx) / newBpPerPx - offset), self.minOffset, self.maxOffset); return self.bpPerPx; }, scrollTo(offsetPx) { const newOffsetPx = clamp(offsetPx, self.minOffset, self.maxOffset); self.offsetPx = newOffsetPx; return newOffsetPx; }, centerAt(coord, refName, regionNumber) { if (!refName) { return; } const centerPx = self.bpToPx({ refName, coord, regionNumber, }); if (centerPx) { this.scrollTo(Math.round(centerPx - self.width / 2)); } }, scroll(distance) { const oldOffsetPx = self.offsetPx; const newOffsetPx = clamp(self.offsetPx + distance, self.minOffset, self.maxOffset); self.offsetPx = newOffsetPx; return newOffsetPx - oldOffsetPx; }, })) .actions(self => ({ moveTo(start, end) { moveTo(self, start, end); }, })); export default Base1DView;