This component no longer exists. It was in ns-ui’s manifest when we first indexed it and is not there now — the registry served its inventory on 2026-08-07 and this item was not on it. The install command below will fail. It is kept here because a tutorial somewhere still tells people to run it.
Chart Donut Halftone
ns-ui/chart-donut-halftoneRemovedComponent
Donut chart for an ordinal size scale where wedge angle carries share and ordered-dither density carries tier order, instead of a second colour.
Live preview
live · rendered by the registry
Rendered by ns-ui on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://design.helpmarq.com/r/chart-donut-halftone.jsonSource
1"use client";23import { useEffect, useId, useMemo, useState } from "react";45// ---------------------------------------------------------------------------6// ChartDonutHalftone — the dithered-chart family's part-to-whole chart. The7// backlog flags pie/donut as a form to build "only with a real reason": the8// dataviz heuristic says bar beats pie for almost every job, and a donut9// whose slice DENSITY re-encoded its own share would be the textbook10// anti-pattern (a value-ramp on a channel that already shows the value via11// angle). The reason here is that the segments are ORDINAL — a small, fixed12// size-tier scale — not nominal categories. Angle still carries the only13// magnitude channel (share of the whole); density carries the tier's14// POSITION in the size scale (S sparsest -> XL densest), the same "one hue,15// monotone lightness steps" idea the dataviz skill prescribes for an ordinal16// ramp, translated into ink density instead of lightness. The two channels17// encode two different facts, so nothing is double-encoded.18//19// Same shared constant as chart-bar-halftone: the 4x4 Bayer matrix already20// used by background-ascii-dither and ascii-engraving-contour, stamped into21// 17 discrete ink-level patterns (0 empty, 16 solid) and duplicated verbatim22// here so both chart-family members produce byte-identical density at the23// same level. Pure var(--foreground) ink on var(--background) paper, no24// --accent in the data channel, --accent reserved for keyboard focus only —25// the family's colour decision, matching heatmap-year-stipple's precedent.26// ---------------------------------------------------------------------------2728export interface ChartDonutHalftoneDatum {29 label: string;30 value: number;31}3233export interface ChartDonutHalftoneProps {34 /** ordinal, low -> high tier order (e.g. size tiers, funnel stages) */35 data?: ChartDonutHalftoneDatum[];36 title?: string;37 /** unit suffix appended to the center readout, e.g. "orders" */38 unit?: string;39 className?: string;40}4142const BAYER = [0, 8, 2, 10, 12, 4, 14, 6, 3, 11, 1, 9, 15, 7, 13, 5];43const LEVELS = 16;44const CELL = 4;4546const SIZE = 240;47const CX = SIZE / 2;48const CY = SIZE / 2;49const R_OUTER = 96;50const R_INNER = 56;51const GAP_RAD = 0.035;52const EXPLODE_PX = 6;5354function ordinalLevel(rank: number, total: number): number {55 if (total <= 1) return LEVELS;56 return Math.round((rank / (total - 1)) * LEVELS);57}5859// … truncated
