UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

105 lines (104 loc) 5.06 kB
import { getSnapshot, isStateTreeNode } from '@jbrowse/mobx-state-tree'; import { BlockSet, ContentBlock, ElidedBlock, InterRegionPaddingBlock, } from "./blockTypes.js"; import { assembleLocStringFast } from "./index.js"; import { intersection2 } from "./range.js"; export default function calculateDynamicBlocks(model, padding = true, elision = true) { const { offsetPx, displayedRegions, bpPerPx, width, minimumBlockWidth, interRegionPaddingWidth, } = model; if (!width) { throw new Error('view has no width, cannot calculate displayed blocks'); } const invBpPerPx = 1 / bpPerPx; const blocks = new BlockSet(); let displayedRegionLeftPx = 0; const windowLeftPx = offsetPx; const windowRightPx = windowLeftPx + width; for (let regionNumber = 0; regionNumber < displayedRegions.length; regionNumber++) { const region = displayedRegions[regionNumber]; const { assemblyName, refName, start: regionStart, end: regionEnd, reversed, } = region; const displayedRegionRightPx = displayedRegionLeftPx + (regionEnd - regionStart) * invBpPerPx; const regionWidthPx = (regionEnd - regionStart) * invBpPerPx; const parentRegion = isStateTreeNode(region) ? getSnapshot(region) : region; const [leftPx, rightPx] = intersection2(windowLeftPx, windowRightPx, displayedRegionLeftPx, displayedRegionRightPx); if (leftPx !== undefined && rightPx !== undefined) { let start; let end; let isLeftEndOfDisplayedRegion; let isRightEndOfDisplayedRegion; let blockOffsetPx; if (reversed) { start = Math.max(regionStart, regionEnd - (rightPx - displayedRegionLeftPx) * bpPerPx); end = regionEnd - (leftPx - displayedRegionLeftPx) * bpPerPx; isLeftEndOfDisplayedRegion = end === regionEnd; isRightEndOfDisplayedRegion = start === regionStart; blockOffsetPx = displayedRegionLeftPx + (regionEnd - end) * invBpPerPx; } else { start = (leftPx - displayedRegionLeftPx) * bpPerPx + regionStart; end = Math.min(regionEnd, (rightPx - displayedRegionLeftPx) * bpPerPx + regionStart); isLeftEndOfDisplayedRegion = start === regionStart; isRightEndOfDisplayedRegion = end === regionEnd; blockOffsetPx = displayedRegionLeftPx + (start - regionStart) * invBpPerPx; } const widthPx = (end - start) * invBpPerPx; const blockData = { assemblyName, refName, start, end, reversed, offsetPx: blockOffsetPx, parentRegion, regionNumber, widthPx, isLeftEndOfDisplayedRegion, isRightEndOfDisplayedRegion, key: `${assembleLocStringFast({ assemblyName, refName, start, end, reversed, })}-${regionNumber}${reversed ? '-reversed' : ''}`, }; if (padding && blocks.length === 0 && isLeftEndOfDisplayedRegion) { blocks.push(new InterRegionPaddingBlock({ key: `${blockData.key}-beforeFirstRegion`, widthPx: -offsetPx, offsetPx: blockData.offsetPx + offsetPx, 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) { blocks.push(new InterRegionPaddingBlock({ key: `${blockData.key}-rightpad`, widthPx: interRegionPaddingWidth, offsetPx: blockData.offsetPx + blockData.widthPx, })); displayedRegionLeftPx += interRegionPaddingWidth; } if (regionNumber === displayedRegions.length - 1 && blockData.isRightEndOfDisplayedRegion) { blockOffsetPx = blockData.offsetPx + blockData.widthPx; blocks.push(new InterRegionPaddingBlock({ key: `${blockData.key}-afterLastRegion`, widthPx: width - blockOffsetPx + offsetPx, offsetPx: blockOffsetPx, variant: 'boundary', })); } } } displayedRegionLeftPx += (regionEnd - regionStart) * invBpPerPx; } return blocks; }