1 | const EventEmitter = require('events').EventEmitter
|
2 | const inherits = require('inherits')
|
3 | const isNumeric = require('is-numeric')
|
4 | const css = require('dom-css')
|
5 | const format = require('param-case')
|
6 | const precision = require('mumath/precision')
|
7 |
|
8 | module.exports = Range
|
9 | inherits(Range, EventEmitter)
|
10 |
|
11 | function Range (opts) {
|
12 | if (!(this instanceof Range)) return new Range(opts);
|
13 |
|
14 | this.update(opts);
|
15 | }
|
16 |
|
17 | Range.prototype.update = function (opts) {
|
18 | var scaleValue, scaleValueInverse, logmin, logmax, logsign
|
19 |
|
20 | if (!!opts.step && !!opts.steps) {
|
21 | throw new Error('Cannot specify both step and steps. Got step = ' + opts.step + ', steps = ', opts.steps)
|
22 | }
|
23 |
|
24 | opts.container.innerHTML = '';
|
25 |
|
26 | if (!opts.container) opts.container = document.body;
|
27 |
|
28 | var input = opts.container.querySelector('.settings-panel-range');
|
29 |
|
30 | if (!input) {
|
31 | input = opts.container.appendChild(document.createElement('input'))
|
32 | input.type = 'range'
|
33 | input.className = 'settings-panel-range'
|
34 | }
|
35 |
|
36 | if (opts.disabled) input.disabled = true;
|
37 |
|
38 |
|
39 | if (opts.scale === 'log') {
|
40 | scaleValue = function (x) {
|
41 | return logsign * Math.exp(Math.log(logmin) + (Math.log(logmax) - Math.log(logmin)) * x / 100)
|
42 | }
|
43 | scaleValueInverse = function (y) {
|
44 | return (Math.log(y * logsign) - Math.log(logmin)) * 100 / (Math.log(logmax) - Math.log(logmin))
|
45 | }
|
46 | } else {
|
47 | scaleValue = scaleValueInverse = function (x) { return x }
|
48 | }
|
49 |
|
50 |
|
51 | if (opts.scale === 'log') {
|
52 |
|
53 | opts.max = (isNumeric(opts.max)) ? opts.max : 100
|
54 | opts.min = (isNumeric(opts.min)) ? opts.min : 0.1
|
55 |
|
56 |
|
57 | if (opts.min * opts.max <= 0) {
|
58 | throw new Error('Log range min/max must have the same sign and not equal zero. Got min = ' + opts.min + ', max = ' + opts.max)
|
59 | } else {
|
60 |
|
61 | logmin = opts.min
|
62 | logmax = opts.max
|
63 | logsign = opts.min > 0 ? 1 : -1
|
64 |
|
65 |
|
66 | logmin = Math.abs(logmin)
|
67 | logmax = Math.abs(logmax)
|
68 |
|
69 |
|
70 | opts.min = 0
|
71 | opts.max = 100
|
72 |
|
73 |
|
74 | if (isNumeric(opts.step)) {
|
75 | throw new Error('Log may only use steps (integer number of steps), not a step value. Got step =' + opts.step)
|
76 | }
|
77 |
|
78 | opts.step = 1
|
79 | }
|
80 |
|
81 | opts.value = scaleValueInverse(isNumeric(opts.value) ? opts.value : scaleValue((opts.min + opts.max) * 0.5))
|
82 |
|
83 | if (opts.value * scaleValueInverse(opts.max) <= 0) {
|
84 | throw new Error('Log range initial value must have the same sign as min/max and must not equal zero. Got initial value = ' + opts.value)
|
85 | }
|
86 | } else {
|
87 |
|
88 | opts.max = (isNumeric(opts.max)) ? opts.max : 100
|
89 | opts.min = (isNumeric(opts.min)) ? opts.min : 0
|
90 | opts.step = (isNumeric(opts.step)) ? opts.step : (opts.max - opts.min) / 100
|
91 |
|
92 | opts.value = isNumeric(opts.value) ? opts.value : (opts.min + opts.max) * 0.5
|
93 | }
|
94 |
|
95 |
|
96 | if (isNumeric(opts.steps)) {
|
97 | opts.step = isNumeric(opts.steps) ? (opts.max - opts.min) / opts.steps : opts.step
|
98 | }
|
99 |
|
100 |
|
101 | var initialStep = Math.round((opts.value - opts.min) / opts.step)
|
102 | opts.value = opts.min + opts.step * initialStep
|
103 |
|
104 |
|
105 | opts.container.setAttribute('data-min', opts.min);
|
106 | opts.container.setAttribute('data-max', opts.max);
|
107 |
|
108 | if (opts.scale === 'log') {
|
109 |
|
110 | var prec = 3;
|
111 | }
|
112 | else {
|
113 | if (opts.step) {
|
114 | var prec = precision(opts.step);
|
115 | }
|
116 | else if (opts.steps) {
|
117 | var prec = precision( (opts.max - opts.min) / opts.steps );
|
118 | }
|
119 | }
|
120 |
|
121 | var value = require('./value')({
|
122 | id: opts.id,
|
123 | container: opts.container,
|
124 | className: 'settings-panel-range-value',
|
125 | value: scaleValue(opts.value).toFixed(prec),
|
126 | type: opts.scale === 'log' ? 'text' : 'number',
|
127 | min: scaleValue(opts.min),
|
128 | max: scaleValue(opts.max),
|
129 | disabled: opts.disabled,
|
130 |
|
131 | step: opts.scale === 'log' ? 0.01 : opts.step,
|
132 | input: (v) => {
|
133 | input.value = scaleValueInverse(v)
|
134 |
|
135 | this.emit('input', v);
|
136 | input.setAttribute('value', v.toFixed(0))
|
137 | opts.container.style.setProperty('--value', v + '%');
|
138 | opts.container.style.setProperty('--coef', v/100);
|
139 | }
|
140 | });
|
141 |
|
142 |
|
143 | input.min = opts.min
|
144 | input.max = opts.max
|
145 | input.step = opts.step
|
146 | input.value = opts.value
|
147 | let v = 100 * (opts.value - opts.min) / (opts.max - opts.min);
|
148 | input.setAttribute('value', v.toFixed(0))
|
149 | opts.container.style.setProperty('--value', v + '%');
|
150 | opts.container.style.setProperty('--coef', v/100);
|
151 |
|
152 | setTimeout(() => {
|
153 | this.emit('init', parseFloat(input.value))
|
154 | });
|
155 |
|
156 | input.oninput = (data) => {
|
157 | var scaledValue = scaleValue(parseFloat(data.target.value));
|
158 | value.value = scaledValue.toFixed(prec);
|
159 | let v = 100 * (data.target.value - opts.min) / (opts.max - opts.min);
|
160 | input.setAttribute('value', v.toFixed(0));
|
161 | opts.container.style.setProperty('--value', v + '%');
|
162 | opts.container.style.setProperty('--coef', v/100);
|
163 | this.emit('input', scaledValue);
|
164 | }
|
165 |
|
166 | return this;
|
167 | }
|