665 lines
21 KiB
JavaScript
665 lines
21 KiB
JavaScript
|
/*
|
||
|
* This file is part of Toolkit.
|
||
|
*
|
||
|
* Toolkit is free software; you can redistribute it and/or
|
||
|
* modify it under the terms of the GNU General Public
|
||
|
* License as published by the Free Software Foundation; either
|
||
|
* version 3 of the License, or (at your option) any later version.
|
||
|
*
|
||
|
* Toolkit is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General
|
||
|
* Public License along with this program; if not, write to the
|
||
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
* Boston, MA 02110-1301 USA
|
||
|
*/
|
||
|
"use strict";
|
||
|
(function(w, TK){
|
||
|
function LinearSnapModule(stdlib, foreign) {
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
var step = +foreign.step;
|
||
|
var base = +foreign.base;
|
||
|
|
||
|
var floor = stdlib.Math.floor;
|
||
|
var ceil = stdlib.Math.ceil;
|
||
|
|
||
|
function low_snap(v, direction) {
|
||
|
v = +v;
|
||
|
direction = +direction;
|
||
|
var n = 0.0;
|
||
|
var t = 0.0;
|
||
|
|
||
|
if (!(v > min)) {
|
||
|
v = min;
|
||
|
direction = 1.0;
|
||
|
} else if (!(v < max)) {
|
||
|
v = max;
|
||
|
direction = +1.0;
|
||
|
}
|
||
|
|
||
|
t = (v - base)/step;
|
||
|
|
||
|
if (direction > 0.0) n = ceil(t);
|
||
|
else if (direction < 0.0) n = floor(t);
|
||
|
else {
|
||
|
if (t - floor(t) < 0.5) {
|
||
|
n = floor(t);
|
||
|
} else {
|
||
|
n = ceil(t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return base + step * n;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the nearest value on the grid which is bigger than <code>value</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#snap_up
|
||
|
*
|
||
|
* @param {number} value - The value to snap.
|
||
|
*
|
||
|
* @returns {number} The snapped value.
|
||
|
*/
|
||
|
function snap_up(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, 1.0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the nearest value on the grid which is smaller than <code>value</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#snap_down
|
||
|
*
|
||
|
* @param {number} value - The value to snap.
|
||
|
*
|
||
|
* @returns {number} The snapped value.
|
||
|
*/
|
||
|
function snap_down(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, -1.0);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the nearest value on the grid. Its rounding behavior is similar to that
|
||
|
* of <code>Math.round</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#snap
|
||
|
*
|
||
|
* @param {number} value - The value to snap.
|
||
|
*
|
||
|
* @returns {number} The snapped value.
|
||
|
*/
|
||
|
function snap(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, 0.0);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
snap_up : snap_up,
|
||
|
snap_down : snap_down,
|
||
|
snap : snap
|
||
|
};
|
||
|
}
|
||
|
|
||
|
function ArraySnapModule(stdlib, foreign, heap) {
|
||
|
var values = new stdlib.Float64Array(heap);
|
||
|
var len = (heap.byteLength>>3)|0;
|
||
|
var min = +(foreign.min !== void 0 ? foreign.min : values[0]);
|
||
|
var max = +(foreign.max !== void 0 ? foreign.max : values[len-1]);
|
||
|
|
||
|
function low_snap(v, direction) {
|
||
|
v = +v;
|
||
|
direction = +direction;
|
||
|
var a = 0;
|
||
|
var mid = 0;
|
||
|
var b = 0;
|
||
|
var t = 0.0;
|
||
|
|
||
|
b = len-1;
|
||
|
|
||
|
if (!(v > min)) v = min;
|
||
|
if (!(v < max)) v = max;
|
||
|
|
||
|
if (!(v < +values[b << 3 >> 3])) return +values[b << 3 >> 3];
|
||
|
if (!(v > +values[0])) return +values[0];
|
||
|
|
||
|
do {
|
||
|
mid = (a + b) >>> 1;
|
||
|
t = +values[mid << 3 >> 3];
|
||
|
if (v > t) a = mid;
|
||
|
else if (v < t) b = mid;
|
||
|
else return t;
|
||
|
} while (((b - a)|0) > 1);
|
||
|
|
||
|
if (direction > 0.0) return +values[b << 3 >> 3];
|
||
|
else if (direction < 0.0) return +values[a << 3 >> 3];
|
||
|
|
||
|
if (values[b << 3 >> 3] - v <= v - values[a << 3 >> 3]) return +values[b << 3 >> 3];
|
||
|
return +values[a << 3 >> 3];
|
||
|
}
|
||
|
|
||
|
function snap_up(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, 1.0);
|
||
|
}
|
||
|
|
||
|
function snap_down(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, -1.0);
|
||
|
}
|
||
|
|
||
|
function snap(v) {
|
||
|
v = +v;
|
||
|
return +low_snap(v, 0.0);
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
snap_up : snap_up,
|
||
|
snap_down : snap_down,
|
||
|
snap : snap
|
||
|
};
|
||
|
}
|
||
|
function NullSnapModule(stdlib, foreign, heap) {
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
|
||
|
function snap(v) {
|
||
|
v = +v;
|
||
|
if (!(v < max)) v = max;
|
||
|
if (!(v > min)) v = min;
|
||
|
return v;
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
snap: snap,
|
||
|
snap_up: snap,
|
||
|
snap_down: snap,
|
||
|
};
|
||
|
}
|
||
|
function num_sort(a) {
|
||
|
a = a.slice(0);
|
||
|
a.sort(function(a, b) { return a - b; });
|
||
|
return a;
|
||
|
}
|
||
|
function update_snap() {
|
||
|
var O = this.options;
|
||
|
// Notify that the ranged options have been modified
|
||
|
if (Array.isArray(O.snap)) {
|
||
|
Object.assign(this, ArraySnapModule(window, O, new Float64Array(num_sort(O.snap)).buffer));
|
||
|
} else if (typeof O.snap === "number" && O.snap > 0.0) {
|
||
|
Object.assign(this, LinearSnapModule(window, { min : Math.min(O.min, O.max), max : Math.max(O.min, O.max), step : O.snap, base: O.base||0 }));
|
||
|
} else if (O.min < Infinity && O.max > -Infinity) {
|
||
|
Object.assign(this, NullSnapModule(window, { min : Math.min(O.min, O.max), max : Math.max(O.min, O.max) }));
|
||
|
} else {
|
||
|
Object.assign(this, {
|
||
|
snap: function(v) { return +v; },
|
||
|
snap_up: function(v) { return +v; },
|
||
|
snap_down: function(v) { return +v; },
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
function TRAFO_PIECEWISE(stdlib, foreign, heap) {
|
||
|
var reverse = foreign.reverse|0;
|
||
|
var l = heap.byteLength >> 4;
|
||
|
var X = new Float64Array(heap, 0, l);
|
||
|
var Y = new Float64Array(heap, l*8, l);
|
||
|
var basis = +foreign.basis;
|
||
|
|
||
|
function val2based(coef, size) {
|
||
|
var a = 0,
|
||
|
b = (l-1)|0,
|
||
|
mid = 0,
|
||
|
t = 0.0;
|
||
|
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
|
||
|
if (!(coef > +Y[0])) return +X[0] * size;
|
||
|
if (!(coef < +Y[b << 3 >> 3])) return +X[b << 3 >> 3] * size;
|
||
|
|
||
|
do {
|
||
|
mid = (a + b) >>> 1;
|
||
|
t = +Y[mid << 3 >> 3];
|
||
|
if (coef > t) a = mid;
|
||
|
else if (coef < t) b = mid;
|
||
|
else return +X[mid << 3 >> 3] * size;
|
||
|
} while (((b - a)|0) > 1);
|
||
|
|
||
|
/* value lies between a and b */
|
||
|
|
||
|
t = (+X[b << 3 >> 3] - +X[a << 3 >> 3]) / (+Y[b << 3 >> 3] - +Y[a << 3 >> 3]);
|
||
|
|
||
|
t = +X[a << 3 >> 3] + (coef - +Y[a << 3 >> 3]) * t;
|
||
|
|
||
|
t *= size;
|
||
|
|
||
|
if (reverse) t = size - t;
|
||
|
|
||
|
return t;
|
||
|
}
|
||
|
function based2val(coef, size) {
|
||
|
var a = 0,
|
||
|
b = (l-1)|0,
|
||
|
mid = 0,
|
||
|
t = 0.0;
|
||
|
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
if (reverse) coef = size - coef;
|
||
|
coef /= size;
|
||
|
|
||
|
if (!(coef > 0)) return Y[0];
|
||
|
if (!(coef < 1)) return Y[b << 3 >> 3];
|
||
|
|
||
|
do {
|
||
|
mid = (a + b) >>> 1;
|
||
|
t = +X[mid << 3 >> 3];
|
||
|
if (coef > t) a = mid;
|
||
|
else if (coef < t) b = mid;
|
||
|
else return +Y[mid << 3 >> 3];
|
||
|
} while (((b - a)|0) > 1);
|
||
|
|
||
|
/* value lies between a and b */
|
||
|
|
||
|
t = (+Y[b << 3 >> 3] - +Y[a << 3 >> 3]) / (+X[b << 3 >> 3] - +X[a << 3 >> 3]);
|
||
|
|
||
|
return +Y[a << 3 >> 3] + (coef - +X[a << 3 >> 3]) * t;
|
||
|
}
|
||
|
function val2px(n) { return val2based(n, basis || 1); }
|
||
|
function px2val(n) { return based2val(n, basis || 1); }
|
||
|
function val2coef(n) { return val2based(n, 1); }
|
||
|
function coef2val(n) { return based2val(n, 1); }
|
||
|
return {
|
||
|
val2based:val2based,
|
||
|
based2val:based2val,
|
||
|
val2px:val2px,
|
||
|
px2val:px2val,
|
||
|
val2coef:val2coef,
|
||
|
coef2val:coef2val,
|
||
|
};
|
||
|
};
|
||
|
function TRAFO_FUNCTION(stdlib, foreign) {
|
||
|
var reverse = foreign.reverse|0;
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
var scale = foreign.scale;
|
||
|
var basis = +foreign.basis;
|
||
|
function val2based(value, size) {
|
||
|
value = +value;
|
||
|
size = +size;
|
||
|
value = scale(value, foreign, false) * size;
|
||
|
if (reverse) value = size - value;
|
||
|
return value;
|
||
|
}
|
||
|
function based2val(coef, size) {
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
if (reverse) coef = size - coef;
|
||
|
coef = scale(coef/size, foreign, true);
|
||
|
return coef;
|
||
|
}
|
||
|
function val2px(n) { return val2based(n, basis || 1); }
|
||
|
function px2val(n) { return based2val(n, basis || 1); }
|
||
|
function val2coef(n) { return val2based(n, 1); }
|
||
|
function coef2val(n) { return based2val(n, 1); }
|
||
|
return {
|
||
|
val2based:val2based,
|
||
|
based2val:based2val,
|
||
|
val2px:val2px,
|
||
|
px2val:px2val,
|
||
|
val2coef:val2coef,
|
||
|
coef2val:coef2val,
|
||
|
};
|
||
|
}
|
||
|
function TRAFO_LINEAR(stdlib, foreign) {
|
||
|
var reverse = foreign.reverse|0;
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
var basis = +foreign.basis;
|
||
|
function val2based(value, size) {
|
||
|
value = +value;
|
||
|
size = +size;
|
||
|
value = ((value - min) / (max - min)) * size;
|
||
|
if (reverse) value = size - value;
|
||
|
return value;
|
||
|
}
|
||
|
function based2val(coef, size) {
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
if (reverse) coef = size - coef;
|
||
|
coef = (coef / size) * (max - min) + min;
|
||
|
return coef;
|
||
|
}
|
||
|
// just a wrapper for having understandable code and backward
|
||
|
// compatibility
|
||
|
function val2px(n) { n = +n; if (basis == 0.0) basis = 1.0; return +val2based(n, basis); }
|
||
|
// just a wrapper for having understandable code and backward
|
||
|
// compatibility
|
||
|
function px2val(n) { n = +n; if (basis == 0.0) basis = 1.0; return +based2val(n, basis); }
|
||
|
// calculates a coefficient for the value
|
||
|
function val2coef(n) { n = +n; return +val2based(n, 1.0); }
|
||
|
// calculates a value from a coefficient
|
||
|
function coef2val(n) { n = +n; return +based2val(n, 1.0); }
|
||
|
return {
|
||
|
/**
|
||
|
* Transforms a value from the coordinate system to the interval <code>0</code>...<code>basis</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#val2based
|
||
|
*
|
||
|
* @param {number} value
|
||
|
* @param {number} [basis=1]
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
val2based:val2based,
|
||
|
/**
|
||
|
* Transforms a value from the interval <code>0</code>...<code>basis</code> to the coordinate system.
|
||
|
*
|
||
|
* @method TK.Ranged#based2val
|
||
|
*
|
||
|
* @param {number} value
|
||
|
* @param {number} [basis=1]
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
based2val:based2val,
|
||
|
/**
|
||
|
* This is an alias for {@link TK.Ranged#val2px}.
|
||
|
*
|
||
|
* @method TK.Ranged#val2px
|
||
|
*
|
||
|
* @param {number} value
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
val2px:val2px,
|
||
|
/**
|
||
|
* This is an alias for {@link TK.Ranged#px2val}.
|
||
|
*
|
||
|
* @method TK.Ranged#px2val
|
||
|
*
|
||
|
* @param {number} value
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
px2val:px2val,
|
||
|
/**
|
||
|
* Calls {@link based2val} with <code>basis = 1</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#val2coef
|
||
|
*
|
||
|
* @param {number} value
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
val2coef:val2coef,
|
||
|
/**
|
||
|
* Calls {@link based2val} with <code>basis = 1</code>.
|
||
|
*
|
||
|
* @method TK.Ranged#coef2val
|
||
|
*
|
||
|
* @param {number} value
|
||
|
*
|
||
|
* @returns {number}
|
||
|
*/
|
||
|
coef2val:coef2val,
|
||
|
};
|
||
|
}
|
||
|
function TRAFO_LOG(stdlib, foreign) {
|
||
|
var db2scale = stdlib.TK.AudioMath.db2scale;
|
||
|
var scale2db = stdlib.TK.AudioMath.scale2db;
|
||
|
var reverse = foreign.reverse|0;
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
var log_factor = +foreign.log_factor;
|
||
|
var trafo_reverse = foreign.trafo_reverse|0;
|
||
|
var basis = +foreign.basis;
|
||
|
function val2based(value, size) {
|
||
|
value = +value;
|
||
|
size = +size;
|
||
|
value = +db2scale(value, min, max, size, trafo_reverse, log_factor);
|
||
|
if (reverse) value = size - value;
|
||
|
return value;
|
||
|
}
|
||
|
function based2val(coef, size) {
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
if (reverse) coef = size - coef;
|
||
|
coef = +scale2db(coef, min, max, size, trafo_reverse, log_factor);
|
||
|
return coef;
|
||
|
}
|
||
|
function val2px(n) { return val2based(n, basis || 1); }
|
||
|
function px2val(n) { return based2val(n, basis || 1); }
|
||
|
function val2coef(n) { return val2based(n, 1); }
|
||
|
function coef2val(n) { return based2val(n, 1); }
|
||
|
return {
|
||
|
val2based:val2based,
|
||
|
based2val:based2val,
|
||
|
val2px:val2px,
|
||
|
px2val:px2val,
|
||
|
val2coef:val2coef,
|
||
|
coef2val:coef2val,
|
||
|
};
|
||
|
}
|
||
|
function TRAFO_FREQ(stdlib, foreign) {
|
||
|
var freq2scale = stdlib.TK.AudioMath.freq2scale;
|
||
|
var scale2freq = stdlib.TK.AudioMath.scale2freq;
|
||
|
var reverse = foreign.reverse|0;
|
||
|
var min = +foreign.min;
|
||
|
var max = +foreign.max;
|
||
|
var trafo_reverse = foreign.trafo_reverse|0;
|
||
|
var basis = +foreign.basis;
|
||
|
function val2based(value, size) {
|
||
|
value = +value;
|
||
|
size = +size;
|
||
|
value = +freq2scale(value, min, max, size, trafo_reverse);
|
||
|
if (reverse) value = size - value;
|
||
|
return value;
|
||
|
}
|
||
|
function based2val(coef, size) {
|
||
|
coef = +coef;
|
||
|
size = +size;
|
||
|
if (reverse) coef = size - coef;
|
||
|
coef = +scale2freq(coef, min, max, size, trafo_reverse);
|
||
|
return coef;
|
||
|
}
|
||
|
function val2px(n) { return val2based(n, basis || 1); }
|
||
|
function px2val(n) { return based2val(n, basis || 1); }
|
||
|
function val2coef(n) { return val2based(n, 1); }
|
||
|
function coef2val(n) { return based2val(n, 1); }
|
||
|
return {
|
||
|
val2based:val2based,
|
||
|
based2val:based2val,
|
||
|
val2px:val2px,
|
||
|
px2val:px2val,
|
||
|
val2coef:val2coef,
|
||
|
coef2val:coef2val,
|
||
|
};
|
||
|
}
|
||
|
function update_transformation() {
|
||
|
var O = this.options;
|
||
|
var scale = O.scale;
|
||
|
|
||
|
var module;
|
||
|
|
||
|
if (typeof scale === "function") {
|
||
|
module = TRAFO_FUNCTION(w, O);
|
||
|
} else if (Array.isArray(scale)) {
|
||
|
var i = 0;
|
||
|
if (scale.length % 2) {
|
||
|
TK.error("Malformed piecewise-linear scale.");
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < scale.length/2 - 1; i++) {
|
||
|
if (!(scale[i] >= 0 && scale[i] <= 1))
|
||
|
TK.error("piecewise-linear x value not in [0,1].");
|
||
|
if (!(scale[i] < scale[i+1]))
|
||
|
TK.error("piecewise-linear array not sorted.");
|
||
|
}
|
||
|
for (i = scale.length/2; i < scale.length - 1; i++) {
|
||
|
if (!(scale[i] < scale[i+1]))
|
||
|
TK.error("piecewise-linear array not sorted.");
|
||
|
}
|
||
|
|
||
|
module = TRAFO_PIECEWISE(w, O, new Float64Array(scale).buffer);
|
||
|
} else switch (scale) {
|
||
|
case "linear":
|
||
|
module = TRAFO_LINEAR(w, O);
|
||
|
break;
|
||
|
case "decibel":
|
||
|
O.trafo_reverse = 1;
|
||
|
module = TRAFO_LOG(w, O);
|
||
|
break;
|
||
|
case "log2":
|
||
|
O.trafo_reverse = 0;
|
||
|
module = TRAFO_LOG(w, O);
|
||
|
break;
|
||
|
case "frequency":
|
||
|
O.trafo_reverse = 0;
|
||
|
module = TRAFO_FREQ(w, O);
|
||
|
break;
|
||
|
case "frequency-reverse":
|
||
|
O.trafo_reverse = 1;
|
||
|
module = TRAFO_FREQ(w, O);
|
||
|
break;
|
||
|
default:
|
||
|
TK.warn("Unsupported scale", scale);
|
||
|
}
|
||
|
|
||
|
Object.assign(this, module);
|
||
|
}
|
||
|
function set_cb(key, value) {
|
||
|
switch (key) {
|
||
|
case "min":
|
||
|
case "max":
|
||
|
case "snap":
|
||
|
update_snap.call(this);
|
||
|
/* fall through */
|
||
|
case "log_factor":
|
||
|
case "scale":
|
||
|
case "reverse":
|
||
|
case "basis":
|
||
|
update_transformation.call(this);
|
||
|
this.fire_event("rangedchanged");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
/**
|
||
|
* @callback TK.Ranged~scale_cb
|
||
|
*
|
||
|
* @param {number} value - The value to be transformed.
|
||
|
* @param {Object} [options={ }] - An object containing initial options. - The options of the corresponding {@link TK.Ranged} object.
|
||
|
* @param {boolean} [inverse=false] - Determines if the value is to be transformed from or
|
||
|
* to the coordinate system.
|
||
|
*
|
||
|
* @returns {number} The transformed value.
|
||
|
*/
|
||
|
TK.Ranged = TK.class({
|
||
|
/**
|
||
|
* TK.Ranged combines functionality for two distinct purposes.
|
||
|
* Firstly, TK.Ranged can be used to snap values to a virtual grid.
|
||
|
* This grid is defined by the options <code>snap</code>,
|
||
|
* <code>step</code>, <code>min</code>, <code>max</code> and <code>base</code>.
|
||
|
* The second feature of TK.anged is that it allows transforming values between coordinate systems.
|
||
|
* This can be used to transform values from and to linear scales in which they are displayed on the
|
||
|
* screen. It is used inside of Toolkit to translate values (e.g. in Hz or dB) to pixel positions or
|
||
|
* percentages, for instance in widgets such as {@link TK.Scale}, {@link TK.MeterBase} or
|
||
|
* {@link TK.Graph}.
|
||
|
*
|
||
|
* TK.Ranged features several types of coordinate systems which are often used in audio applications.
|
||
|
* They can be configured using the <code>options.scale</code> option, possible values are:
|
||
|
* <ul>
|
||
|
* <li><code>linear</code> for linear coordinates,
|
||
|
* <li><code>decibel</code> for linear coordinates,
|
||
|
* <li><code>log2</code> for linear coordinates,
|
||
|
* <li><code>frequency</code> for linear coordinates or
|
||
|
* <li><code>frequency-reverse"</code> for linear coordinates.
|
||
|
* </ul>
|
||
|
* If <code>options.scale</code> is a function, it is used as the coordinate transformation.
|
||
|
* Its signature is {@link TK.Ranged~scale_cb}. This allows the definition of custom
|
||
|
* coordinate transformations, which go beyond the standard types.
|
||
|
*
|
||
|
* @param {Object} [options={ }] - An object containing initial options.
|
||
|
*
|
||
|
* @property {String|Array<Number>|Function} [options.scale="linear"] -
|
||
|
* The type of the scale. Either one of <code>linear</code>, <code>decibel</code>, <code>log2</code>,
|
||
|
* <code>frequency</code> or <code>frequency-reverse</code>; or an array containing a
|
||
|
* piece-wise linear scale;
|
||
|
* or a callback function of type {@link TK.Ranged~scale_cb}.
|
||
|
* @property {Boolean} [options.reverse=false] - Reverse the scale of the range.
|
||
|
* @property {Number} [options.basis=1] - The size of the linear scale. Set to pixel width or height
|
||
|
* if used for drawing purposes or to 100 for percentages.
|
||
|
* @property {Number} [options.min=0] - Minimum value of the range.
|
||
|
* @property {Number} [options.max=1] - Maximum value of the range.
|
||
|
* @property {Number} [options.log_factor=1] - Used to overexpand logarithmic curves. 1 keeps the
|
||
|
* natural curve while values above 1 will overbend.
|
||
|
* @property {Number|Array.<number>} [options.snap=0] -
|
||
|
* Defines a virtual grid.
|
||
|
* If <code>options.snap</code> is a positive number, it is interpreted as the distance of
|
||
|
* grid points.
|
||
|
* Then, inside of the interval <code>options.min</code> ... <code>options.max</code> the grid
|
||
|
* points are <code> options.base + n * options.snap </code> where <code>n</code> is any
|
||
|
* integer. Any values outside of that interval are snapped to the biggest or smallest grid
|
||
|
* point, respectively.
|
||
|
* In order to define grids with non-uniform spacing, set <code>options.snap</code> to an Array
|
||
|
* of grid points.
|
||
|
* @property {Number} [options.base=0] - Base point. Used e.g. to mark 0dB on a fader from -96dB to 12dB.
|
||
|
* @property {Number} [options.step=0] - Step size. Used for instance by {@link TK.ScrollValue}
|
||
|
* as the step size.
|
||
|
* @property {Number} [options.shift_up=4] - Multiplier for increased stepping speed, e.g. used by
|
||
|
* {@link TK.ScrollValue} when simultaneously pressing 'shift'.
|
||
|
* @property {Number} [options.shift_down=0.25] - Multiplier for descresed stepping speed, e.g. used by
|
||
|
* {@link TK.ScrollValue} when simultaneously pressing 'shift' and 'ctrl'.
|
||
|
*
|
||
|
* @mixin TK.Ranged
|
||
|
*/
|
||
|
|
||
|
_class: "Ranged",
|
||
|
options: {
|
||
|
scale: "linear",
|
||
|
reverse: false,
|
||
|
basis: 1,
|
||
|
min: 0,
|
||
|
max: 1,
|
||
|
base: 0,
|
||
|
step: 0,
|
||
|
shift_up: 4,
|
||
|
shift_down: 0.25,
|
||
|
snap: 0,
|
||
|
round: true, /* default for TK.Range, no dedicated option */
|
||
|
log_factor: 1,
|
||
|
trafo_reverse: false, /* used internally, no documentation */
|
||
|
},
|
||
|
_options: {
|
||
|
scale: "string|array|function",
|
||
|
reverse: "boolean",
|
||
|
basis: "number",
|
||
|
min: "number",
|
||
|
max: "number",
|
||
|
base: "number",
|
||
|
step: "number",
|
||
|
shift_up: "number",
|
||
|
shift_down: "number",
|
||
|
snap: "mixed",
|
||
|
round: "boolean",
|
||
|
log_factor: "number",
|
||
|
trafo_reverse: "boolean",
|
||
|
},
|
||
|
static_events: {
|
||
|
set: set_cb,
|
||
|
initialized: function() {
|
||
|
var O = this.options;
|
||
|
if (!(O.min <= O.max))
|
||
|
TK.warn("Ranged needs min <= max. min: ", O.min, ", max:", O.max, ", options:", O);
|
||
|
update_snap.call(this);
|
||
|
update_transformation.call(this);
|
||
|
},
|
||
|
},
|
||
|
});
|
||
|
})(this, this.TK);
|