All files luminosity.ts

100% Statements 16/16
100% Branches 15/15
100% Functions 4/4
100% Lines 16/16
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 762x                         2x         12x 12x   12x                           12x 6x     12x                       240x 240x 240x   240x                   2x       14x 18x   18x      
import Chroma from "chroma-js";
 
/**
 * Type definition for a luminosity switch
 */
export type LuminositySwitch = (a: any, b: any) => any;
 
/**
 * Adjust a color to a specific luminosity. This function is almost a direct copy of
 * https://github.com/gka/chroma.js/blob/master/src/io/luminance.coffee, except that
 * it accepts a rounding function. This is necessary to prevent contrast ratios being slightly below
 * their target due to rounding RGB channel values the wrong direction.
 */
export function luminance(
    targetLuminance: number,
    sourceColor: Chroma,
    round?: (value: number) => number
): number[] {
    const sourceLuminosity: number = sourceColor.luminance();
    const maxIterations: number = 20;
    let color: any =
        sourceLuminosity > targetLuminance
            ? adjustLuminance(
                  Chroma("black"),
                  sourceColor,
                  targetLuminance,
                  maxIterations
              )
            : adjustLuminance(
                  sourceColor,
                  Chroma("white"),
                  targetLuminance,
                  maxIterations
              );
 
    if (typeof round === "function") {
        color = Chroma(color.rgb(false).map(round));
    }
 
    return color.rgba();
}
 
/**
 * Recursive function to adjust the luminosity value of a color
 */
function adjustLuminance(
    low: Chroma,
    high: Chroma,
    targetLuminance: number,
    iterations: number
): Chroma {
    const middle: Chroma = low.interpolate(high, 0.5, "rgb");
    const middleLuminosity: number = middle.luminance();
    iterations -= 1;
 
    return Math.abs(targetLuminance - middleLuminosity) < 1e-7 || !iterations
        ? middle
        : middleLuminosity > targetLuminance
            ? adjustLuminance(low, middle, targetLuminance, iterations)
            : adjustLuminance(middle, high, targetLuminance, iterations);
}
 
/**
 * Returns a function that selects one of two arguments based on the value of luminance inputs.
 */
export function luminanceSwitch(
    operandLuminance: number,
    referenceLuminance: number
): LuminositySwitch {
    return (a: any, b: any): any => {
        const difference: number = operandLuminance - referenceLuminance;
 
        return difference < 0 || (difference === 0 && referenceLuminance > 0.5) ? b : a;
    };
}