Gauge radial
A radial gauge for any numeric value, on a 270, 180 or 90 degree sweep, with a readout and advice zones.
On this page
Code
import {
AdviceType,
GaugeRadial,
GaugeRadialHorizontalAlignment,
GaugeRadialSector,
GaugeRadialVerticalAlignment,
InstrumentState,
ObcGaugeRadialType,
Priority,
TickmarkStyle,
type GaugeRadialAdvice,
} from "@bosunkit/instruments";
import { useEffect, useState, type CSSProperties, type Dispatch, type ReactElement, type SetStateAction } from "react";
export const description: string =
"The engine panel of a Yanmar 4JH80 on a live feed: revolutions on a needle with the cruise setpoint, coolant " +
"filling a half dial into its caution zone, oil pressure and alternator load on quarter dials, and the " +
"generator switched off.";
const RPM_ADVICES: GaugeRadialAdvice[] = [
{ minValue: 1600, maxValue: 2400, type: AdviceType.advice, hinted: true },
{ minValue: 3200, maxValue: 4000, type: AdviceType.caution, hinted: true },
];
const COOLANT_ADVICES: GaugeRadialAdvice[] = [
{ minValue: 70, maxValue: 88, type: AdviceType.advice, hinted: true },
{ minValue: 92, maxValue: 120, type: AdviceType.caution, hinted: true },
];
const PANEL: CSSProperties = {
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(190px, 1fr))",
gap: 20,
alignItems: "center",
justifyItems: "center",
width: "100%",
maxWidth: 660,
};
const COLUMN: CSSProperties = { display: "flex", flexDirection: "column", gap: 12, alignItems: "center" };
/** A short, wide strip: the dial fits the height and sits at the left of the slack. */
const STRIP: CSSProperties = { width: 190, height: 110 };
export default function Showcase(): ReactElement {
const [second, setSecond]: [number, Dispatch<SetStateAction<number>>] = useState<number>(0);
useEffect((): (() => void) => {
const interval: number = window.setInterval((): void => {
setSecond((previous: number): number => previous + 1);
}, 1000);
return (): void => {
window.clearInterval(interval);
};
}, []);
// The skipper eases the throttle up to 2400 rpm and back every half minute; the coolant follows behind.
const load: number = (1 - Math.cos((second * Math.PI) / 15)) / 2;
const rpm: number = 1750 + 650 * load + 25 * Math.sin(second * 1.7);
const coolant: number = 82 + (13 * (1 - Math.cos(((second - 4) * Math.PI) / 15))) / 2;
const oilPressure: number = 3.2 + 0.8 * load;
const alternator: number = 38 + 14 * Math.sin(second / 6);
return (
<div style={PANEL}>
<GaugeRadial
value={rpm}
minValue={0}
maxValue={4000}
type={ObcGaugeRadialType.needle}
priority={Priority.enhanced}
tickmarkStyle={TickmarkStyle.enhanced}
setpoint={1800}
autoAtSetpoint
autoAtSetpointDeadband={100}
animateSetpoint
advices={RPM_ADVICES}
primaryTickmarkInterval={1000}
secondaryTickmarkInterval={500}
tertiaryTickmarkInterval={100}
showLabels
hasReadout
label="Engine"
unit="rpm"
faceDiameter={190}
/>
<GaugeRadial
sector={GaugeRadialSector.deg180}
value={coolant}
minValue={40}
maxValue={120}
advices={COOLANT_ADVICES}
setpoint={85}
primaryTickmarkInterval={20}
secondaryTickmarkInterval={10}
tertiaryTickmarkInterval={2}
showLabels
hasReadout
label="Coolant"
unit="°C"
fractionDigits={1}
faceDiameter={190}
/>
<div style={COLUMN}>
<GaugeRadial
sector={GaugeRadialSector.deg90Left}
value={oilPressure}
minValue={0}
maxValue={6}
primaryTickmarkInterval={2}
secondaryTickmarkInterval={1}
showLabels
tickmarksInside
hasReadout
label="Oil"
unit="bar"
fractionDigits={1}
style={STRIP}
horizontalAlignment={GaugeRadialHorizontalAlignment.left}
verticalAlignment={GaugeRadialVerticalAlignment.bottom}
/>
<GaugeRadial
sector={GaugeRadialSector.deg90Right}
type={ObcGaugeRadialType.bar}
value={alternator}
minValue={0}
maxValue={115}
primaryTickmarkInterval={50}
secondaryTickmarkInterval={10}
showLabels
hasReadout
label="Alternator"
unit="A"
style={STRIP}
horizontalAlignment={GaugeRadialHorizontalAlignment.right}
verticalAlignment={GaugeRadialVerticalAlignment.top}
/>
</div>
<GaugeRadial
state={InstrumentState.off}
value={0}
minValue={0}
maxValue={100}
setpoint={70}
setpointOverride
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="Generator"
unit="%"
faceDiameter={150}
/>
</div>
);
}
The radial gauge shows any value on a range, such as a load, a temperature or a count of revolutions. It fills the arc
from zero or turns a needle, marks advice and caution zones, and prints the value with its label and unit. sector
selects the 270, 180 or 90 degree sweep, and faceDiameter pins the size so that gauges side by side match. On a pinned
face the readout scales with the dial, but its label and unit never draw under 11 px. A 90 degree dial under 160 px tall
has no room for the readout in its open corner, so it prints the value and unit in one line under the arc, and the dial
gives that line its height. It ports obc-gauge-radial; the overview lists the other instruments.
Examples
Three quarter
Code
import { GaugeRadial } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string =
"The default 270 degree sweep, filled from zero to 50 percent, with the readout in the center.";
export default function ThreeQuarter(): ReactElement {
return (
<GaugeRadial
value={50}
minValue={0}
maxValue={100}
faceDiameter={180}
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="Load"
unit="%"
/>
);
}
Needle and setpoint
Code
import { GaugeRadial, ObcGaugeRadialType, Priority } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string = "A needle in the enhanced palette at 50, with the setpoint marker at 75.";
export default function NeedleAndSetpoint(): ReactElement {
return (
<GaugeRadial
value={50}
minValue={0}
maxValue={100}
faceDiameter={180}
type={ObcGaugeRadialType.needle}
priority={Priority.enhanced}
setpoint={75}
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="RPM"
unit="×100"
/>
);
}
Half sector
Code
import { GaugeRadial, GaugeRadialSector } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string = "A 180 degree sweep at 62 percent, with the readout below the arc.";
export default function HalfSector(): ReactElement {
return (
<GaugeRadial
sector={GaugeRadialSector.deg180}
value={62}
minValue={0}
maxValue={100}
faceDiameter={180}
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="Trim"
unit="%"
/>
);
}
Quarter sector
Code
import { GaugeRadial, GaugeRadialSector } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string =
"A 90 degree sweep on the right at 62 percent; the dial is under 160 px tall, so the value and unit sit under the arc.";
export default function QuarterSector(): ReactElement {
return (
<GaugeRadial
sector={GaugeRadialSector.deg90Right}
value={62}
minValue={0}
maxValue={100}
faceDiameter={180}
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="Aux"
unit="%"
/>
);
}
Advice triggered
Code
import { AdviceType, GaugeRadial } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string =
"A temperature of 80 inside the caution zone, which is drawn as triggered, beside an advice zone that is only hinted.";
export default function AdviceTriggered(): ReactElement {
return (
<GaugeRadial
value={80}
minValue={0}
maxValue={100}
faceDiameter={180}
primaryTickmarkInterval={25}
secondaryTickmarkInterval={5}
showLabels
hasReadout
label="Temp"
unit="°C"
advices={[
{ minValue: 70, maxValue: 100, type: AdviceType.caution, hinted: true },
{ minValue: 25, maxValue: 60, type: AdviceType.advice, hinted: true },
]}
/>
);
}
No reading
Code
import { GaugeRadial } from "@bosunkit/instruments";
import type { ReactElement } from "react";
export const description: string = "A value that is not a number draws no bar, so the gauge shows no reading.";
export default function NoReading(): ReactElement {
return (
<div style={{ width: 200, height: 200 }}>
<GaugeRadial value={Number.NaN} minValue={0} maxValue={100} />
</div>
);
}
Choose the domain before the dial
Set the minimum, maximum, unit and advice ranges from the quantity being shown. Keep comparable gauges on the
same domain and use faceDiameter to align their visible faces. Equal outer boxes can contain different face
sizes when labels or external scales take space.
Choose the sector for the space available without losing readable ticks or the exact value. Advice ranges are visual guidance; the application owns threshold evaluation and alerts. If a value can exceed the displayed range, retain its numeric value and state rather than letting a needle at the limit hide the excursion.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| value | number | undefined | 0 | Value to show, in the unit of minValue and maxValue. Clamped to the range. A value that is not a number shows
no reading. Default 0. |
| maxValue | number | undefined | 100 | Value at the end of the scale. Default 100. |
| minValue | number | undefined | 0 | Value at the start of the scale. Default 0. |
| showLabels | boolean | undefined | false | Show numeric labels at primary ticks and the zero/min/max positions. |
| primaryTickmarkInterval | number | undefined | 50 | Interval for primary tickmarks in value units; undefined/<= 0 shows none. |
| secondaryTickmarkInterval | number | undefined | 10 | Interval for secondary tickmarks in value units; undefined/<= 0 shows none. |
| tertiaryTickmarkInterval | number | undefined | – | Interval for tertiary tickmarks in value units; undefined/<= 0 shows none. |
| state | InstrumentState | undefined | InstrumentState.active | Instrument state: active (default), loading or off. loading and off draw the bar, the needle and the
setpoint marker disabled. |
| priority | Priority | undefined | Priority.regular | Color priority: regular (gray palette, default) or enhanced (blue palette) for the bar, the needle and the
setpoint marker. |
| type | ObcGaugeRadialType | undefined | ObcGaugeRadialType.filled | How the value is drawn: filled (default) fills the arc from zero, or from the nearest end of the range, to the
value; bar draws that arc in the quieter tertiary color with a short marker at the value; needle draws a
pointer from the center instead of an arc. |
| tickmarksInside | boolean | undefined | false | Draws the tickmarks and their labels inside the ring instead of outside it. Default false. |
| tickmarkStyle | TickmarkStyle | undefined | TickmarkStyle.regular | Tickmark color style. regular (default) draws every tick in the dim tertiary color; enhanced draws ticks in the
brighter primary color and tertiary ticks in the secondary color. |
| advices | GaugeRadialAdvice[] | undefined | [] | Caution/alert arcs. Ignored on sector: 90-left / 90-right. |
| sector | GaugeRadialSector | undefined | GaugeRadialSector.deg270 | Arc span: 270 (default), 180, 90-left, or 90-right. |
| horizontalAlignment | GaugeRadialHorizontalAlignment | undefined | GaugeRadialHorizontalAlignment.center | Horizontal placement of the dial when the host is wider than the dial
(e.g. a short, wide container shrinks the dial to fit the height, leaving
horizontal slack). Default center. |
| verticalAlignment | GaugeRadialVerticalAlignment | undefined | GaugeRadialVerticalAlignment.center | Vertical placement of the dial when the host is taller than the dial
(e.g. a tall, narrow container shrinks the dial to fit the width, leaving
vertical slack). Default center. |
| hasReadout | boolean | undefined | false | When true, shows the center readout(s) with the current value (and
optional label/unit). Layout depends on sector and type — see the
placement matrix in the component doc. Default false. |
| label | string | undefined | "" | Name shown with the readout, such as Load. Default empty. |
| unit | string | undefined | "" | Unit shown with the readout, such as %. Default empty. |
| fractionDigits | number | undefined | 0 | Number of fraction digits shown in the readout. Default 0. |
| faceDiameter | number | undefined | – | Outer-ring diameter in CSS pixels. When set, the instrument renders at a fixed intrinsic size derived from the ring, arc shape and label reserve — so instruments sharing the same value have identical ring circumference regardless of label width or arc extent. When unset (default), the instrument fills its container. |
| className | string | undefined | – | Class names added to the instrument's root element. |
| style | CSSProperties | undefined | – | Inline style for the instrument's root element. |
| setpoint | number | undefined | – | Target setpoint value. |
| newSetpoint | number | undefined | – | Adjustment preview (2-step interface): while defined, the original setpoint marker dims and a focus-state marker renders at this value. |
| atSetpoint | boolean | undefined | – | Manual at-setpoint override; used when autoAtSetpoint is false. |
| touching | boolean | undefined | – | User is physically interacting with the control. Forces focus rendering and suppresses at-setpoint detection while true. |
| autoAtSetpoint | boolean | undefined | – | Enable automatic at-setpoint detection (default true). |
| autoAtSetpointDeadband | number | undefined | – | Tolerance for auto at-setpoint detection (default 2). |
| setpointAtZeroDeadband | number | undefined | – | Zero-snap tolerance for the marker's equalZero state (default 0.5). |
| setpointOverride | boolean | undefined | – | Derive the setpoint color from priority even when loading/off. |
| animateSetpoint | boolean | undefined | – | Enable the CSS-animated confirm transition. |
Related
- Instrument radial: the building block this gauge wraps.
- Gauge radial indicator: the 48 pixel cue.
- Data integrity: the states a value can be in, and what the crew does.