const Control = require('./control');
const Calc = require('../util/calc');
/**
* Create a range control
*
* @param {object} variaboard - Reference to parent VariaBoard instance
* @param {object} config - Configuration object
* @param {string} config.id - Unique id/slug
* @param {string} config.title - UI display title
* @param {number} config.min - Minimum value
* @param {number} config.max - Maximum value
* @param {number} config.step - Step size
* @param {number} config.default - Starting value
* @param {boolean} config.randomizable - Can be randomized individually and by randomizing all
* @param {boolean} config.mutable - Can be mutated individually and by mutating all
* @param {boolean} config.locked - Temporarily toggle whether the control is affected by randomization and mutation
*
* @extends Control
*
* @requires {@link Control}
* @requires {@link Calc}
*/
class Range extends Control {
constructor(variaboard, config) {
super(variaboard, config);
this.type = 'range';
this.min = config.min;
this.max = config.max;
this.step = config.step !== undefined ? Math.abs(config.step) : 1;
this.places = this.step.toString().indexOf('.') > -1 ? this.step.toString().split('.')[1].length : 0;
this.valueTarget = this.value;
this.mouseIsDown = false;
this.settled = false;
this.listen();
this.set(this.value);
}
createDOM() {
super.createDOM();
// range
this.dom.range = document.createElement('div');
this.dom.range.classList.add(`${this.variaboard.namespace}-control-range`);
// range inner
this.dom.rangeInner = document.createElement('div');
this.dom.rangeInner.classList.add(`${this.variaboard.namespace}-control-range-inner`);
this.dom.range.appendChild(this.dom.rangeInner);
this.dom.control.appendChild(this.dom.range);
}
listen() {
this.dom.value.addEventListener('change', (e) => this.onValueChange(e));
this.dom.range.addEventListener('mousedown', (e) => this.onValueMousedown(e));
}
onValueChange(e) {
this.set(this.dom.value.value);
this.valueTarget = this.value;
}
onValueMousedown(e) {
this.variaboard.mouse.down = true;
this.variaboard.mouse.anchor.x = e.clientX;
this.variaboard.mouse.anchor.y = e.clientY;
this.mouseIsDown = true;
this.setDragValue();
}
onWindowMouseup(e) {
this.mouseIsDown = false;
}
onWindowMousemove(e) {
if(this.mouseIsDown) {
this.setDragValue();
}
}
randomize() {
this.settled = false;
this.valueTarget = Calc.rand(this.min, this.max);
}
setDragValue() {
let left = this.dom.range.offsetLeft;
let width = this.dom.range.offsetWidth;
let val = Calc.map(this.variaboard.mouse.x, left, left + width, this.min, this.max);
this.set(val);
this.valueTarget = this.value;
}
easeSet() {
if(Math.abs(this.value - this.valueTarget) > this.step / 2) {
this.value += (this.valueTarget - this.value) * 0.2;
this.set(this.value, true);
} else {
this.settled = true;
this.value = this.valueTarget;
this.set(this.value);
}
}
set(val, bypassRounding) {
// sanitize value
val = parseFloat(val);
val = isNaN(val) ? this.default : val;
val = Calc.clamp(val, this.min, this.max);
val = bypassRounding ? val : Calc.roundToNearestInterval(val, this.step);
this.value = val;
// set input value
this.dom.value.value = this.value.toFixed(this.places);
// set range value
this.dom.rangeInner.style.transform = `scaleX(${Calc.map(this.value, this.min, this.max, 0, 1)})`;
// set the title attribute for the control
this.dom.control.setAttribute('title', `${this.title}: ${this.value.toFixed(this.places)}`);
}
}
module.exports = Range;