Home Reference Source Repository

src/util/colors.js

/**
 * Created by gavorhes on 11/3/2015.
 */
import provide from './provide';
import * as chk from './checkDefined';
let nm = provide('util.colors');


/**
 * helper function to convert to hex
 * @param {number|string} x - the number to convert to hex
 * @returns {string} number as hex
 * @private
 */
function _hex(x) {
    let hexDigits = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"];

    return isNaN(x) ? "00" : hexDigits[(x - x % 16) / 16] + hexDigits[x % 16];
}

/**
 * converts an RGB string to hex
 * @param {string} rgb - rgb color
 * @returns {string} rbg as hex
 */
export function rgb2hex(rgb) {
    let rgb1 = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);

    return ("#" + _hex(rgb1[1]) + _hex(rgb1[2]) + _hex(rgb1[3])).toUpperCase();
}

nm.rgb2hex = rgb2hex;


/**
 * Convert hex string to RGB or RGBA string
 * @param {string} hexString - hex color string
 * @param {number} [alphaVal=undefined] Alpha value
 * @returns {string} - rgb or rgba color
 */
export function hexAlphaToRgbOrRgba(hexString, alphaVal) {
    hexString = ((hexString.charAt(0) == "#") ? hexString.substring(1, 7) : hexString);
    let r = parseInt(hexString.substring(0, 2), 16).toString() || '0';
    let g = parseInt(hexString.substring(2, 4), 16).toString() || '0';
    let b = parseInt(hexString.substring(4, 6), 16).toString() || '0';
    if (alphaVal) {
        return `rgba(${r},${g},${b},${alphaVal})`;
    } else {
        return `rgba(${r},${g},${b})`;
    }
}

nm.hexAlphaToRgbOrRgba = hexAlphaToRgbOrRgba;


/**
 * adds alpha value to rgb string 'rgb(r, b, g)', returns 'rgba(r, g, b, a)'
 * @param {string} rgb - rgb color
 * @param {number} alpha - alpha value 0 to 1
 * @returns {string} rgba color
 */
export function rgbToRgba(rgb, alpha) {
    let pieces = rgb.split(',');
    pieces[0] = pieces[0].replace('rgb', 'rgba');
    pieces[2] = pieces[2].replace(')', '');
    pieces.push(' ' + alpha.toFixed(1) + ')');

    return pieces.join(',');
}

nm.rgbToRgba = rgbToRgba;


/**
 * @typedef {function} colorLookupByNumber
 * @param {number} num - the number to use to retrieve the color
 * @returns {string} rgb color
 */


/**
 * Make a blue green red gradient
 * @param {number} minVal - minimum value
 * @param {number} maxVal - maximum value
 * @param {boolean} flipColors - if the colors should be flipped
 * @returns {colorLookupByNumber} color lookup function
 */
export function makeBlueGreenRedGradient(minVal, maxVal, flipColors) {

    if (typeof flipColors != "boolean") {
        flipColors = false;
    }

    return function (theVal) {
        let r, g, b;
        let ratio;

        if (chk.undefinedOrNull(theVal)) {
            return 'rgb(100,100,100)';
        }

        let percent = (theVal - minVal) / (maxVal - minVal);

        if (flipColors == true) {
            percent = 1 - percent;
        }

        if (percent >= 1) {
            r = 255;
            g = 0;
            b = 0;
        } else if (percent <= 0) {
            r = 0;
            g = 0;
            b = 255;
        } else if (percent < .25) {
            // green up, blue constant
            r = 0;
            g = Math.floor(255 * percent / 0.25);
            b = 255;
        } else if (percent < 0.50) {
            //blue down, green constant
            ratio = (percent - 0.25) / 0.25;
            r = 0;
            g = 255;
            b = 255 - Math.floor(255 * ratio);
        } else if (percent < 0.75) {
            // red up, green constant
            ratio = (percent - 0.5) / 0.25;
            r = Math.floor(255 * ratio);
            g = 255;
            b = 0;
        } else {
            // green down, red constant
            ratio = (percent - 0.75) / 0.25;
            r = 255;
            g = 255 - Math.floor(255 * ratio);
            b = 0;
        }

        r = r.toFixed();
        g = g.toFixed();
        b = b.toFixed();

        return 'rgb(' + r + ',' + g + ',' + b + ')';
    };
}

nm.makeBlueGreenRedGradient = makeBlueGreenRedGradient;


/**
 * Create a function that will return colors based on a gradient
 * @param {number} median - median value
 * @param {number} stdDev - standard deviation
 * @param {boolean} flipColors - if the colors should be flipped
 * @returns {colorLookupByNumber} color lookup function
 */
export function makeBlueGreenRedGradientZScore(median, stdDev, flipColors) {

    let grd = makeBlueGreenRedGradient(-2.5, 2.5, flipColors);

    return function (theVal) {

        let zScore;
        if (theVal == null) {
            zScore = null;
        } else {
            zScore = (theVal - median) / stdDev;
        }

        return grd(zScore);
    };
}

nm.makeBlueGreenRedGradientZScore = makeBlueGreenRedGradientZScore;