Canvas-based JavaScript UI element implementing touch, keyboard, mouse and scroll wheel support.

Overview

pure-knob

Initially a (circular) knob / dial control with mouse, wheel, touch and keyboard support, implemented in pure JavaScript.

In addition, this script can also render (linear) bar graphs.

  • Canvas-based, no image files required.
  • Mouse, wheel, touch and keyboard controls.

pure-knob as generated in index.xhtml:

pure-knob as generated in index.xhtml

Example for knob control

// Create knob element, 300 x 300 px in size.
const knob = pureknob.createKnob(300, 300);

// Set properties.
knob.setProperty('angleStart', -0.75 * Math.PI);
knob.setProperty('angleEnd', 0.75 * Math.PI);
knob.setProperty('colorFG', '#88ff88');
knob.setProperty('trackWidth', 0.4);
knob.setProperty('valMin', 0);
knob.setProperty('valMax', 100);

// Set initial value.
knob.setValue(50);

/*
 * Event listener.
 *
 * Parameter 'knob' is the knob object which was
 * actuated. Allows you to associate data with
 * it to discern which of your knobs was actuated.
 *
 * Parameter 'value' is the value which was set
 * by the user.
 */
const listener = function(knob, value) {
	console.log(value);
};

knob.addListener(listener);

// Create element node.
const node = knob.node();

// Add it to the DOM.
const elem = document.getElementById('some_element');
elem.appendChild(node);

Properties

  • angleStart: Angle in radians, at which the knob track starts.
  • angleEnd: Angle in radians, at which the knob track ends.
  • angleOffset: Offset in radians, relative to the positive x-axis.
  • colorBG: Color of the knob track.
  • colorFG: Color of the knob gauge / indicator.
  • colorLabel: Color of the (optional) label.
  • fnStringToValue: Function turning a string into a (numeric) value. (Check the "custom formatting" section below for more information.)
  • fnValueToString: Function turning a (numeric) value into a string. (Check the "custom formatting" section below for more information.)
  • label: A label (string) displayed at the bottom of the knob, a track radius length away from the center. Set to null to not print any label.
  • needle: Boolean indicating whether we should use a simple marker / needle instead of a filling gauge to indicate value along the knob's track.
  • readonly: Boolean indicating whether the value of the knob is write-protected and thus not editable by the user. Useful for displaying values without allowing them to get edited.
  • textScale: Linear scaling factor for increasing / decreasing the font size. (1.0 is default font size.)
  • trackWidth: Width of the track, relative to the average radius of the knob.
  • valMin: Minimum selectable value.
  • valMax: Maximum selectable value.
  • val: Default value. (Do not edit directly! Use setValue(...) to set this.)

Events / Actions

  • Normal left click / drag / touch changes value, releasing button commits value.
  • Pulling mouse / touch outside the element before release restores back to old value.
  • Double click or middle click enables entry of value via keyboard.
  • When keyboard entry is enabled, use arrow keys to navigate cursor, backspace or Del to delete character before / after cursor, ESC to restore old value and disable keyboard entry, Enter/Return to commit new value and disable keyboard entry.

Custom formatting

You may provide a set of two JavaScript functions and set them as the fnStringToValue and fnValueToString properties, respectively, to support custom formatting of your numbers, for example to support fractional parts and / or custom units. Note that this is an advanced feature, which is not required for basic functionality of the knob.

The function provided in the fnValueToString property is called when the knob needs to obtain a string representation from an integer value. This is usually the case when the knob needs to get rendered. A single argument is passed into the function, which is the integer value, for which the string representation should be obtained. The function must generate and return the string representation to the knob.

On the other hand, the function provided in the fnStringToValue property is called when the knob needs to obtain an integer value from a string representation. This is usually the case after the user entered and committed a new value for the knob via the (physical or on-screen) keyboard. A single argument is passed into the function, which is the string representation, for which the integer value should be obtained. The function must generate and return the integer value to the knob.

The default implementation of both functions is as follows.

knob.setProperty('fnStringToValue', function(string) { return parseInt(string); });
knob.setProperty('fnValueToString', function(value) { return value.toString(); });

We will now provide a more complicated example, which uses a knob control with a value range from 0 to 1000 (both inclusive), but displays it as a fractional percentage value with one decimal place between 0.0 % and 100.0 %. The relative font size has to be reduced in order for the relatively long string 100.0 % to fit inside the control.

knob.setProperty('valMin', 0);
knob.setProperty('valMax', 1000);
knob.setProperty('textScale', 0.75);

/*
 * Function for converting integer value to string for display.
 */
knob.setProperty('fnValueToString', function(value) {
	let string = value.toString();
	let n = string.length;

	/*
	 * If value is just a single digit, add leading zero.
	 */
	if (n < 2) {
		string = '0' + string;
		n += 1;
	}

	const prefix = string.slice(0, n - 1);
	const suffix = string.slice(n - 1, n);
	const result = prefix + '.' + suffix + ' %';
	return result;
});

/*
 * Function for converting string entered by user to integer value.
 */
knob.setProperty('fnStringToValue', function(string) {
	let val = 0;
	const numerals = string.match(/\d*(\.\d*)?/);

	/*
	 * Ensure that numerals are non-null.
	 */
	if (numerals !== null) {

		/*
		 * Check if we found a numeral.
		 */
		if (numerals.length > 0) {
			const numeral = numerals[0];
			const f = parseFloat(numeral);
			val = Math.round(10.0 * f);
		}

	}

	return val;
});

Example for bar graph control

// Create bar graph element, 400 x 40 px in size.
const graph = pureknob.createBarGraph(400, 40);

// Set properties.
graph.setProperty('colorFG', '#88ff88');
graph.setProperty('colorMarkers', '#ffffff');
graph.setProperty('markerStart', 50);
graph.setProperty('markerEnd', 100);
graph.setProperty('markerStep', 10);
graph.setProperty('valMin', 0);
graph.setProperty('valMax', 100);

// Set initial value.
graph.setValue(50);

// Set peak value. (Multiple peak values may be passed as a list.)
graph.setPeaks([75]);

// Create element node.
const node = graph.node();

// Add it to the DOM.
const elem = document.getElementById('some_element');
elem.appendChild(node);

You may update both the bar graph value (setValue(...)) and the peak values (setPeaks(...)) programmatically in your script to display new values.

Properties

  • colorBG: Color of the bar graph track.
  • colorFG: Color of the bar graph filling / indicator.
  • colorMarkers: Color of the markers (scale) on both sides (top and bottom) of the bar graph track.
  • markerStart: Value where the first marker will be drawn along the track.
  • markerEnd: Value where the last marker will be drawn along the track.
  • markerStep: Spacing (increment) between the markers.
  • trackWidth: Width of the track, relative to the absolute height of the control.
  • valMin: Minimum value which can be displayed (left-hand side of the track).
  • valMax: Maximum value which can be displayed (right-hand side of the track).
  • valPeaks: List of peak values to be displayed. (Do not edit directly! Use setPeaks(...) to set this.)
  • val: Default value. (Do not edit directly! Use setValue(...) to set this.)

There is also a small sample provided for the bar graph control in the index.xhtml file.

Comments
  • non ideal resolution

    non ideal resolution

    Hello all and thanks for this great project ! I just implemented it into http://www.soundjack.eu and it works just fine, however, there is a problem with the resolution of the button – it is not as "smooth" as in your demo images and appears pixeled as displayed in the linked image below. Has anyone a suggestion how to fix this ? Thanks in advance !

    Bildschirmfoto 2021-04-20 um 12 50 26
    opened by jazzalex 10
  • Pixel ratio handling

    Pixel ratio handling

    I modified the resize functions to take the device pixel ratio into account.

    This allows a better rendering on mobile devices with 'retina' capabilities.

    It might introduce side effects though as I switched from a '%' methodology to 'px', I didn't dive into the code enough to know if this may have an impact.

    opened by Booster2ooo 8
  • Make pure-knob npm publishable

    Make pure-knob npm publishable

    This pull request does two things:

    • puts pureknob into a UMD definition.
      • UMD (Universal Module Definition) patterns for JavaScript modules that work everywhere. https://github.com/umdjs/umd/blob/master/templates/returnExports.js
    • add package.json file

    UMD definition allows us to avoid polluting global namespace

    The demo still works with no changes to the html, and pure-knob can still be used the way it was before. i.e. If inserted as a script tag in an html file, a variable pureknob will get added to the global scope.

    In addition, the module definition allows it to be imported as a node, commonjs, or amd module, as in

    const pureknob = require(".../path_to/pureknob.js")
    
    pureknob.createKnob(...) 
    

    or if imported as a bundle by parcel, webpack, browserify, etc, we can even import it into the bundle like a es6 module.

    import * as pureknob from ".../path_to/pureknob.js"
    
    pureknob.createKnob(...)
    

    Publishable to npm repository

    The package.json file defines pure-knob as a node package, which can be published to the node repository using npm-publish (see https://docs.npmjs.com/misc/developers and https://docs.npmjs.com/cli/publish). That way, developers can include it in their projects simply with npm install pure-knob, and then import it into their code with

    import * as pk from "pure-knob"
    pk.createKnob()
    

    or

    const pk = require("pure-knob")
    pk.createKnob()
    

    "pure-knob" without a path or .js extension indicates to the bundler that "pure-knob" is a npm package and will look for it in the node_modules folder for the active project.

    I could publish it from my fork, but I would rather that @andrepxx publish the official pure-knob node package.

    @andrepxx let me know if you need any more clarification about how to publish the "pure-knob" module to npm. This will make it available to many more developers!

    opened by ebrensi 5
  • Set value programaticaly and reflect changes?

    Set value programaticaly and reflect changes?

    Hi and thanks for your nice plug-in.

    Found no way to easily set a new value from script, and reflect the changes with the adequate rotary action.

    Currently what I do is replacing a knob by a new one with a new value, it works but this leads to some issues with event listeners, the goal would be to set many values on different knobs in the same time.

    So far, I am setting the values as follow, changing at events. . Each knob div have an id. My script retrieve this data-values, so I can change it from there, and it has effect, but of course knobs don't follow on this case.

    screenshot at 2018-06-04 22 30 54

    Currently building a simple audio workstation:

    gif1528143151_optimized

    Also, the mouse wheel action is reversed, up wheel go down value?

    Otherwise all good, no lags, simple and precise, thanks again.

    question 
    opened by webdev23 5
  • Replace method to get offset in touch event

    Replace method to get offset in touch event

    Loop through parent nodes to get offset from top of page since Element.getBoundingClientRect() returns offset to top of screen.

    That way touch events work when scrolled down.

    opened by jaarenhoevel 4
  • suggestion: knob keeps focus until mouse up / touch end

    suggestion: knob keeps focus until mouse up / touch end

    Hi, thanks for sharing your knob :)

    There's one feature that I find not very convenient: "Pulling mouse / touch outside the element before release restores back to old value.". The smaller your knob, the easier it is to leave the element by accident and revert the changes.

    My plan is to change the behavior so the knob does NOT calculate the angle between the center and the mouse pointer / finger. Instead, clicking the knob sets it as focused, then I would just drag up / down to set the value (not caring about if the mouse / finger is inside the element or not). When releasing the value stays. A bit like with https://nexus-js.github.io/ui/

    One drawback: there's no way to cancel (unless I detect the ESC to cancel).

    What do you think of this approach? Would you use this as an alternative mode for pure-knob?

    wontfix 
    opened by hamoid 4
  • Decimal percentage numbers

    Decimal percentage numbers

    Hi Andre Plötze,

    First thank you for the code, it's great! I'm not a programmer, I just fool around with html and css and I'm trying to make a "spacecraft panel" for my son to use it on a tablet.

    Question: I was wondering if is there any way to make this knob display 'decimal percentage numbers', something like 14.7%.

    Sorry for the silly question.

    Thank you, Jun

    enhancement 
    opened by jun5150 2
  • es6 update and minor optimizations

    es6 update and minor optimizations

    @andrepxx, nice little knob library you made! I found you via https://github.com/aterrien/jQuery-Knob/pull/356. I have been using https://github.com/aterrien/jQuery-Knob, which appears to be inactive, and I don't really need jQuery.

    This merge replaces all var declarations with appropriate lets and consts, and takes some redundant canvas style updating out of a couple of loops.

    The changes are minor but brings it up to date with current ECMA standards.

    opened by ebrensi 1
  • Can fail on odd startAngle endAngle

    Can fail on odd startAngle endAngle

    Dial sticks at 0 when clicked on :

    knob.setProperty('angleStart', 1.5Math.PI); knob.setProperty('angleEnd' , 2.0Math.PI); knob.setProperty('trackWidth', 0.4); knob.setProperty('valMin' , 0); knob.setProperty('valMax' , 90); knob.setProperty('needle' , true); knob.setValue(45);

    I had originally wanted

    knob.setProperty('angleStart', 0); knob.setProperty('angleEnd' , 0.5*Math.PI);

    but then I wanted the dial to go anti-clockwise, so tried to swap valMin and valMax but that didn't work, so I tried the code I have above and found it doesn't work either.

    invalid 
    opened by gazhay 1
  • add change events?

    add change events?

    I need change event notification for my application, and not just commit event. I would like the option to set a callback for change events. I am willing to implement this.

    opened by ebrensi 3
Owner
Andre Plötze
Andre Plötze
Smooth scrolling effect (while using mouse wheel). No jQuery or other unnecessary stuff needed.

scrooth Smooth scrolling effect (while using mouse wheel). No jQuery or other unnecessary stuff needed. Why? I needed that, and I was unable to find p

Rafał Spiżewski 20 Aug 29, 2022
Pressure is a JavaScript library for handling both Force Touch and 3D Touch on the web

Pressure is a JavaScript library for handling both Force Touch and 3D Touch on the web, bundled under one library with a simple API that makes working with them painless.

Stuart Yamartino 2.9k Dec 29, 2022
A Deno library for interacting with the mouse 🖱️ keyboard ⌨️ and screen 💻

A Deno library for interacting with the mouse ??️ keyboard ⌨️ and screen ?? . Litebot provides a simple API for creating kbm events, macros, & working with displays. Litebot leverages Deno's FFI to allow speedy low level control in C & C++ while having a typescript API exposed to the user.

Tyler Laceby 10 Aug 30, 2022
👇 Bread n butter utility for component-tied mouse/touch gestures in Svelte.

svelte-gesture svelte-gesture is a library that lets you bind richer mouse and touch events to any component or view. With the data you receive, it be

Robert Soriano 29 Dec 21, 2022
👇 Bread n butter utility for component-tied mouse/touch gestures in Solid.

solid-gesture solid-gesture is a port of @use-gesture/react which lets you bind richer mouse and touch events to any component or view. With the data

Robert Soriano 8 Sep 30, 2022
Super tiny size multi-touch gestures library for the web.    You can touch this →

Preview You can touch this → http://alloyteam.github.io/AlloyFinger/ Install You can install it via npm: npm install alloyfinger Usage var af = new Al

腾讯 AlloyTeam 3.3k Dec 12, 2022
A JavaScript animation plugin for menus. It creates a div that moves when you mouse over an element, giving it an elastic animation.

Lava-Lamp Description: A JavaScript animation plugin for menus. It creates a div that moves when you mouse over an element, giving it an elastic anima

Richard Hung 38 Jun 4, 2022
We are creating a Library that would ensure developers do not reinvent the wheel anymore as far as Authentication is concerned. Developers can easily register and download authentication codes that suits their need at any point.

#AuthWiki Resource Product Documentation Figma Database Schema First Presentation Live Link API Documentation Individual Contributions User Activity U

Zuri Training 17 Dec 2, 2022
A vanilla-js module for adding zoom-on-wheel and pan-on-drag behavior to inline SVG elements.

svg-pan-zoom-container A vanilla-js module for adding zoom-on-wheel and pan-on-drag behavior to inline SVG elements. No need to write scripts. Just ma

31 Dec 10, 2022
Fancytree - JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkboxes, drag'n'drop, and lazy loading

Fancytree Fancytree (sequel of DynaTree 1.x) is a JavaScript tree view / tree grid plugin with support for keyboard, inline editing, filtering, checkb

Martin Wendt 2.6k Jan 9, 2023
A simple jQuery extension to make any HTML element sticky on scroll.

jquery.sticky.js A simple jQuery extension to make any HTML element sticky on scroll. Installation Just download the script and include it in your HTM

Achal Jain 2 Aug 22, 2022
A jQuery plugin allowing you to scroll an image within a container element

jQuery Scroll Image Inside v0.1 A jQuery plugin allowing you to scroll an image within a container element Usage <div id="window"> <img src="reall

Derek Ashauer 1 Apr 11, 2021
The Easel Javascript library provides a full, hierarchical display list, a core interaction model, and helper classes to make working with the HTML5 Canvas element much easier.

EaselJS EaselJS is a library for building high-performance interactive 2D content in HTML5. It provides a feature-rich display list to allow you to ma

CreateJS 8k Dec 29, 2022
JavaScript micro-library: pass in an element and a callback and this will trigger when you click anywhere other than the element

Add a click listener to fire a callback for everywhere on the window except your chosen element. Installation run npm install @lukeboyle/when-clicked-

Boyleing Point 5 May 13, 2021
Responsive navigation plugin without library dependencies and with fast touch screen support.

Responsive Nav Responsive navigation plugin without library dependencies and with fast touch screen support. Responsive Nav is a tiny JavaScript plugi

Viljami Salminen 4.1k Dec 29, 2022
Obsidian plugin to support a sequenced of keyboard shortcuts to run commands.

Sequence Shortcuts (Obsidian plugin) This plugin allows you to use a sequences of chords for shortcuts instead of single chords. Creating a hotkey You

Ruan Moolman 23 Dec 17, 2022
Query for CSS brower support data, combined from caniuse and MDN, including version support started and global support percentages.

css-browser-support Query for CSS browser support data, combined from caniuse and MDN, including version support started and global support percentage

Stephanie Eckles 65 Nov 2, 2022
A JavaScript library for adding ripple effects to HTML elements based on mouse events.

About project Ripplejs is an open source javascript library created for the purpose of adding ripple effects to html elements based on mouse events. L

Udezue Oluomachi Chimaobi 7 May 10, 2022
jQuery based scrolling Bar, for PC and Smartphones (touch events). It is modern slim, easy to integrate, easy to use. Tested on Firefox/Chrome/Maxthon/iPhone/Android. Very light <7ko min.js and <1Ko min.css.

Nice-Scrollbar Responsive jQuery based scrolling Bar, for PC and Smartphones (touch events). It is modern slim, easy to integrate, easy to use. Tested

Renan LAVAREC 2 Jan 18, 2022