@checksub_team/peaks_timeline
Version:
JavaScript UI component for displaying audio waveforms
434 lines (353 loc) • 10.7 kB
JavaScript
/**
* @file
*
* Some general utility functions.
*
* @module utils
*/
define([
'uuid'
], function(UUID) {
'use strict';
if (typeof Number.isFinite !== 'function') {
Number.isFinite = function isFinite(value) {
if (typeof value !== 'number') {
return false;
}
// Check for NaN and infinity
// eslint-disable-next-line no-self-compare
if (value !== value || value === Infinity || value === -Infinity) {
return false;
}
return true;
};
}
function zeroPad(number) {
return number < 10 ? '0' + number : number;
}
return {
/**
* Returns a formatted time string.
*
* @param {Number} time The time to be formatted, in seconds.
* @param {Boolean} dropHundredths Don't display hundredths of a second if true.
* @returns {String}
*/
formatTime: function(time, dropHundredths) {
var result = [];
time = this.roundTime(time);
var hundredths = Math.round((time % 1) * 100);
var seconds = Math.floor(time);
var minutes = Math.floor(seconds / 60);
var hours = Math.floor(minutes / 60);
if (hours > 0) {
result.push(hours); // Hours
}
result.push(minutes % 60); // Mins
result.push(seconds % 60); // Seconds
for (var i = 0; i < result.length; i++) {
result[i] = zeroPad(result[i]);
}
result = result.join(':');
if (!dropHundredths) {
result += '.' + zeroPad(hundredths);
}
return result;
},
/**
* Rounds the given value up to the nearest given multiple.
*
* @param {Number} value
* @param {Number} multiple
* @returns {Number}
*
* @example
* roundUpToNearest(5.5, 3); // returns 6
* roundUpToNearest(141.0, 10); // returns 150
* roundUpToNearest(-5.5, 3); // returns -6
*/
roundUpToNearest: function(value, multiple) {
if (multiple === 0) {
return 0;
}
var multiplier = 1;
if (value < 0.0) {
multiplier = -1;
value = -value;
}
var roundedUp = Math.ceil(value);
return multiplier * (((roundedUp + multiple - 1) / multiple) | 0) * multiple;
},
roundUpToNearestPositive: function(value, multiple) {
if (multiple === 0) {
return 0;
}
var multiplier = 1;
if (value < 0.0) {
value = 0;
}
var roundedUp = Math.ceil(value);
return multiplier * (((roundedUp + multiple - 1) / multiple) | 0) * multiple;
},
clamp: function(value, min, max) {
if (value < min) {
return min;
}
else if (value > max) {
return max;
}
else {
return value;
}
},
extend: function(to, from) {
for (var key in from) {
if (this.objectHasProperty(from, key)) {
to[key] = from[key];
}
}
return to;
},
/**
* Checks whether the given array contains values in ascending order.
*
* @param {Array<Number>} array The array to test
* @returns {Boolean}
*/
isInAscendingOrder: function(array) {
if (array.length === 0) {
return true;
}
var value = array[0];
for (var i = 1; i < array.length; i++) {
if (value >= array[i]) {
return false;
}
value = array[i];
}
return true;
},
/**
* Checks whether the given value is a boolean.
*
* @param {Boolean} value The value to test
* @returns {Boolean}
*/
isBoolean: function(value) {
return typeof value === 'boolean';
},
/**
* Checks whether the given value is a number.
*
* @param {Number} value The value to test
* @returns {Boolean}
*/
isNumber: function(value) {
return typeof value === 'number';
},
/**
* Checks whether the given value is an integer.
*
* @param {Number} value The value to test
* @returns {Boolean}
*/
isInteger: function(value) {
return typeof value === 'number' && Number.isInteger(value);
},
/**
* Checks whether the given value is a valid timestamp.
*
* @param {Number} value The value to test
* @returns {Boolean}
*/
isValidTime: function(value) {
return (typeof value === 'number') && Number.isFinite(value);
},
/**
* Checks whether the given value is a valid object.
*
* @param {Object|Array} value The value to test
* @returns {Boolean}
*/
isObject: function(value) {
return (value !== null) && (typeof value === 'object')
&& !Array.isArray(value);
},
/**
* Checks whether the given value is a valid string.
*
* @param {String} value The value to test
* @returns {Boolean}
*/
isString: function(value) {
return typeof value === 'string';
},
/**
* Checks whether the given value is a valid ArrayBuffer.
*
* @param {ArrayBuffer} value The value to test
* @returns {Boolean}
*/
isArrayBuffer: function(value) {
return Object.prototype.toString.call(value).includes('ArrayBuffer');
},
/**
* Checks whether the given value is null or undefined.
*
* @param {Object} value The value to test
* @returns {Boolean}
*/
isNullOrUndefined: function(value) {
return value === undefined || value === null;
},
/**
* Checks whether the given value is a function.
*
* @param {Function} value The value to test
* @returns {Boolean}
*/
isFunction: function(value) {
return typeof value === 'function';
},
/**
* Checks whether the given value is a valid HTML element.
*
* @param {HTMLElement} value The value to test
* @returns {Boolean}
*/
isHTMLElement: function(value) {
return value instanceof HTMLElement;
},
/**
* Checks whether the given value is a valid CSS color.
*
* @param {String} value The value to test
* @returns {Boolean}
*/
isValidColor: function(value) {
var s = new Option().style;
s.color = value;
return s.color !== '';
},
isValidIndicatorType: function(value) {
return ['volume', 'noVolume', 'visibility', 'noVisibility', 'default'].includes(value);
},
objectHasProperty: function(object, field) {
return Object.prototype.hasOwnProperty.call(object, field);
},
roundTime: function(rawTime) {
return parseFloat((Math.round(rawTime * 100) / 100).toFixed(2));
},
removeLineBreaks: function(rawText) {
var text = rawText.replace(/(\r\n|\n|\r)/gm, ' ');
return text.replace(/ +(?= )/g,'');
},
createUuidv4: function() {
return UUID.v4();
},
shadeColor: function(color, percent) {
var R, G, B;
if (color.length === 4) {
R = parseInt(2 * color[1], 16);
G = parseInt(2 * color[2], 16);
B = parseInt(2 * color[3], 16);
}
else {
R = parseInt(color.substring(1,3), 16);
G = parseInt(color.substring(3,5), 16);
B = parseInt(color.substring(5,7), 16);
}
R = Math.round(R * (100 + percent) / 100);
G = Math.round(G * (100 + percent) / 100);
B = Math.round(B * (100 + percent) / 100);
R = (R < 255) ? R : 255;
G = (G < 255) ? G : 255;
B = (B < 255) ? B : 255;
var RR = ((R.toString(16).length === 1) ? '0' + R.toString(16) : R.toString(16));
var GG = ((G.toString(16).length === 1) ? '0' + G.toString(16) : G.toString(16));
var BB = ((B.toString(16).length === 1) ? '0' + B.toString(16) : B.toString(16));
return '#' + RR + GG + BB;
},
// ==================== Performance Utilities ====================
/**
* Schedules work during browser idle time.
* Falls back to setTimeout if requestIdleCallback is not available.
*
* @param {Function} callback Function to execute
* @param {Object} options Options object with timeout property
* @returns {Number} ID that can be used to cancel
*/
scheduleIdle: function(callback, options) {
options = options || { timeout: 50 };
if (typeof window !== 'undefined' && window.requestIdleCallback) {
return window.requestIdleCallback(callback, options);
}
return setTimeout(function() {
callback({
didTimeout: true,
timeRemaining: function() {
return 0;
}
});
}, 0);
},
/**
* Cancels a scheduled idle callback.
*
* @param {Number} id The ID returned by scheduleIdle
*/
cancelIdle: function(id) {
if (typeof window !== 'undefined' && window.cancelIdleCallback) {
window.cancelIdleCallback(id);
}
else {
clearTimeout(id);
}
},
/**
* Creates a simple LRU (Least Recently Used) cache.
*
* @param {Number} maxSize Maximum number of items to cache
* @returns {Object} Cache with get(), set(), has(), delete(), clear() methods
*/
createLRUCache: function(maxSize) {
var cache = new Map();
maxSize = maxSize || 100;
return {
get: function(key) {
if (!cache.has(key)) {
return undefined;
}
// Move to end (most recently used)
var value = cache.get(key);
cache.delete(key);
cache.set(key, value);
return value;
},
set: function(key, value) {
if (cache.has(key)) {
cache.delete(key);
}
else if (cache.size >= maxSize) {
// Delete oldest (first) entry
var firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, value);
},
has: function(key) {
return cache.has(key);
},
delete: function(key) {
return cache.delete(key);
},
clear: function() {
cache.clear();
},
size: function() {
return cache.size;
}
};
}
};
});