123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- /**
- * Copyright (c) 2018-2022 mol* contributors, licensed under MIT, See LICENSE file for more info.
- *
- * @author Alexander Rose <alexander.rose@weirdbyte.de>
- */
- import { NumberArray } from '../../mol-util/type-helpers';
- import { Vec3 } from '../../mol-math/linear-algebra';
- import { Hcl } from './spaces/hcl';
- import { Lab } from './spaces/lab';
- /** RGB color triplet expressed as a single number */
- export type Color = { readonly '@type': 'color' } & number
- export function Color(hex: number) { return hex as Color; }
- export namespace Color {
- export function toStyle(hexColor: Color) {
- return `rgb(${hexColor >> 16 & 255}, ${hexColor >> 8 & 255}, ${hexColor & 255})`;
- }
- export function toHexStyle(hexColor: Color) {
- return '#' + ('000000' + hexColor.toString(16)).slice(-6);
- }
- export function toHexString(hexColor: Color) {
- return '0x' + ('000000' + hexColor.toString(16)).slice(-6);
- }
- export function toRgbString(hexColor: Color) {
- return `RGB: ${Color.toRgb(hexColor).join(', ')}`;
- }
- export function toRgb(hexColor: Color): [number, number, number] {
- return [hexColor >> 16 & 255, hexColor >> 8 & 255, hexColor & 255];
- }
- export function toRgbNormalized(hexColor: Color): [number, number, number] {
- return [(hexColor >> 16 & 255) / 255, (hexColor >> 8 & 255) / 255, (hexColor & 255) / 255];
- }
- export function fromHexStyle(s: string): Color {
- return parseInt(s.replace('#', '0x')) as Color;
- }
- export function fromHexString(s: string): Color {
- return parseInt(s) as Color;
- }
- export function fromRgb(r: number, g: number, b: number): Color {
- return ((r << 16) | (g << 8) | b) as Color;
- }
- export function fromNormalizedRgb(r: number, g: number, b: number): Color {
- return (((r * 255) << 16) | ((g * 255) << 8) | (b * 255)) as Color;
- }
- export function fromArray(array: NumberArray, offset: number): Color {
- return fromRgb(array[offset], array[offset + 1], array[offset + 2]);
- }
- export function fromNormalizedArray(array: NumberArray, offset: number): Color {
- return fromNormalizedRgb(array[offset], array[offset + 1], array[offset + 2]);
- }
- /** Copies hex color to rgb array */
- export function toArray(hexColor: Color, array: NumberArray, offset: number) {
- array[offset] = (hexColor >> 16 & 255);
- array[offset + 1] = (hexColor >> 8 & 255);
- array[offset + 2] = (hexColor & 255);
- return array;
- }
- /** Copies normalized (0 to 1) hex color to rgb array */
- export function toArrayNormalized<T extends NumberArray>(hexColor: Color, array: T, offset: number) {
- array[offset] = (hexColor >> 16 & 255) / 255;
- array[offset + 1] = (hexColor >> 8 & 255) / 255;
- array[offset + 2] = (hexColor & 255) / 255;
- return array;
- }
- /** Copies hex color to rgb vec3 */
- export function toVec3(out: Vec3, hexColor: Color) {
- out[0] = (hexColor >> 16 & 255);
- out[1] = (hexColor >> 8 & 255);
- out[2] = (hexColor & 255);
- return out;
- }
- /** Copies normalized (0 to 1) hex color to rgb vec3 */
- export function toVec3Normalized(out: Vec3, hexColor: Color) {
- out[0] = (hexColor >> 16 & 255) / 255;
- out[1] = (hexColor >> 8 & 255) / 255;
- out[2] = (hexColor & 255) / 255;
- return out;
- }
- /** Linear interpolation between two colors in rgb space */
- export function interpolate(c1: Color, c2: Color, t: number): Color {
- const r1 = c1 >> 16 & 255;
- const g1 = c1 >> 8 & 255;
- const b1 = c1 & 255;
- const r2 = c2 >> 16 & 255;
- const g2 = c2 >> 8 & 255;
- const b2 = c2 & 255;
- const r = r1 + (r2 - r1) * t;
- const g = g1 + (g2 - g1) * t;
- const b = b1 + (b2 - b1) * t;
- return ((r << 16) | (g << 8) | b) as Color;
- }
- const tmpSaturateHcl = [0, 0, 0] as Hcl;
- export function saturate(c: Color, amount: number): Color {
- Hcl.fromColor(tmpSaturateHcl, c);
- return Hcl.toColor(Hcl.saturate(tmpSaturateHcl, tmpSaturateHcl, amount));
- }
- export function desaturate(c: Color, amount: number): Color {
- return saturate(c, -amount);
- }
- const tmpDarkenLab = [0, 0, 0] as Lab;
- export function darken(c: Color, amount: number): Color {
- Lab.fromColor(tmpDarkenLab, c);
- return Lab.toColor(Lab.darken(tmpDarkenLab, tmpDarkenLab, amount));
- }
- export function lighten(c: Color, amount: number): Color {
- return darken(c, -amount);
- }
- //
- function _sRGBToLinear(c: number) {
- return (c < 0.04045) ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
- }
- export function sRGBToLinear(c: Color) {
- return fromNormalizedRgb(
- _sRGBToLinear((c >> 16 & 255) / 255),
- _sRGBToLinear((c >> 8 & 255) / 255),
- _sRGBToLinear((c & 255) / 255)
- );
- }
- function _linearToSRGB(c: number) {
- return (c < 0.0031308) ? c * 12.92 : 1.055 * (Math.pow(c, 0.41666)) - 0.055;
- }
- export function linearToSRGB(c: Color) {
- return fromNormalizedRgb(
- _linearToSRGB((c >> 16 & 255) / 255),
- _linearToSRGB((c >> 8 & 255) / 255),
- _linearToSRGB((c & 255) / 255)
- );
- }
- }
- export type ColorListEntry = Color | [Color, number /** normalized value from 0 to 1 */]
- export interface ColorList {
- label: string
- description: string
- list: ColorListEntry[]
- type: 'sequential' | 'diverging' | 'qualitative'
- }
- export function ColorList(label: string, type: 'sequential' | 'diverging' | 'qualitative', description: string, list: (number | [number, number])[]): ColorList {
- return { label, description, list: list as Color[], type };
- }
- export type ColorTable<T extends { [k: string]: number[] }> = { [k in keyof T]: Color[] }
- export function ColorTable<T extends { [k: string]: number[] }>(o: T) { return o as unknown as ColorTable<T>; }
- export type ColorMap<T extends { [k: string]: number }> = { [k in keyof T]: Color }
- export function ColorMap<T extends { [k: string]: number }>(o: T) { return o as unknown as ColorMap<T>; }
- export function getAdjustedColorMap<T extends { [k: string]: number }>(map: ColorMap<T>, saturation: number, lightness: number) {
- const adjustedMap: { [k: string]: Color } = {};
- for (const e in map) {
- let c = map[e];
- c = Color.saturate(c, saturation);
- c = Color.darken(c, -lightness);
- adjustedMap[e] = c;
- }
- return adjustedMap as ColorMap<T>;
- }
- export type ColorSwatch = [string, Color][]
- export function ColorSwatch(l: [string, number][]) { return l as unknown as ColorSwatch; }
|