A flexible and customizable knob for your web applications.
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
dist
sanbox
src
tests
.babelrc
.gitignore
.npmignore
LICENSE
README.md
anatomy.html
demo.html
notes.md
package.json
webpack.config.js
yarn.lock

README.md

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.

Simple SvgKnob component (2 files):

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