Back to work

Selected work — 02 / Custom visuals

Charts I had to write.

Power BI ships with a fixed set of charts. When the one I needed wasn't among them, I wrote it — six so far: a body-map heatmap, a bar visual, a gauge, a stacked-change column and KPI cards, all hand-written in TypeScript. Rebuilt below, live, so you can play with them.

6 visuals 13 body regions gauge · bars · stacks · cards TypeScript · SVG 0 chart libraries

Every figure inside these widgets is sample data — invented to show how each visual behaves, not real numbers.

LIVEthe same heatmap that's further down — warmer means more injuries.

In short

A custom visual is a small program Power BI runs inside the report: it hands your code the data and the size of the box, and your code draws the pixels.

It's code, not a template

A TypeScript class that implements one interface. No drag-and-drop — every pixel is drawn on purpose.

01 · IVisual · TypeScript

Power BI hands it data

You declare the fields you accept; the host shapes the data to match and passes it in on every change.

02 · capabilities · dataView

You draw the pixels

Given the data and the viewport, the code lays out SVG — bars, paths, labels, a whole stats panel.

03 · SVG · your layout

It ships as one file

Packaged into a single .pbiviz — code, styles and icon zipped together — and imported into any report.

04 · one .pbiviz · one GUID

How it works

Power BI talks. Your code draws.

Its whole life is one loop: built once, then update() fires on every data, size or setting change — read, redraw. Run the loop

ONCE

constructor

Host builds the visual, hands over the DOM element. You set up your <svg>.

TRIGGER

data / size / setting changes

Someone filters, resizes, or tweaks a format control.

EVERY TIME

update(options)

The host calls your update() with fresh options.

READ

options.dataViews[0]

You pull the reshaped data and the current settings out.

DRAW

render() → SVG

Clear the canvas, lay out the picture at the new size.

idle

Visual one — the injury body map

Injuries, mapped onto a body.

Two fields in — a body region and an injury count — and each region colours on a five-band scale while the panel rolls them into groups and spotlights the worst. Click a region, or drag the caseload

Injuries by Body Group

0
1–5
6–15
16–40
41+
Colour = number of injuries
Caseload240 injuries
0quietbusy600

Bands: 1–5 · 6–15 · 16–40 · 41+ — all format-pane colours. This is the prototype; its shipped twin bodyInjuryHeatmap swaps the five bands for a smooth min→max gradient, tells left from right, and wires up Power BI selection, cross-highlight and tooltips.

The data behind it

Two fields in. A picture out.

It declares what it accepts — one grouping, one measure — and Power BI reshapes the report into the categorical dataView it receives. Toggle rows — watch the dataView

role bodyRegion · Grouping role injuryCount · Measure
Body RegionInjury Count

dataViewwhat update() receives — categorical


          

Visual two — the bar visual

A bar chart that does what the built-in one won't.

For the details the built-in bar chart skips — a real grand-total header, its own fonts, alignment and a border you can shape. Each is a control in the format pane. Change the pane — the chart follows

Format · Bar visual
Total header
Show
Prefix
Alignment
Header border
Style
Thickness1.5
Radius6
Colour
Fonts & colour
Label size12
Value size13
Bars

Where the pane comes from

Declare a control. Power BI draws the pane.

You never build the pane by hand — you declare each property's type, and the host renders the control. Pick a type

Renders as
Toggle switch

A boolean becomes a switch in the pane, and arrives in your settings model as true / false.

Visual three — the semi-circle gauge

On target, at a glance.

One value fills toward a max, past two targets, into one of three zones — behind, on track, ahead — and the arc takes that zone's colour. Drag the value

Actual value62
min 0max 100
Behind0 – 40
On track40 – 75
Ahead75 – 100

Targets at 40 and 75 · min/max, zones and markers are all format-pane controls.

Also on the shelf

Same instinct, a few more times.

Two more that earn their place — a stacked column that annotates its change between periods, and a strip of KPI cards. Both live. Poke them

Stacked column + change

v3.5.8 · legend · drilldown · change deltas

MultiCard

v1.3.2 · KPI cards · row or column

Iteration

One good version is really six.

Each release added exactly one thing a report asked for — and the old package was never overwritten, only superseded. Walk the versions

1.6.0Data

Set the Values role to accept a measure or a grouping, so a report author can pick “Don't summarize” and show raw category values instead of a forced sum.

By the numbers

The family, counted.

6custom visuals
13body regions
5colour bands
3gauge zones
4region groups
6bar-visual releases
1interface · IVisual
0chart libraries

Both drawn in raw SVG on the powerbi-visuals API — no D3 chart helpers, no third-party charting. Every colour, font and border is a format-pane control.

© 2026 Mohsen Zarei Designed, coded & shipped by me Back to top ↑