@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
130 lines (129 loc) • 3.81 kB
JavaScript
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;