Rebar UI

1.0

opinionnew

SchematicHeatmap

Regions drawn at their own coordinates over a site plan, each shaded by how complete it is, hatched where there is no data.

Signage installedNorthern depot: hover, focus or click an area
North shed: 91.0% (182 / 200)North shedEast shed: 45.7% (96 / 210)East shedDepot office: 8.6% (12 / 140)Depot officeQuay yard: 55.0%Quay yardVan park: 100.0% (40 / 40)Van parkGenerator: no dataPump house: no data
Hover or focus a region for its numbers; click to pin it.
No data
North shed: no dataNorth shedEast shed: no dataEast shedDepot office: no dataDepot office
Hover or focus a region for its numbers; click to pin it.
Pinned
North shed: 91.0% (182 / 200)North shedEast shed: 45.7% (96 / 210)East shedDepot office: 8.6% (12 / 140)Depot office
East shed: 45.7% (96 / 210)
No legend
North shed: 91.0% (182 / 200)North shedEast shed: 45.7% (96 / 210)East shedDepot office: 8.6% (12 / 140)Depot office

In context

Depot signageThe plan beside the project summary
Depot signageWayfinding for the three northern depots.
Review

48% done, due 21 Nov

Pin an area on the plan to see its numbers.

North shed: 91.0% (182 / 200)North shedEast shed: 45.7% (96 / 210)East shedDepot office: 8.6% (12 / 140)Depot officeQuay yard: 55.0%Quay yardVan park: 100.0% (40 / 40)Van parkGenerator: no dataPump house: no data
Hover or focus a region for its numbers; click to pin it.

Props

PropTypeRequiredDefault
regionsHeatmapRegion[]Yes—
brushesHeatmapBrush[] | Record<string, HeatmapBrush> | undefinedNo—
valuesRecord<string, HeatmapValue | undefined> | undefinedNo{}
cropHeatmapBounds | undefinedNo—
backgroundHeatmapBackground | undefinedNo—
selectedIdstring | null | undefinedNo—
defaultSelectedIdstring | null | undefinedNonull
selectedIdsstring[] | undefinedNo—
onSelect((id: string | null, info?: SchematicHeatmapSelectInfo | undefined) => void) | undefinedNo—
ariaLabelstringYes—
colorScale((share: number) => string) | undefinedNo—
labelsPartial<SchematicHeatmapLabels> | undefinedNo—
formatValue((info: { region: HeatmapRegion; share: number | null; value: HeatmapValue | undefined; }) => string) | undefinedNo—
legendBandsSchematicHeatmapLegendBand[] | undefinedNo—
hideLegendboolean | undefinedNofalse
legendExtraReactNodeNo—

data-rebar-* attributes

data-rebar-component="schematic-heatmap" on the root <figure>; data-rebar-state is idle, hovering or selected. Parts: canvas (the <svg>), background, region (with data-region="<id>" and data-rebar-state of value, no-data or selected), region-outline, region-label, legend-row, readout, legend.

Migrating to Ant Design

Not codemod-covered — AntD ships no chart or schematic components (it points to @ant-design/charts), and there is no 1:1 mapping. Keep this component as a small owned SVG, or redraw regions in your charting library of choice.

HeatmapPainter

The authoring tool that comes with SchematicHeatmap: an infinite canvas for painting the regions it draws. Paint a few cells, name them, create the region. The dashboard built on these layouts is HeatmapViewer.

50%

New region from painted area
Frames (1)A frame is the rectangle of the canvas the plot shows. Use the Frame tool to drag one out; move it by its body, resize it by its handles, Delete removes it.
Brushes (2)Your own categories for this layout. Pick the active brush for new regions.
2 regions
1 regions
Tracing image
Regions (3)
hallCorridor
room-aRoom
room-bRoom

Painter: Code

<HeatmapPainter
  value={layout}
  onChange={setLayout}
  height={560}
  idSuggestions={knownAreaIds}
  onUploadBackground={async (file) => ({ url: await store(file) })}
/>

Painter: Props

PropTypeRequiredDefault
valueHeatmapLayout | undefinedNo—
defaultValueHeatmapLayout | undefinedNo—
onChange((layout: HeatmapLayout) => void) | undefinedNo—
activeBrushIdstring | null | undefinedNo—
defaultActiveBrushIdstring | null | undefinedNonull
onActiveBrushChange((id: string | null) => void) | undefinedNo—
heightstring | number | undefinedNo560
cellSizesnumber[] | undefinedNo[10, 20, 50]
idSuggestionsstring[] | undefinedNo—
renderCellForm((ctx: HeatmapPainterCellFormContext) => ReactNode) | undefinedNo—
onCreateRegion((region: HeatmapRegion) => false | void | HeatmapRegion) | undefinedNo—
onUploadBackground((file: File) => Promise<{ url: string; width?: number | undefined; height?: number | undefined; version?: number | undefined; }>) | undefinedNo—
onRemoveBackground(() => void | Promise<void>) | undefinedNo—
defaultCameraHeatmapCamera | undefinedNo—
canvasLabelstring | undefinedNoHeatmap painting canvas

Painter: What it's for

Extracting a drawing's geometry automatically proved hit-and-miss, so the layouts SchematicHeatmap draws are painted: lay a grid over a tracing image, colour in cells, and turn the painted area into a named region. This is that authoring tool, with no knowledge of where region ids or images come from. It edits one HeatmapLayout (cell size, brushes, optional tracing image, frames, regions) — controlled via value/onChange, or uncontrolled via defaultValue — and the host decides how to save it.

Painter: Using it

The canvas is infinite: scroll pans, Ctrl/Cmd+scroll (or pinch) zooms at the cursor, hold Space (or the middle button) and drag to grab it. The *Paint tool paints cells by dragging, Shift-drag paints a box, and starting a stroke on a painted cell erases. Name the painted area in the side panel and create the region; its rectangles are merged by a greedy run-merge (`cellsToRects`), and Edit loads a region's cells back for re-painting (`rectsToCells`). The Frame* tool drags out the named rectangles a plot will show; move a frame by its body, resize it by its eight handles, press Delete to remove it. The focused canvas also takes arrow keys (pan), + / - (zoom) and 0 (fit).

Painting itself is pointer-only (there is no keyboard cell cursor); every other control in the side panel is a native, keyboard-operable form control. Destructive buttons (delete, clear all) need a second press.

Painter: Host integration points

*Region ids.* The default form is a plain text field, with idSuggestions offered through a native datalist. To plug in your own picker (an area search, a register lookup), pass renderCellForm, which receives the draft state and a create() function. onCreateRegion can transform or veto (return false) a region just before it is added.

*Images.* The painter never uploads anything: onUploadBackground(file) must store the file and resolve { url, width?, height?, version? }, and onRemoveBackground lets you delete it. Without onUploadBackground the upload control is not offered. On this page the handler returns a session-only blob: URL.

*Persistence.* None — onChange receives the whole next layout after every edit; save it however you like. Painted-but-uncreated cells are transient UI state and never leave the component.

Painter: Exported pure helpers

cellsToRects, rectsToCells, outlinePath, fitCamera, zoomCameraAt, scrollCamera, dragCamera, screenToWorld, worldToScreen, hitHandle, resizeBounds, moveBounds, frameAt, and the layout helpers. The camera, frame hit-testing and resize math are plain functions, unit-tested directly — jsdom cannot drive canvas or real pointer geometry.

Painter: data-rebar-* attributes

data-rebar-component="heatmap-painter" on the root; data-rebar-state is the current tool (paint or frame). Parts: stage, canvas, tools, tool-paint, tool-frame, zoom, zoom-readout, panel, toolbar, notice (a role="status" line), cell-form, frames-section, frame-row, brushes-section, brush-row, image-section, image-input, regions-section, region-row.

Painter: Migrating to Ant Design

Not codemod-covered — AntD has no canvas authoring component. The side panel maps onto AntD's Collapse, Input, Select, Slider and Popconfirm; the canvas itself is plain <canvas> and carries over unchanged.