ef-dial
Attributes
valuenumberCurrent angle value in degrees (0-360)
0Rotary control for angle input with circular interaction.
Basic Usage
Display a rotary dial:
<ef-dial value="45" class="w-48 h-48"></ef-dial>
Drag the handle to rotate. Value displays in the center.
Value
Dial value is in degrees (0-360):
const dial = document.querySelector('ef-dial');// Set valuedial.value = 90;// Get valueconsole.log(dial.value); // 0-360// Values are normalized to 0-360dial.value = 380; // Becomes 20dial.value = -30; // Becomes 330
Events
Listen for value changes:
const dial = document.querySelector('ef-dial');dial.addEventListener('change', (e) => {const { value } = e.detail;console.log('New angle:', value);});
Events fire during drag operations.
Precision
Values are limited to 6 significant digits:
dial.value = 45.123456789;console.log(dial.value); // 45.1235 (6 significant digits)
Snap to Increment
Hold Shift while dragging to snap to 15° increments:
<ef-dial value="0" class="w-48 h-48"></ef-dial><p class="text-sm text-gray-600 mt-2">Hold Shift to snap to 15° increments</p>
Without Shift: smooth rotation. With Shift: 0°, 15°, 30°, 45°, 60°, etc.
Sizing
Dial scales to its container:
<!-- Small dial --><ef-dial value="45" class="w-24 h-24"></ef-dial><!-- Medium dial --><ef-dial value="45" class="w-48 h-48"></ef-dial><!-- Large dial --><ef-dial value="45" class="w-64 h-64"></ef-dial>
Default size is 200×200 pixels.
Visual Elements
Dial displays:
Handle
Blue dot indicating current angle position.
Center Text
Current angle value in degrees.
Circle Guide
Dashed circle showing rotation path.
Tick Marks
Four marks at cardinal directions (0°, 90°, 180°, 270°).
Usage Examples
Rotation Control
<div class="flex gap-8 items-center"><ef-dial value="30" class="w-48 h-48" id="rotation-dial"></ef-dial><div class="relative w-32 h-32"><div id="rotation-target" class="w-full h-full bg-blue-500 rounded-lg shadow-lg" style="transform: rotate(30deg)"></div></div></div><script>const dial = document.getElementById('rotation-dial');const target = document.getElementById('rotation-target');dial.addEventListener('change', (e) => {target.style.transform = `rotate(${e.detail.value}deg)`;});</script>
Volume Knob
const volumeDial = document.querySelector('#volume-dial');const audioElement = document.querySelector('audio');volumeDial.addEventListener('change', (e) => {// Map 0-360 degrees to 0-1 volumeaudioElement.volume = e.detail.value / 360;});
Hue Selector
const hueDial = document.querySelector('#hue-dial');const colorPreview = document.querySelector('#color-preview');hueDial.addEventListener('change', (e) => {const hue = e.detail.value;colorPreview.style.backgroundColor = `hsl(${hue}, 100%, 50%)`;});
Programmatic Animation
Animate the dial value:
const dial = document.querySelector('ef-dial');let angle = 0;setInterval(() => {angle = (angle + 1) % 360;dial.value = angle;}, 16);
Interaction
Dial uses pointer capture for smooth dragging:
- Pointer down: Capture pointer, start drag
- Pointer move: Update angle based on mouse position
- Pointer up: Release pointer, end drag
Drag works anywhere in the dial, not just on the handle.
Angle Calculation
Dial calculates angle from pointer position relative to center:
// Internal calculationconst centerX = dialWidth / 2;const centerY = dialHeight / 2;const x = pointerX - centerX;const y = pointerY - centerY;const angle = Math.atan2(y, x) * 180 / Math.PI;
0° is at 3 o'clock, increases clockwise.
Styling
Dial uses CSS custom properties:
ef-dial {/* Circle border color */--dial-stroke: #d0d0d0;/* Tick mark color */--dial-tick: #e0e0e0;/* Background color */--ef-color-bg-panel: #f5f5f5;/* Border color */--ef-color-border: #d0d0d0;/* Handle border color */--ef-color-primary: #2196f3;/* Handle background */--ef-color-bg-elevated: #fff;/* Text color */--ef-color-text: #000;}
Accessibility
Dial captures pointer events for smooth interaction. Consider adding keyboard support for accessibility:
dial.addEventListener('keydown', (e) => {if (e.key === 'ArrowRight') {dial.value = (dial.value + 5) % 360;} else if (e.key === 'ArrowLeft') {dial.value = (dial.value - 5 + 360) % 360;}});
Visual State
Handle shows visual feedback during interaction:
- Normal: White background with blue border
- Dragging: Blue background (solid)
- Cursor:
grabwhen idle,grabbingwhen dragging
Precision Handling
Dial normalizes values to prevent floating point issues:
// Values are automatically normalizeddial.value = 359.99999999;console.log(dial.value); // 0 (wraps around)dial.value = 45.123456789123;console.log(dial.value); // 45.1235 (6 sig figs)
Container Sizing
Dial fills its container and adapts to container dimensions:
ef-dial {width: 100%; /* Fill container width */height: 100%; /* Fill container height */}
Dial uses clientWidth for sizing calculations, so it responds to container size changes.