/*
* This file is part of AUX.
*
* AUX 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.
*
* AUX 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
* 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
*/
import { Base } from '../implements/base.js';
import {
rangedEvents,
rangedOptionsDefaults,
rangedOptionsTypes,
makeTransformation,
makeSnapModule,
} from '../utils/ranged.js';
/**
* Range is used for calculating linear scales from
* different values. They are useful for building coordinate systems,
* calculating pixel positions for different scale types, and the like.
* Range is used e.g. in {@link Scale}, {@link Meter} and {@link Graph}, to draw
* elements on a certain position according to a value on an
* arbitrary scale.
*
* @class Range
*
* @extends Base
*
* @param {Object} [options={ }] - An object containing initial options.
*
* @property {String|Function} [options.scale="linear"] - Type of the value.
* <code>linear</code>, <code>decibel</code>, <code>log2</code>, <code>frequency</code>
* or a <code>function (value, options, coef) {}</code>.
* If a function instead of a constant is handed over, it receives the
* actual options object as the second argument and is supposed to return a
* coefficient between 0 and 1. If the third argument "coef" is true, it is
* supposed to return a value depending on a coefficient handed over as the
* first argument.
* @property {Boolean} [options.reverse=false] - <code>true</code> if
* the range is reversed.
* @property {Number} [options.basis=0] - Dimensions of the range, set to
* width/height in pixels, if you need it for drawing purposes, to 100 if
* you need percentual values or to 1 if you just need a linear
* coefficient for a e.g. logarithmic scale.
* @property {Number} [options.min=0] - The minimum value possible.
* @property {Number} [options.max=0] - The maximum value possible.
* @property {Number} [options.step=1] - Step size, needed for e.g. user
* interaction
* @property {Number} [options.shift_up=4] - Multiplier for e.g. SHIFT pressed
* while stepping
* @property {Number} [options.shift_down=0.25] - Multiplier for e.g. SHIFT + CONTROL
* pressed while stepping
* @property {Number|Array} [options.snap=0] - Snap the value to a virtual grid
* with this distance. Numbers define the step size between snaps, an
* array contains a list of values to snap to.
* Using snap option with float values
* causes the range to reduce its minimum and maximum values depending
* on the amount of decimal digits because of the implementation of
* math in JavaScript. Using a step size of e.g. 1.125
* reduces the maximum usable value from 9,007,199,254,740,992 to
* 9,007,199,254,740.992 (note the decimal point).
*/
export class Range extends Base {
static get _options() {
return rangedOptionsTypes;
}
static get options() {
return [
rangedOptionsDefaults,
{
scale: 'linear',
reverse: false,
basis: 0,
min: -Infinity,
max: Infinity,
step: 1,
shift_up: 4,
shift_down: 0.25,
snap: 0,
},
];
}
static get static_events() {
return rangedEvents;
}
valueToBased(coef, size) {
return this.get('transformation').valueToBased(coef, size);
}
basedToValue(coef, size) {
return this.get('transformation').basedToValue(coef, size);
}
valueToPixel(value) {
return this.get('transformation').valueToPixel(value);
}
pixelToValue(pos) {
return this.get('transformation').pixelToValue(pos);
}
valueToCoef(value) {
return this.get('transformation').valueToCoef(value);
}
coefToValue(coef) {
return this.get('transformation').coefToValue(coef);
}
snapUp(value) {
return this.get('snap_module').snapUp(value);
}
snapDown(value) {
return this.get('snap_module').snapDown(value);
}
snap(value) {
return this.get('snap_module').snap(value);
}
}
/* jshint +W079 */
export function effectiveValue(
value,
base,
falling,
duration,
init,
value_time
) {
if (falling <= 0) return value;
const age = performance.now() - value_time;
const diff = age * (falling / duration);
if (age > init) {
if (value > base) {
value -= diff;
if (value < base) value = base;
} else {
value += diff;
if (value > base) value = base;
}
}
return value;
}