Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | 2x 11x 11x 11x 11x 11x 11x 11x 11x 2x 82x 82x 82x 2x 3x 3x | /**
* A turned block as the map panel hands it to the renderer and reads it back
* (§17).
*
* `render/rotate.ts` is the rotation itself — where a contact goes, which pair
* of bins a turned cell came from — and is written against nothing but its own
* block. `render/heatmap.ts` draws a dense block in a box and knows of a turn
* only the numbers it is handed for its guides. Between the two sit three small
* facts the panel needs of every block it turns: the band as the ordinary dense
* matrix the renderer takes, which edge of its box the band stands on, and where
* a cell of it stands on the genomic axis. They are here rather than in either
* neighbour because each would then have to speak the other's vocabulary: the
* rotation would need the renderer's anchor type, and the renderer already
* imports the rotation for its guides.
*
* Pure — no DOM, no canvas, no panel — which is why it is not in
* `ui/MatrixPanel.ts`, where it used to be: the tests that pin these import a
* function of one argument, and should not have to import a panel to reach it.
*/
import type { DenseMatrix } from '../types'
import type { VerticalAnchor } from './heatmap'
import type { RotatedBlock } from './rotate'
/** The band, as an ordinary dense block the renderer can be handed. */
export function turnedDense(turned: RotatedBlock): DenseMatrix {
return {
nrows: turned.nrows,
ncols: turned.ncols,
values: turned.values,
// The band's own extents, in the half-bin units its columns are counted in,
// so anything downstream that measures a span in cells measures it in the
// grid actually on screen.
rowExtent: [0, turned.nrows],
colExtent: [turned.originBin * 2, turned.originBin * 2 + turned.ncols],
}
}
/**
* Which edge of its box a turned block is pinned to — see the caller for why it
* is pinned at all.
*
* `middle` for a square map, which is centred like any picture, and for a
* **mirrored pair**, whose diagonal is the line down the middle of it rather
* than either edge. `end` and `start` are the one-band cases, standing on
* whichever edge their own diagonal is.
*
* Exported for the test: the whole of the bug it fixes is invisible until a
* band is deeper than its box, which is two zooms away from any state a test
* can set up directly.
*/
export function anchorFor(turned: RotatedBlock | null): VerticalAnchor {
if (turned === null || turned.fold !== undefined) return 'middle'
return turned.direction === 'down' ? 'start' : 'end'
}
/**
* Where a cell of a turned map stands on the genomic axis, in cells of the
* square block it was turned out of.
*
* The **midpoint** of the pair it is a contact between, which is what a turned
* column is: the rotation puts the cell for `(i, j)` over `(i + j) / 2` and its
* height carries the rest (`render/rotate.ts`). Half-integers are the ordinary
* case rather than an edge one — a column is half a bin — and are passed on
* rather than rounded, since the arithmetic below them is linear and the reader
* is being told a position, not a bin.
*/
export function alongAxis(square: { row: number; col: number }): number {
return (square.row + square.col) / 2
}
|