UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

107 lines (106 loc) 5.1 kB
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; }