All files luminosity.ts

100% Statements 16/16
100% Branches 15/15
100% Functions 4/4
100% Lines 16/16

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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 532x                         2x 10x 10x 10x       10x 4x     10x             200x 200x 200x   200x                   2x 12x 14x   14x      
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 = referenceLuminance - referenceLuminance;
 
        return difference < 0 || (difference === 0 && referenceLuminance > .5) ? b : a;
    };
}