Quick Start
A pure JavaScript canvas gauge library with spring-damper needle physics. No dependencies, no build step required for usage.
// HTML: <div id="my-gauge" style="width:200px;height:200px"></div> import { Gauge } from './src/index.js'; const gauge = new Gauge(document.getElementById('my-gauge'), { min: 0, max: 100, label: 'SPEED', units: 'MPH' }); gauge.setValue(60);
Constructor
new Gauge(element, config)
element— AnHTMLElement. The gauge appends a<canvas>child inside it.config— A preset name string (e.g.'speed','rpm') or a config object merged with defaults.
// Using a preset name const rpm = new Gauge(el1, 'rpm'); // Using a custom config object const custom = new Gauge(el2, { min: 0, max: 200, label: 'KPH', units: 'km/h', majorTicks: 11, minorTicks: 2 });
Methods
setValue(value, options?)
Set the gauge value. Animates by default with spring-damper physics. Pass { immediate: true } to snap instantly. Dispatches gauge:valuechange.
sweep()
Runs a self-test sweep animation: needle goes to max then returns. Dispatches gauge:sweepcomplete when done.
destroy()
Disconnects the resize observer, cancels animation, and removes the canvas element. Call this before removing the gauge from the DOM.
gauge.setValue(75); // animated gauge.setValue(75, { immediate: true }); // instant snap gauge.sweep(); // self-test gauge.destroy(); // cleanup
Properties
value (getter/setter)
Get or set the current target value. Setting calls setValue() with animation.
vibration (setter)
Enable or disable needle vibration effect (subtle jitter, useful for RPM gauges).
gauge.value = 50; // same as gauge.setValue(50) console.log(gauge.value); // 50 gauge.vibration = true; // enable needle jitter
Events
Events are dispatched on the container element passed to the constructor.
gauge:ready— Fired after construction and initial render.gauge:valuechange— Fired onsetValue(). Detail:{ value }.gauge:sweepcomplete— Fired when asweep()animation finishes.
Configuration Reference
All configuration keys with their types and defaults. Pass these in the config object to the constructor.
| Key | Type | Default | Description |
|---|---|---|---|
| min | number | 0 | Minimum scale value |
| max | number | 100 | Maximum scale value |
| units | string | '' | Unit text shown below label |
| label | string | '' | Main label text on gauge face |
| majorTicks | number | 5 | Number of major tick marks |
| minorTicks | number | 4 | Minor ticks between each major |
| startAngle | number | -225 | Start angle in degrees (from 12 o'clock) |
| endAngle | number | 45 | End angle in degrees |
| stiffness | number | 120 | Spring stiffness (higher = faster) |
| damping | number | 18 | Damping coefficient (higher = less bounce) |
| redlineStart | number | - | Value where redline zone begins |
| dangerStart | number | - | Value where danger zone begins |
| showOdometer | boolean | false | Show odometer display |
| customLabels | string[] | - | Custom labels for each major tick |
| faceStyle | string | 'light' | 'light' or 'dark' face background |
| colors | object | {} | Color overrides (see Colors section) |
| zones | array | [] | Warning/danger zone arcs |
| texts | array | [] | Arbitrary text placements on face |
| showDigitalValue | boolean | false | Show simple digital numeric readout (legacy; prefer digitalDisplay) |
| digitalDisplay | object | null | Advanced digital readout with position, font size, units display (see Modern Features) |
| labelFontSize | number | 1 | Label font size multiplier (auto-shrinks for long labels) |
| needleGlow | boolean | false | Adds a colored glow effect behind the needle |
| activeTicks | object | null | Illuminate ticks up to current value (see Modern Features) |
| innerRing | object | null | Decorative ring inside the gauge face (see Modern Features) |
| microTicks | object | null | Dense minor tick marks for high-resolution scales (see Modern Features) |
| progressArc | object | null | Colored arc that fills proportional to current value (see Modern Features) |
| rings | array | [] | External segmented ring indicators (see Modern Features) |
| complications | array | [] | Sub-gauges embedded on the dial face (see Modern Features) |
| onDraw | function | null | Custom draw callback (ctx, state) => {} called each frame after needle |
Here is a "kitchen sink" gauge demonstrating many config keys:
new Gauge(el, { min: 0, max: 120, label: 'POWER', units: 'kW', majorTicks: 7, minorTicks: 3, faceStyle: 'dark', showDigitalValue: true, labelFontSize: 1.2, zones: [ { start: 80, end: 100, color: 'rgba(255,165,0,0.15)' }, { start: 100, end: 120, color: 'rgba(204,32,32,0.15)' } ], texts: [{ text: 'EV', x: 0, y: -0.25 }] });
Colors & Theming
The colors object overrides individual gauge colors. All keys are optional; unset keys use smart defaults based on faceStyle.
| Key | Affects | Light Default | Dark Default |
|---|---|---|---|
| face | Face background gradient | #FEFEFE | #1A1A1A |
| needle | Needle gradient base | #CC1010 | #CC1010 |
| ticks | Major tick marks | #1A1A1A | #E0E0E0 |
| minorTicks | Minor tick marks | #404040 | #888888 |
| numbers | Number text | #1A1A1A | #D0D0D0 |
| label | Label text | #2A2A2A | #E0E0E0 |
| units | Units text | #555555 | #AAAAAA |
| redline | Redline/danger zone | #CC2020 | #FF4040 |
Three gauges: default light, custom colors, and dark face.
Modern Features
These advanced features enable contemporary instrument cluster designs with glowing needles, illuminated ticks, segmented rings, digital readouts, and embedded sub-gauges. See the modern preset for a full working example.
needleGlow
When true, adds a soft colored glow behind the needle using the needle's color. Simple boolean toggle.
digitalDisplay
Advanced digital readout replacing the simple showDigitalValue boolean. Provides full control over position, size, colors, and units display.
| Key | Type | Description |
|---|---|---|
| show | boolean | Enable the digital display |
| y | number | Vertical position (-1 to 1, 0 = center) |
| fontSize | number | Font size multiplier (e.g. 2 for large) |
| color | string | Text color (hex or CSS color) |
| background | boolean | Show a dark background behind the value |
| showUnits | boolean | Display units text alongside the value |
| unitsColor | string | Color for the units text |
| unitsFontSize | number | Font size multiplier for units text |
activeTicks
Illuminates tick marks from minimum up to the current needle position, creating a "fill" effect.
| Key | Type | Description |
|---|---|---|
| color | string | Color for illuminated ticks (e.g. '#FFAA00') |
innerRing
Draws a decorative circular ring inside the gauge face, useful for framing a digital readout.
| Key | Type | Description |
|---|---|---|
| radius | number | Ring radius as fraction of gauge radius (0.1 – 0.8) |
| width | number | Line width in pixels (1 – 6) |
| color | string | Ring color |
microTicks
Draws a dense set of fine tick marks for high-resolution scales (e.g. one per km/h on a speedometer).
| Key | Type | Description |
|---|---|---|
| count | number | Total number of micro ticks around the arc (10 – 500) |
| color | string | Tick color |
progressArc
A colored arc that fills proportional to the current gauge value, drawn along the tick arc.
| Key | Type | Description |
|---|---|---|
| width | number | Arc width as fraction of gauge radius (e.g. 0.04) |
| offset | number | Radial offset from center (0.5 – 1.0) |
| background | string | Background color for the unfilled portion |
| glow | boolean | Add glow effect to the filled arc |
| gradient | array | Color stops: [{ at: 0, color: '#00ff00' }, { at: 1, color: '#ff0000' }] |
rings
External segmented ring indicators, often used for RPM/rev bands outside the main bezel. Each ring is an object in the array:
| Key | Type | Description |
|---|---|---|
| min / max | number | Value range for the ring |
| width | number | Ring width as fraction of gauge radius |
| offset | number | Radial offset (1.0 = at bezel edge, >1.0 = outside) |
| startAngle / endAngle | number | Angular span in degrees |
| segments | number | Number of discrete blocks (0 = continuous) |
| background | string | Color for unfilled segments |
| gradient | array | Color stops: [{ at: 0, color: '#0f0' }, ...] |
| flash | object | Flash effect: { above: 7000, color: 'rgba(255,0,0,0.5)', rate: 4 } |
complications
Embedded sub-gauges on the dial face (fuel gauge, oil temp, etc.). Each complication is an object in the array:
| Key | Type | Description |
|---|---|---|
| type | string | Complication type ('arc') |
| x / y | number | Position on dial face (-1 to 1) |
| radius | number | Size reference for tick/marker width |
| min / max | number | Value range |
| startAngle / endAngle | number | Angular span in degrees |
| arcOffset | number | Radial position of the arc |
| arcWidth | number | Arc line width |
| zones | array | Color zones: [{ start: 0, end: 0.15, color: '#FF3333' }] |
| fill | object | Fill arc: { color, widthMultiplier, glow } |
| tickMarks | number | Number of tick marks on the arc |
| marker | boolean | Show a position marker on the arc |
| markerColor | string | Marker color |
| labelSide | string | 'inside' or 'outside' for label placement |
| labelFontSize | number | Font size for labels |
| labels | array | Label positions: [{ text: 'E', position: 0 }, { text: 'F', position: 1 }] |
onDraw
Custom draw callback invoked each animation frame after the needle is drawn. Receives the canvas 2D context and a state object with { value, angle, centerX, centerY, radius }.
Here is the built-in modern preset demonstrating these features together:
new Gauge(el, { min: 0, max: 320, units: 'km/h', faceStyle: 'dark', needleGlow: true, colors: { needle: '#FF8800', ticks: '#CCCCCC' }, digitalDisplay: { show: true, fontSize: 2, color: '#FFFFFF', showUnits: true, unitsColor: '#999999' }, activeTicks: { color: '#FFAA00' }, innerRing: { radius: 0.38, color: '#333333', width: 2 }, microTicks: { count: 320, color: '#444444' }, rings: [{ min: 0, max: 8000, width: 0.04, offset: 1.08, segments: 30, gradient: [ { at: 0, color: '#2255FF' }, { at: 1, color: '#FF2200' } ] }], complications: [{ type: 'arc', startAngle: 216, endAngle: 144, arcOffset: 0.82, arcWidth: 0.012, fill: { color: '#00CCBB', glow: true }, labels: [ { text: 'E', position: 0 }, { text: 'F', position: 1 } ] }] });
Presets Reference
Built-in presets for common automotive gauges. Pass the preset name as the config argument.
Container Requirements
The container element must have explicit dimensions. The gauge uses the smaller of width/height to maintain a square aspect ratio. Use aspect-ratio: 1 for best results.
<!-- Recommended: square container --> <div style="width: 200px; aspect-ratio: 1"></div> <!-- Also works: explicit width + height --> <div style="width: 300px; height: 300px"></div> <!-- Responsive: percentage width --> <div style="width: 50%; aspect-ratio: 1"></div>
Advanced
NeedlePhysics
The needle uses a second-order spring-damper system. The equation of motion:
// acceleration = stiffness * (target - angle) - damping * velocity // Semi-implicit Euler integration at 120Hz fixed timestep
stiffness— Higher values make the needle respond faster.damping— Higher values reduce oscillation/overshoot.
Constructor: new NeedlePhysics(config). Key methods: setTarget(angle, immediate), update(timestamp), isSettled(threshold).
GaugeRenderer
Handles all canvas drawing. Static layers (bezel, face, ticks, numbers) are pre-rendered to an OffscreenCanvas. Per-frame layers (needle, center cap, digital value) are drawn each animation frame.
Layer pipeline: Outer Shadow → Bezel → Inner Lip → Face → Texts → Zones → Ticks → Numbers → Label → Odometer → Glass Highlight.
Compare stiffness/damping: "loose" (stiffness 40, damping 8) vs "tight" (stiffness 300, damping 30).