svg-knob
A flexible and customizable knob for your web applications.
Open the anatomy.html
file to view a description of how the knob is constructed.
Usage
Check the demo.html
file for examples.
.knob {
width: 100px;
}
<svg class="knob" id="knob"></svg>
Without ES6 module support:
<script src="dist/svg-knob.min.js"></script>
<script>
var Knob = svgKnob.default;
var k = new Knob('#knob', { /* config... */ });
</script>
With ES6 module support:
<script type="module">
import Knob from './svg-knob.js';
const k = new Knob('#knob', { /* config... */ });
</script>
change the value:
k.value = 42;
listen to the change events:
document.getElementById("slider").addEventListener("change", function(event) {
let [knob_id, knob_value] = [event.target.id, event.detail];
});
Usage with React
Quick example for a svg-knob and a linked div displaying the value transmitted through the knob's onChange event.
SvgKnob
component (2 files):
Simple components/SvgKnob/index.jsx
:
import React, { Component } from 'react';
import Knob from './knob';
function Value(props) {
return <div className="value">{props.value}</div>;
}
class SvgKnobWithValueSimplerSyntax extends Component {
state = { value: 0 };
handleChange = e => this.setState({value: e.detail});
render() {
return (
<div className="knob">
<Knob onChange={this.handleChange} />
<Value value={this.state.value} />
</div>
);
}
}
export default SvgKnob;
components/SvgKnob/knob.jsx
:
import React, { Component } from 'react';
import SvgKnob from 'svg-knob';
class Knob extends Component {
handleChange = e => {if (this.props.onChange) this.props.onChange(e);};
componentDidMount() {
this.k = new SvgKnob(this.dom);
this.dom.addEventListener("change", this.handleChange);
}
// Not really necessary, but will slightly improve the rendering performance.
shouldComponentUpdate() {
return this.k === null;
}
render() {
return (
<svg ref={elem => this.dom = elem} />
);
}
}
export default Knob;
React App:
App.js
:
import React, {Component} from 'react';
import './App.css';
import SvgKnob from "./components/SvgKnob/";
class App extends Component {
render() {
return (
<div className="App">
<SvgKnob />
</div>
);
}
}
export default App;
App.css
:
.knob {
width: 100px;
}
.knob .value {
text-align: center;
}
Options
let defaults = {
// User configurable properties. The colors are defined in the 'palettes', later on.
label: false,
rotation: CW,
default_value: 0,
initial_value: 0,
value_min: 0.0,
value_max: 100.0,
value_resolution: 1, // null means ignore
// split knob:
center_zero: false,
center_value: null, // if null, the value will be computed from the min and max in the init() method
center_gap: 4, // only used when center_zero=true; is the width of the gap between the left and right track around the zero value.
// position:
zero_at: 270.0, // [deg] (polar) the 0 degree will be at 270 polar degrees (6 o'clock).
angle_min: 30.0, // [deg] Angle in knob coordinates (0 at 6 0'clock)
angle_max: 330.0, // [deg] Angle in knob coordinates (0 at 6 0'clock)
// background disk:
bg_radius: 32,
bg_border_width: 1,
// track background:
track_bg_radius: 40,
track_bg_width: 8,
// track:
track_radius: 40,
track_width: 8,
// cursor
cursor_radius: 18, // same unit as radius
cursor_length: 10,
cursor_width: 4,
// appearance:
palette: 'light',
bg: false,
track_bg: true,
track: true,
cursor: false,
// CSS class names
linecap: 'butt', // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/stroke-linecap
value_text: true,
value_position: HALF_HEIGHT + 8, // empirical value: HALF_HEIGHT + config.font_size / 3
format: v => v, // formatting of the displayed value
font_family: 'sans-serif',
font_size: 25,
font_weight: 'bold',
markers: 0, // number of markers; 0 or false to disable
markers_radius: 40,
markers_length: 8,
markers_width: 2,
class_bg: 'knob-bg',
class_track_bg : 'knob-track-bg',
class_track : 'knob-track',
class_value : 'knob-value',
class_cursor : 'knob-cursor',
class_markers: 'knob-markers',
// mouse wheel support:
mouse_wheel_acceleration: 1,
// callback function:
onchange: null // provides an alternative to the 'change' event
};
light : {
bg_color: '#E0E0E0',
bg_border_color: '#BDBDBD',
track_bg_color: '#CFD8DC',
track_color_init: '#64B5F6',
track_color: '#42A5F5',
cursor_color_init: '#64B5F6',
cursor_color: '#42A5F5',
markers_color: '#9E9E9E',
font_color: '#424242',
},
light2 : {
bg_color: '#B1DAEE',
bg_border_color: '#569DC0',
track_bg_color: '#B1DAEE',
track_color_init: '#569DC0',
track_color: '#1D6D93',
cursor_color_init: '#569DC0',
cursor_color: '#1D6D93',
markers_color: '#3680A4',
font_color: '#1D6D93',
},
dark: {
bg_color: '#000000',
bg_border_color: '#569DC0',
track_bg_color: '#424242',
track_color_init: '#FDD835',
track_color: '#FFEC00',
cursor_color_init: '#569DC0',
cursor_color: '#FDD835',
markers_color: '#3680A4',
font_color: '#FFEA00',
}
TODO
- log scale
- predefined positions
- contextual menu
License
This project is licensed under the MIT License - see the LICENSE file for details