moremath
Version:
The missing JavaScript Math functions
162 lines (157 loc) • 6.05 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.MoreMath = {}));
})(this, (function (exports) { 'use strict';
/**
* @author Zeh Fernando
*/
// Vars
var _uniqueInt = 1;
/**
* Maps a value from a range, determined by old minimum and maximum values, to a new range,
* determined by new minimum and maximum values. These minimum and maximum values are
* referential; the new value is not clamped by them.
*
* @param value The value to be re-mapped.
* @param oldMin The previous minimum value.
* @param oldMax The previous maximum value.
* @param newMin The new minimum value.
* @param newMax The new maximum value.
* @return The new value, mapped to the new range.
*/
function map(value, oldMin, oldMax, newMin, newMax, shouldClamp) {
if (newMin === void 0) { newMin = 0; }
if (newMax === void 0) { newMax = 1; }
if (shouldClamp === void 0) { shouldClamp = false; }
if (oldMin === oldMax)
return newMin;
var p = ((value - oldMin) / (oldMax - oldMin)) * (newMax - newMin) + newMin;
if (shouldClamp)
p = newMin < newMax ? clamp(p, newMin, newMax) : clamp(p, newMax, newMin);
return p;
}
/**
* Clamps a number to a range, by restricting it to a minimum and maximum values: if the passed
* value is lower than the minimum value, it's replaced by the minimum; if it's higher than the
* maximum value, it's replaced by the maximum; if neither, it's unchanged.
*
* @param value The value to be clamped.
* @param min Minimum value allowed.
* @param max Maximum value allowed.
* @return The newly clamped value.
*/
function clamp(value, min, max) {
if (min === void 0) { min = 0; }
if (max === void 0) { max = 1; }
return value < min ? min : value > max ? max : value;
}
/**
* Clamps a number to a range, by restricting it to a range of values: if the passed
* value is lower than the minimum value, it's replaced by the minimum; if it's higher than the
* maximum value, it's replaced by the maximum; if neither, it's unchanged.
*
* This function is similar to clamp(), but it switches the range values if necessary, without
* assuming the first value is the lower value.
*
* @param value The value to be clamped.
* @param clamp1 One end of the allowed range.
* @param clamp2 Other end of the allowed range.
* @return The newly clamped value.
*/
function clampAuto(value, clamp1, clamp2) {
if (clamp1 === void 0) { clamp1 = 0; }
if (clamp2 === void 0) { clamp2 = 1; }
if (clamp2 < clamp1) {
var v = clamp2;
clamp2 = clamp1;
clamp1 = v;
}
return value < clamp1 ? clamp1 : value > clamp2 ? clamp2 : value;
}
/**
* Returns a power of two value that is higher than the passed value.
*
* @param value The minimum value desired.
* @return A power of two value that is equal to or higher than the input value.
*/
function getHighestPowerOfTwo(value) {
var c = 1;
while (c < value)
c <<= 1;
return c;
}
/**
* Returns a unique number for this session. This is simply a global integer sequence, starting at 1.
*
* @return A unique integer for the session.
*/
function getUniqueNumber() {
return _uniqueInt++;
}
/**
* Returns whether a number is a power of two (2, 4, 8, 16, etc).
*
* @param value A number to be tested.
* @return Whether the input number is a power of two.
*/
function isPowerOfTwo(value) {
return value > 0 && (value & (value - 1)) === 0;
}
/**
* Restricts a value to a range, by restricting it to a minimum and maximum values but folding the
* value to the range instead of simply clamping to the minimum and maximum. It works like a
* more powerful Modulo function because it allows arbitrary ranges.
*
* @param value The value to be clamped.
* @param min Minimum value allowed.
* @param max Maximum value allowed. Never reached; the minimum would be used instead.
* @return The new value, mapped to the range.
*
* @example Some examples:
* console.log(rangeMod(14, 0, 10));
* // Result: 4
*
* console.log(rangeMod(360, 0, 360));
* // Result: 0
*
* console.log(rangeMod(360, -180, 180));
* // Result: 0
*
* console.log(rangeMod(21, 0, 10));
* // Result: 1
*
* console.log(rangeMod(-98, 0, 100));
* // Result: 2
*/
function rangeMod(value, min, pseudoMax) {
var range = pseudoMax - min;
value = (value - min) % range;
if (value < 0)
value = range - (-value % range);
value += min;
return value;
}
var defs = {
clamp: clamp,
clampAuto: clampAuto,
getHighestPowerOfTwo: getHighestPowerOfTwo,
getUniqueNumber: getUniqueNumber,
isPowerOfTwo: isPowerOfTwo,
map: map,
rangeMod: rangeMod,
};
// export default class MathUtils {
// static DEG2RAD: number;
// static RAD2DEG: number;
exports.clamp = clamp;
exports.clampAuto = clampAuto;
exports.default = defs;
exports.getHighestPowerOfTwo = getHighestPowerOfTwo;
exports.getUniqueNumber = getUniqueNumber;
exports.isPowerOfTwo = isPowerOfTwo;
exports.map = map;
exports.rangeMod = rangeMod;
Object.defineProperty(exports, '__esModule', { value: true });
}));
module.exports.default = module.exports; // Terrible injection just so it works regardless of how it's required