common.js

/**
 * @module common
 * @description Functions for various things such as matrix math
**/
'use strict';

const {cos, pow, sin, sqrt} = Math;

const BASE_16 = 16;
const SHIFT_KEYCODE = 16;

const isNumber = val => (typeof val === 'number');
const isUndefined = val => (val === undefined);
const isShiftKey = e => (e.keyCode === SHIFT_KEYCODE || e.which === SHIFT_KEYCODE);
const squared = val => pow(val, 2);

module.exports = {
    findKeyWithValue,
    generateRotationMatrix,
    hexToRgb,
    isNumber,
    isShiftKey,
    isUndefined,
    mapValues,
    not,
    multiplyMatrices,
    rgbToHex,
    squared,
    constant: val => () => val,
    getDistance: (a, b) => sqrt(squared(a) + squared(b)),
    identity: val => val
};
function findKeyWithValue(dict, value) {
    let keys = Object.keys(dict);
    let index = keys
        .map((key, index) => ((dict[key] === value) && index))
        .find(isNumber);
    return keys[index];
}
function mapValues(obj, fn) {
    return Object.keys(obj)
        .map(key => ({[key]: fn(obj[key])}))
        .reduce((o, item) => Object.assign(o, item), {});
}
function not(fn) {
    return function() {
        return !fn(...arguments);
    };
}
/**
 * @functino hexToRgb
 * @param {string} hex Hex value to be converted to RGB
 * @returns {?object} {r, g, b}
 * @see https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb/5624139#5624139
**/
function hexToRgb(hex) {
    let shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthandRegex, (m, r, g, b) => {
        return r + r + g + g + b + b;
    });
    let result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
    return result ? {
        r: parseInt(result[1], BASE_16),
        g: parseInt(result[2], BASE_16),
        b: parseInt(result[3], BASE_16)
    } : null;
}
/**
 * @function rgbToHex
 * @param {object} color RGB color data
 * @param {number} color.r Red value
 * @param {number} color.g Green value
 * @param {number} color.b Blue value
 * @returns {string} Hex string (no #)
 * @see https://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb/5624139#5624139
**/
function rgbToHex(color) {/* eslint-disable no-magic-numbers */
    let {r, g, b} = color;
    return '' + ((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1);
}/* eslint-enable no-magic-numbers */
/**
 * @function generateRotationMatrix
 * @description Generate rotation matrix for rotation with given x, y, and z components
 * @param {number} rotX x-component of rotation
 * @param {number} rotY y-component of rotation
 * @param {number} rotZ z-component of rotation
 * @returns {array[]} 3x3 array (nested array)
**/
function generateRotationMatrix(rotX, rotY, rotZ) {
    var xRotation = [
        [1, 0, 0],
        [0, cos(rotX), -sin(rotX)],
        [0, sin(rotX), cos(rotX)]
    ];
    var yRotation = [
        [cos(rotY), 0, sin(rotY)],
        [0, 1, 0],
        [-sin(rotY), 0, cos(rotY)]
    ];
    var zRotation = [
        [cos(rotZ), -sin(rotZ), 0],
        [sin(rotZ), cos(rotZ), 0],
        [0, 0, 1]
    ];
    return multiplyMatrices(multiplyMatrices(zRotation, yRotation), xRotation);
}
/**
 * @function multiplyMatrices
 * @description Matrix multiplication
 * @param {array[]} a Matrix A
 * @param {array[]} b Matric B
 * @returns {array[]} AxB
**/
function multiplyMatrices(a, b) {
    var aNumRows = a.length;
    var aNumCols = a[0].length;
    var bNumCols = b[0].length;
    var m = new Array(aNumRows); // initialize array of rows
    for (var r = 0; r < aNumRows; ++r) {
        m[r] = new Array(bNumCols); // initialize the current row
        for (var c = 0; c < bNumCols; ++c) {
            m[r][c] = 0; // initialize the current cell
            for (var i = 0; i < aNumCols; ++i) {
                m[r][c] += a[r][i] * b[i][c];
            }
        }
    }
    return m;
}