Skip to main content

Layouts and slice types

A viewer arranges its canvas into tiles: 2D slices, a 3D render, or both. You pick the arrangement with a few layout properties. Like every viewer setting, they can go in the constructor or be assigned later, and the view redraws.

import NiiVue, { MULTIPLANAR_TYPE, SLICE_TYPE } from '@niivue/niivue'

const mosaic = 'A -20 0 20 40 ; C -30 0 30 S R X 0'

const demo = async (canvas, { ui, asset }) => {
const nv = new NiiVue({ backgroundColor: [0.2, 0.2, 0.2, 1] })
await nv.attachToCanvas(canvas)
await nv.loadVolumes([{ url: asset('volumes/mni152.nii.gz') }])

ui.select(
'View',
[
['Axial', String(SLICE_TYPE.AXIAL)],
['Coronal', String(SLICE_TYPE.CORONAL)],
['Sagittal', String(SLICE_TYPE.SAGITTAL)],
['Multiplanar', String(SLICE_TYPE.MULTIPLANAR)],
['Render', String(SLICE_TYPE.RENDER)],
['Mosaic', 'mosaic'],
],
String(SLICE_TYPE.MULTIPLANAR),
(v) => {
if (v === 'mosaic') {
nv.mosaicString = mosaic
return
}
nv.mosaicString = ''
nv.sliceType = Number(v)
},
)
ui.select(
'Multiplanar',
[
['Auto', String(MULTIPLANAR_TYPE.AUTO)],
['Column', String(MULTIPLANAR_TYPE.COLUMN)],
['Grid', String(MULTIPLANAR_TYPE.GRID)],
['Row', String(MULTIPLANAR_TYPE.ROW)],
],
String(MULTIPLANAR_TYPE.AUTO),
(v) => {
nv.multiplanarType = Number(v)
},
)
return nv
}

export default demo

Slice type​

sliceType takes a SLICE_TYPE value:

ValueView
SLICE_TYPE.AXIAL (0)one axial slice
SLICE_TYPE.CORONAL (1)one coronal slice
SLICE_TYPE.SAGITTAL (2)one sagittal slice
SLICE_TYPE.MULTIPLANAR (3, default)all three slices, plus a render when there is room
SLICE_TYPE.RENDER (4)the 3D render only
SLICE_TYPE.NONE (5)no spatial view; the whole canvas goes to the signal graph
import NiiVue, { SLICE_TYPE } from '@niivue/niivue'

const nv = new NiiVue({ sliceType: SLICE_TYPE.AXIAL })
nv.sliceType = SLICE_TYPE.RENDER

A single 2D slice fills the canvas by default. Set isSingleViewFillCanvas to false to letterbox it to the slice's aspect ratio instead.

Multiplanar options​

In multiplanar mode, multiplanarType sets how the tiles are arranged: MULTIPLANAR_TYPE.AUTO (picks a layout that suits the canvas shape), COLUMN, GRID or ROW.

showRender decides whether the 3D render joins the slices. SHOW_RENDER.ALWAYS always adds it and SHOW_RENDER.NEVER never does. The default, SHOW_RENDER.AUTO, adds it only when that does not make the slices smaller.

A few more properties shape the tiles:

  • heroFraction (0 to 1) gives one large "hero" tile that share of the canvas, and heroSliceType picks which view it shows (the render by default).
  • isEqualSize makes every tile the same size, instead of sizing each one to its slice's extent.
  • tileMargin adds a gap, in pixels, between tiles.
  • layoutInset keeps a strip of the canvas clear of tiles, colorbar, legend and graph: [left, top, right, bottom] in CSS pixels. Overlays still draw on the whole canvas, so in-canvas controls can sit there.
  • isRadiological flips left and right.
nv.multiplanarType = MULTIPLANAR_TYPE.GRID
nv.showRender = SHOW_RENDER.ALWAYS
nv.heroFraction = 0.6

Mosaics​

A mosaic shows many slices at once. Set mosaicString to a short list of tokens; while it is non-empty it overrides sliceType. Set it back to '' to return to the normal layout.

  • A, C and S choose axial, coronal or sagittal for the numbers that follow.
  • Each number is a slice position in mm and becomes one tile.
  • R makes the next tile a 3D render seen from that orientation. A negative number (or -0) views it from the opposite side.
  • X draws cross-lines on the next tile, marking where the other slices sit.
  • L turns slice labels on and L- turns them off.
  • ; starts a new row.
nv.mosaicString = 'A -20 0 20 40 ; C -30 0 30 S R X 0'

isMosaicCentered (on by default) centers the mosaic on the canvas.

Custom layouts​

For full control, give customLayout a list of tiles. Each tile has a sliceType and a position of [left, top, width, height], all as fractions of the canvas, measured from the top left. A tile can also fix its slice at sliceMM, or set fill: true to fill its pane instead of keeping the slice's aspect ratio.

nv.customLayout = [
{ sliceType: SLICE_TYPE.SAGITTAL, position: [0, 0, 0.5, 1] },
{ sliceType: SLICE_TYPE.CORONAL, position: [0.5, 0, 0.5, 0.5] },
{ sliceType: SLICE_TYPE.AXIAL, position: [0.5, 0.5, 0.5, 0.5] },
]
nv.clearCustomLayout() // back to the built-in layouts

The setter checks the list and throws if a tile is invalid.

Several viewers in one canvas​

Two or more viewers can share a canvas, each drawing into its own region. Pass bounds to the constructor as [[x1, y1], [x2, y2]], or call setBounds([x1, y1, x2, y2]) later. Coordinates are fractions of the canvas, with y = 0 at the bottom (unlike customLayout). clearBounds() gives a viewer the whole canvas again, and showBoundsBorder, boundsBorderColor and boundsBorderThickness outline each region.

import NiiVue, { SLICE_TYPE } from '@niivue/niivue'

const demo = async (canvas, { ui, asset }) => {
const nv1 = new NiiVue({
bounds: [
[0, 0],
[0.5, 1],
],
showBoundsBorder: true,
})
const nv2 = new NiiVue({
bounds: [
[0.5, 0],
[1, 1],
],
showBoundsBorder: true,
})
await nv1.attachToCanvas(canvas)
await nv2.attachToCanvas(canvas)
await nv1.loadVolumes([{ url: asset('volumes/mni152.nii.gz') }])
await nv2.loadVolumes([
{ url: asset('volumes/mni152.nii.gz'), colormap: 'hot' },
])
nv1.sliceType = SLICE_TYPE.AXIAL
nv2.sliceType = SLICE_TYPE.RENDER

ui.select('Split', ['Side by side', 'Stacked'], 'Side by side', (v) => {
// [x1, y1, x2, y2], with y = 0 at the bottom of the canvas
const stacked = v === 'Stacked'
nv1.setBounds(stacked ? [0, 0.5, 1, 1] : [0, 0, 0.5, 1])
nv2.setBounds(stacked ? [0, 0, 1, 0.5] : [0.5, 0, 1, 1])
})
return [nv1, nv2]
}

export default demo

Each viewer has its own volumes and settings. If you move one viewer's region, call drawScene() on the others so the shared canvas repaints. To make the viewers follow each other, see Linking viewers.

Viewers that share a canvas also share its backend, so a shared canvas does not fall back from WebGPU to WebGL2: if you ask for backend: 'webgpu' and the machine has no WebGPU adapter, attachToCanvas throws.

See also​

  • Layout: every layout property in one page.
  • Custom layout: several predefined customLayouts.
  • Bounds: two linked viewers on one canvas.