diff --git a/src/mol-util/color/color.ts b/src/mol-util/color/color.ts index 9bc745987476d8e70ee108524d3023295d56000a..b55415c7b4c163d8bfbd580700ad309efd3c3315 100644 --- a/src/mol-util/color/color.ts +++ b/src/mol-util/color/color.ts @@ -1,5 +1,5 @@ /** - * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info. + * Copyright (c) 2018-2023 mol* contributors, licensed under MIT, See LICENSE file for more info. * * @author Alexander Rose <alexander.rose@weirdbyte.de> */ @@ -15,19 +15,19 @@ export type Color = { readonly '@type': 'color' } & number export function Color(hex: number) { return hex as Color; } export namespace Color { - export function toStyle(hexColor: Color) { + export function toStyle(hexColor: Color): string { return `rgb(${hexColor >> 16 & 255}, ${hexColor >> 8 & 255}, ${hexColor & 255})`; } - export function toHexStyle(hexColor: Color) { + export function toHexStyle(hexColor: Color): string { return '#' + ('000000' + hexColor.toString(16)).slice(-6); } - export function toHexString(hexColor: Color) { + export function toHexString(hexColor: Color): string { return '0x' + ('000000' + hexColor.toString(16)).slice(-6); } - export function toRgbString(hexColor: Color) { + export function toRgbString(hexColor: Color): string { return `RGB: ${Color.toRgb(hexColor).join(', ')}`; } @@ -64,7 +64,7 @@ export namespace Color { } /** Copies hex color to rgb array */ - export function toArray(hexColor: Color, array: NumberArray, offset: number) { + export function toArray<T extends NumberArray>(hexColor: Color, array: T, offset: number): T { array[offset] = (hexColor >> 16 & 255); array[offset + 1] = (hexColor >> 8 & 255); array[offset + 2] = (hexColor & 255); @@ -72,7 +72,7 @@ export namespace Color { } /** Copies normalized (0 to 1) hex color to rgb array */ - export function toArrayNormalized<T extends NumberArray>(hexColor: Color, array: T, offset: number) { + export function toArrayNormalized<T extends NumberArray>(hexColor: Color, array: T, offset: number): T { array[offset] = (hexColor >> 16 & 255) / 255; array[offset + 1] = (hexColor >> 8 & 255) / 255; array[offset + 2] = (hexColor & 255) / 255; @@ -80,7 +80,7 @@ export namespace Color { } /** Copies hex color to rgb vec3 */ - export function toVec3(out: Vec3, hexColor: Color) { + export function toVec3(out: Vec3, hexColor: Color): Vec3 { out[0] = (hexColor >> 16 & 255); out[1] = (hexColor >> 8 & 255); out[2] = (hexColor & 255); @@ -88,7 +88,7 @@ export namespace Color { } /** Copies normalized (0 to 1) hex color to rgb vec3 */ - export function toVec3Normalized(out: Vec3, hexColor: Color) { + export function toVec3Normalized(out: Vec3, hexColor: Color): Vec3 { out[0] = (hexColor >> 16 & 255) / 255; out[1] = (hexColor >> 8 & 255) / 255; out[2] = (hexColor & 255) / 255; @@ -131,13 +131,38 @@ export namespace Color { return darken(c, -amount); } + function _luminance(x: number): number { + return x <= 0.03928 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4); + } + + /** + * Relative luminance + * http://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + */ + export function luminance(c: Color): number { + const r = _luminance((c >> 16 & 255) / 255); + const g = _luminance((c >> 8 & 255) / 255); + const b = _luminance((c & 255) / 255); + return 0.2126 * r + 0.7152 * g + 0.0722 * b; + } + + /** + * WCAG contrast ratio + * http://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef + */ + export function contrast(a: Color, b: Color): number { + const l1 = luminance(a); + const l2 = luminance(b); + return l1 > l2 ? (l1 + 0.05) / (l2 + 0.05) : (l2 + 0.05) / (l1 + 0.05); + }; + // - function _sRGBToLinear(c: number) { + function _sRGBToLinear(c: number): number { return (c < 0.04045) ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4); } - export function sRGBToLinear(c: Color) { + export function sRGBToLinear(c: Color): Color { return fromNormalizedRgb( _sRGBToLinear((c >> 16 & 255) / 255), _sRGBToLinear((c >> 8 & 255) / 255), @@ -145,11 +170,11 @@ export namespace Color { ); } - function _linearToSRGB(c: number) { + function _linearToSRGB(c: number): number { return (c < 0.0031308) ? c * 12.92 : 1.055 * (Math.pow(c, 0.41666)) - 0.055; } - export function linearToSRGB(c: Color) { + export function linearToSRGB(c: Color): Color { return fromNormalizedRgb( _linearToSRGB((c >> 16 & 255) / 255), _linearToSRGB((c >> 8 & 255) / 255),