@jbrowse/core
Version:
JBrowse 2 core libraries used by plugins
107 lines (106 loc) • 5.1 kB
JavaScript
import { getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree';
import { BlockSet, ContentBlock, ElidedBlock, InterRegionPaddingBlock, } from "./blockTypes.js";
import { assembleLocStringFast } from "./index.js";
export default function calculateStaticBlocks(model, padding = true, elision = true, extra = 0, width = 800) {
const { offsetPx, displayedRegions, bpPerPx, minimumBlockWidth, interRegionPaddingWidth, width: modelWidth, } = model;
const windowLeftBp = offsetPx * bpPerPx;
const windowRightBp = (offsetPx + modelWidth) * bpPerPx;
const blockSizePx = width;
const blockSizeBp = Math.ceil(blockSizePx * bpPerPx);
const invBpPerPx = 1 / bpPerPx;
const invBlockSizeBp = 1 / blockSizeBp;
let regionBpOffset = 0;
const blocks = new BlockSet();
for (let regionNumber = 0; regionNumber < displayedRegions.length; regionNumber++) {
const region = displayedRegions[regionNumber];
const { assemblyName, refName, start: regionStart, end: regionEnd, reversed, } = region;
const regionBlockCount = Math.ceil((regionEnd - regionStart) * invBlockSizeBp);
const parentRegion = isStateTreeNode(region) ? getSnapshot(region) : region;
let windowRightBlockNum = Math.floor((windowRightBp - regionBpOffset) * invBlockSizeBp) + extra;
if (windowRightBlockNum >= regionBlockCount) {
windowRightBlockNum = regionBlockCount - 1;
}
let windowLeftBlockNum = Math.floor((windowLeftBp - regionBpOffset) * invBlockSizeBp) - extra;
if (windowLeftBlockNum < 0) {
windowLeftBlockNum = 0;
}
const regionWidthPx = (regionEnd - regionStart) * invBpPerPx;
for (let blockNum = windowLeftBlockNum; blockNum <= windowRightBlockNum; blockNum += 1) {
let start;
let end;
let isLeftEndOfDisplayedRegion;
let isRightEndOfDisplayedRegion;
if (reversed) {
start = Math.max(regionStart, regionEnd - (blockNum + 1) * blockSizeBp);
end = regionEnd - blockNum * blockSizeBp;
isLeftEndOfDisplayedRegion = end === regionEnd;
isRightEndOfDisplayedRegion = start === regionStart;
}
else {
start = regionStart + blockNum * blockSizeBp;
end = Math.min(regionEnd, regionStart + (blockNum + 1) * blockSizeBp);
isLeftEndOfDisplayedRegion = start === regionStart;
isRightEndOfDisplayedRegion = end === regionEnd;
}
const widthPx = (end - start) * invBpPerPx;
const blockData = {
assemblyName,
refName,
start,
end,
reversed,
offsetPx: (regionBpOffset + blockNum * blockSizeBp) * invBpPerPx,
parentRegion,
regionNumber,
widthPx,
isLeftEndOfDisplayedRegion,
isRightEndOfDisplayedRegion,
key: `${assembleLocStringFast({
assemblyName,
refName,
start,
end,
reversed,
})}-${regionNumber}${reversed ? '-reversed' : ''}`,
};
if (padding && regionNumber === 0 && blockNum === 0) {
blocks.push(new InterRegionPaddingBlock({
key: `${blockData.key}-beforeFirstRegion`,
widthPx: width,
offsetPx: blockData.offsetPx - width,
variant: 'boundary',
}));
}
if (elision && regionWidthPx < minimumBlockWidth) {
blocks.push(new ElidedBlock(blockData));
}
else {
blocks.push(new ContentBlock(blockData));
}
if (padding) {
if (regionWidthPx >= minimumBlockWidth &&
blockData.isRightEndOfDisplayedRegion &&
regionNumber < displayedRegions.length - 1) {
regionBpOffset += interRegionPaddingWidth * bpPerPx;
blocks.push(new InterRegionPaddingBlock({
key: `${blockData.key}-rightpad`,
widthPx: interRegionPaddingWidth,
offsetPx: blockData.offsetPx + blockData.widthPx,
}));
}
if (regionNumber === displayedRegions.length - 1 &&
blockData.isRightEndOfDisplayedRegion) {
regionBpOffset += interRegionPaddingWidth * bpPerPx;
blocks.push(new InterRegionPaddingBlock({
key: `${blockData.key}-afterLastRegion`,
widthPx: width,
offsetPx: blockData.offsetPx + blockData.widthPx,
variant: 'boundary',
}));
}
}
}
regionBpOffset += regionEnd - regionStart;
}
return blocks;
}