UNPKG

@jbrowse/core

Version:

JBrowse 2 core libraries used by plugins

206 lines (205 loc) 6.5 kB
function lengthBetween(self, start, end) { let bpSoFar = 0; const { displayedRegions } = self; if (start.index === end.index) { bpSoFar += end.offset - start.offset; } else { const s = displayedRegions[start.index]; bpSoFar += s.end - s.start - start.offset; if (end.index - start.index >= 2) { for (let i = start.index + 1, l = end.index; i < l; i++) { const region = displayedRegions[i]; const len = region.end - region.start; bpSoFar += len; } } bpSoFar += end.offset; } return bpSoFar; } export function moveTo(self, start, end) { if (!start || !end) { return; } const { width, interRegionPaddingWidth, displayedRegions, bpPerPx, minimumBlockWidth, } = self; const len = lengthBetween(self, start, end); let numBlocksWideEnough = 0; for (let i = start.index, l = end.index; i < l; i++) { const r = displayedRegions[i]; if ((r.end - r.start) / bpPerPx > minimumBlockWidth) { numBlocksWideEnough++; } } const targetBpPerPx = len / (width - interRegionPaddingWidth * numBlocksWideEnough); const newBpPerPx = self.zoomTo(targetBpPerPx); let extraBp = 0; if (targetBpPerPx < newBpPerPx) { extraBp = ((newBpPerPx - targetBpPerPx) * self.width) / 2; } let bpToStart = -extraBp; for (let i = 0, l = displayedRegions.length; i < l; i++) { const region = displayedRegions[i]; if (start.index === i) { bpToStart += start.offset; break; } else { bpToStart += region.end - region.start; } } const scrollPos = Math.round(bpToStart / self.bpPerPx); self.scrollTo(scrollPos); } function coord(r, bp) { return Math.floor(r.reversed ? r.end - bp : r.start + bp) + 1; } export function pxToBp(self, px) { let bpSoFar = 0; const { bpPerPx, offsetPx, displayedRegions, interRegionPaddingWidth, staticBlocks, } = self; const blocks = staticBlocks.contentBlocks; const bp = (offsetPx + px) * bpPerPx; if (bp < 0) { const r = displayedRegions[0]; const snap = r; return { ...snap, oob: true, coord: coord(r, bp), offset: bp, index: 0, }; } const interRegionPaddingBp = interRegionPaddingWidth * bpPerPx; let currBlock = 0; for (let i = 0, l = displayedRegions.length; i < l; i++) { const r = displayedRegions[i]; const len = r.end - r.start; const offset = bp - bpSoFar; if (len + bpSoFar > bp && bpSoFar <= bp) { const snap = r; return { ...snap, oob: false, offset, coord: coord(r, offset), index: i, }; } if (blocks[currBlock]?.regionNumber === i) { const paddingStart = bpSoFar + len; const paddingEnd = paddingStart + interRegionPaddingBp; if (bp >= paddingStart && bp < paddingEnd && i + 1 < displayedRegions.length) { const nextR = displayedRegions[i + 1]; const snap = nextR; return { ...snap, oob: false, offset: 0, coord: coord(nextR, 0), index: i + 1, }; } bpSoFar += len + interRegionPaddingBp; currBlock++; } else { bpSoFar += len; } } if (bp >= bpSoFar && displayedRegions.length > 0) { const r = displayedRegions.at(-1); const len = r.end - r.start; const offset = bp - bpSoFar + len; const snap = r; return { ...snap, oob: true, offset, coord: coord(r, offset), index: displayedRegions.length - 1, }; } return { coord: 0, index: 0, refName: '', oob: true, assemblyName: '', offset: 0, start: 0, end: 0, reversed: false, }; } export function bpToPx({ refName, coord, regionNumber, self, }) { let bpSoFar = 0; const { interRegionPaddingWidth, bpPerPx, displayedRegions, staticBlocks } = self; const blocks = staticBlocks.contentBlocks; const interRegionPaddingBp = interRegionPaddingWidth * bpPerPx; let currBlock = 0; let i = 0; for (let l = displayedRegions.length; i < l; i++) { const r = displayedRegions[i]; const len = r.end - r.start; if (refName === r.refName && coord >= r.start && coord <= r.end && (regionNumber ? regionNumber === i : true)) { bpSoFar += r.reversed ? r.end - coord : coord - r.start; break; } if (blocks[currBlock]?.regionNumber === i) { bpSoFar += len + interRegionPaddingBp; currBlock++; } else { bpSoFar += len; } } const found = displayedRegions[i]; if (found) { return { index: i, offsetPx: Math.round(bpSoFar / bpPerPx), }; } return undefined; } export function bpToPxMap({ refName, coord, regionNumber, self, }) { let bpSoFar = 0; const { interRegionPaddingWidth, bpPerPx, displayedRegions, staticBlocks } = self; const blocks = staticBlocks.contentBlocks; const interRegionPaddingBp = interRegionPaddingWidth * bpPerPx; const map = {}; let currBlock = 0; let i = 0; for (let l = displayedRegions.length; i < l; i++) { const r = displayedRegions[i]; const len = r.end - r.start; if (refName === r.refName && coord >= r.start && coord <= r.end && (regionNumber === undefined ? true : regionNumber === i)) { bpSoFar += r.reversed ? r.end - coord : coord - r.start; break; } if (blocks[currBlock]?.regionNumber === i) { bpSoFar += len + interRegionPaddingBp; currBlock++; } else { bpSoFar += len; } } const found = displayedRegions[i]; if (found) { return { index: i, offsetPx: Math.round(bpSoFar / bpPerPx), }; } return map; }