02Object 02 · Dials & knobs
Detent Dial
A rotary control you count by feel. The value sticks at each notch and clicks over, and the light stays where the lamp is. Not a slider in a round costume.
- Version
- 0.1.0
- Size
- 19.5 KB gzipped
- Access
- With a Pass
- Needs
- detent-dial.mjs + detent-dial.css
- Tests
- 19 tests · 11 states
Use it
Set a value by turning, where a slider would lose the sense of travel: levels, gain, selectors, set points. Built for both hands on a pointer and hands on a keyboard.
Copy the detent-dial folder from its package next to your page, link its stylesheet and construct it on an element. Every option has a default; the lab’s Code tab writes the same example at any settings, and for React, Vue, Svelte or a custom element (Using a framework).
<link rel="stylesheet" href="detent-dial/detent-dial.css">
<div id="detent-dial"></div>
<script type="module">
import DetentDial from './detent-dial/detent-dial.mjs';
const detentDial = new DetentDial(document.getElementById('detent-dial'), {
min: 0,
max: 100,
step: 1,
});
// detentDial.update({ … }); change any option in place
// detentDial.destroy(); and take it away again
</script>Options
| Option | Type | Default | What it does |
|---|---|---|---|
| range | percent · gain · selector · temperature | 'percent' | Four jobs for one knob: a level, a gain in decibels, an eight-way selector, a thermostat. |
| position | number, 0 to 100 | 50 | How far through the range. Turning the dial in the preview writes here too. |
| detents | number, 0 to 24 | 11 | Felt notches across the sweep, ends included. 0 is a smooth dial. |
| snap | boolean | false | A selector rather than a level. |
| strength | number, 0 to 1.5 | 0.6 | How hard each notch holds before the knob clicks over. |
| sweep | number, 180 to 330 | 270 | Sweep (degrees) |
| finish | aluminium · graphite · brass · bone | 'aluminium' | Spun aluminium, turned brass, anodised graphite with a diamond-cut chamfer, glazed bone ceramic. |
| light | number, 0 to 345 | 315 | 0 is from above, clockwise. The spun band, the glints on the grip, the engraving and the shadow all follow it. |
| size | number, 64 to 400 | 320 | From a panel of 64 px knobs to a hero dial. Numerals and minor ticks appear when there is room for them. |
| numerals | value · index · none | 'value' | The detent values, or 0, 1, 2… the way a hardware knob is marked. |
| caption | below · above · inset · none | 'below' | Label and value under the dial, above it, set into the open throat of the scale, or hidden (still named for assistive technology). |
| led | boolean | false | A ring of lenses that light up to the value, in --dd-led. |
| label | text | '' | The accessible name. Leave empty to use the range’s own name, so it is never blank and never wrong. |
| drag | rotary · vertical | 'rotary' | Rotary follows the pointer round; vertical is the audio-plugin convention. |
| readout | boolean | true | Show value |
| ticks | boolean | true | Show scale |
| sound | boolean | false | Synthesised, no audio file. Starts only after you touch the dial. |
| haptics | boolean | true | Where the device supports it. |
| disabled | boolean | false | Disabled |
Methods
new DetentDial(element, options)- Builds it inside the element with these options.
valueset(v, { emit = false, animate = true } = {})- Set the value programmatically.
update(opts = {})- Change options in place; the value is clamped into any new range.
destroy()- Stops it and cleans up after it.
Events it fires, which bubble from the element: dial:change, dial:input.
States
- IdleThe knob rests at its value; the scale fills to it and every passed detent takes the accent.
- DraggingAngular drag with unwrapping, vertical travel near the centre, Shift for a fifth of the speed; the knob follows a magnetised position between notches.
- Tap on the scaleA click or tap on the printed scale or the LED ring, with no drag, sets the value at that angle and the knob travels there on its usual settle. A tap within reach of a detent lands on it (on a printed 60 it is 60, not 61); with snap on it always lands on the nearest detent. The open throat below the scale takes no tap, and the knob keeps focus for the keys.
- SettlingOn release the knob settles onto the landed value; reduced motion removes the flight and keeps the value.
- SnappingWith snap on, the value only ever lands on a detent: a selector rather than a level.
- At an endHome and End reach the limits; nothing, including a drag past the stop, moves beyond them.
- DisabledPointer, scale taps, keys and wheel are ignored and the dial leaves the tab order.
- AsleepOnce the knob has settled nothing is drawn: no frame is requested, and the loop also pauses off screen and in a hidden tab.
- LED ringAn optional lit arc around the collar shows the value from its start to the pointer, in the signal colour, drawn with the rest of the knob.
- Caption placementThe value readout can sit below, above, inside the open bottom of the scale, or be hidden while still announced as the slider value text.
- Reduced motionThe knob lands on each value with no flight or settle: the value, the detents, the keys, the drag and the scale tap all stay; only the travel between positions goes.
How it works
Made of: Rotary input, Angle unwrapping, Magnetic detents, Fixed lighting, Keyboard slider, Tap to set scale.
Original. Informed by physical detented potentiometers rather than by a catalogue reference, so references is honestly empty. The click is synthesised with Web Audio; no audio file ships.
Blocks built with it
- 02.1Synth PanelA synthesiser’s live front panel.
- 02.2ThermostatA home-climate section with a glazed ceramic dial.
- 02.3Hi-Fi VolumeAn amplifier hero in walnut and brushed brass.
- 06.4Specimen CaseA bento of glass-topped compartments in a machined case, each holding one real Tactile object running small (the Odometer, the Flip-Dot, the Detent Dial, the Vessel) with an engraved label card under the glass.