Skip to content

Commit

Permalink
feat(color): add RGBA/HSLA wrapper types, update convert
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Dec 24, 2018
1 parent 404ac54 commit 610699a
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 21 deletions.
4 changes: 4 additions & 0 deletions packages/color/src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export enum ColorMode {
CSS,
}

export interface IColor {
readonly mode: ColorMode;
}

// RGBA constants

export const BLACK = Object.freeze([0, 0, 0, 1]);
Expand Down
17 changes: 17 additions & 0 deletions packages/color/src/clamp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@ import { Color, ReadonlyColor } from "./api";
import { ensureAlpha } from "./ensure-alpha";
import { ensureHue } from "./ensure-hue";

/**
* Clamps all color channels to [0,1] interval and calls `ensureAlpha()`
* to ensure alpha channel is defined (if missing sets it to `alpha`
* (default: 1)).
*
* @param out
* @param src
* @param alpha
*/
export const clamp =
(out: Color, src: ReadonlyColor, alpha = 1) =>
setC4(
Expand All @@ -14,6 +23,14 @@ export const clamp =
ensureAlpha(src[3], alpha)
);

/**
* Similar to `clamp`, but calls `ensureHue()` to fold (instead of
* clamping) the hue into [0,1] interval.
*
* @param out
* @param src
* @param alpha
*/
export const clampH =
(out: Color, src: ReadonlyColor, alpha = 1) =>
setC4(
Expand Down
69 changes: 48 additions & 21 deletions packages/color/src/convert.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { defmulti, Implementation3, MultiFn3 } from "@thi.ng/defmulti";
import { Color, ColorMode, ReadonlyColor } from "./api";
import { defmulti, Implementation3, MultiFn2O } from "@thi.ng/defmulti";
import { illegalArgs } from "@thi.ng/errors/illegal-arguments";
import {
Color,
ColorMode,
IColor,
ReadonlyColor
} from "./api";
import { hsiaRgba } from "./hsia-rgba";
import { hslaCss } from "./hsla-css";
import { hslaRgba } from "./hsla-rgba";
import { hsvaCss } from "./hsva-css";
Expand All @@ -8,37 +15,52 @@ import { intCss } from "./int-css";
import { intRgba } from "./int-rgba";
import { parseCss } from "./parse-css";
import { rgbaCss } from "./rgba-css";
import { rgbaHsia } from "./rgba-hsia";
import { rgbaHsla } from "./rgba-hsla";
import { rgbaHsva } from "./rgba-hsva";
import { rgbaInt } from "./rgba-int";
import { hsiaRgba } from "./hsia-rgba";

export const convert: MultiFn3<string | number | ReadonlyColor, ColorMode, ColorMode, Color | string | number> =
defmulti((...args: any[]) => convID(args[1], args[2]));

export const asRGBA = (col: string | number | ReadonlyColor, mode: ColorMode) =>
<Color>convert(col, ColorMode.RGBA, mode);

export const asHSLA = (col: string | number | ReadonlyColor, mode: ColorMode) =>
<Color>convert(col, ColorMode.HSLA, mode);

export const asHSVA = (col: string | number | ReadonlyColor, mode: ColorMode) =>
<Color>convert(col, ColorMode.HSLA, mode);

export const asCSS = (col: string | number | ReadonlyColor, mode: ColorMode) =>
<string>convert(col, ColorMode.CSS, mode);
export const convert: MultiFn2O<string | number | ReadonlyColor | IColor, ColorMode, ColorMode, Color | string | number> =
defmulti(
(col, mdest, msrc) =>
(<any>col).mode !== undefined ?
`${ColorMode[mdest]}-${ColorMode[<ColorMode>(<any>col).mode]}` :
msrc !== undefined ?
`${ColorMode[mdest]}-${ColorMode[msrc]}` :
illegalArgs(`missing src color mode`)
);

const convID =
(dest: ColorMode, src: ColorMode) =>
`${ColorMode[dest]}-${ColorMode[src]}`;
export function asRGBA(col: IColor): Color;
export function asRGBA(col: string | number | ReadonlyColor, mode: ColorMode): Color;
export function asRGBA(col: any, mode?: ColorMode) {
return <Color>convert(col, ColorMode.RGBA, mode);
}

export function asHSLA(col: IColor): Color;
export function asHSLA(col: string | number | ReadonlyColor, mode: ColorMode): Color;
export function asHSLA(col: any, mode?: ColorMode) {
return <Color>convert(col, ColorMode.HSLA, mode);
}

export function asHSVA(col: IColor): Color;
export function asHSVA(col: string | number | ReadonlyColor, mode: ColorMode): Color;
export function asHSVA(col: any, mode?: ColorMode) {
return <Color>convert(col, ColorMode.HSVA, mode);
}

export function asCSS(col: IColor): string;
export function asCSS(col: string | number | ReadonlyColor, mode: ColorMode): string;
export function asCSS(col: any, mode?: ColorMode) {
return <string>convert(col, ColorMode.CSS, mode);
}

const defConversion = (
dest: ColorMode,
src: ColorMode,
impl: Implementation3<string | number | ReadonlyColor, ColorMode, ColorMode, Color | string | number>
) =>
convert.add(
convID(dest, src),
`${ColorMode[dest]}-${ColorMode[src]}`,
impl
);

Expand Down Expand Up @@ -139,6 +161,11 @@ defConversion(
(x: ReadonlyColor) => rgbaCss(x)
);

defConversion(
ColorMode.HSIA, ColorMode.RGBA,
(x: ReadonlyColor) => rgbaHsia([], x)
);

defConversion(
ColorMode.HSLA, ColorMode.RGBA,
(x: ReadonlyColor) => rgbaHsla([], x)
Expand Down
54 changes: 54 additions & 0 deletions packages/color/src/hsla.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { EPS } from "@thi.ng/math/api";
import { IVector, Vec } from "@thi.ng/vectors3/api";
import { eqDelta4 } from "@thi.ng/vectors3/eqdelta";
import { declareIndices } from "@thi.ng/vectors3/internal/accessors";
import { AVec } from "@thi.ng/vectors3/internal/avec";
import { ColorMode, IColor } from "./api";

export class HSLA extends AVec implements
IColor,
IVector<HSLA> {

h: number;
s: number;
l: number;
a: number;
[id: number]: number;

constructor(buf?: Vec, i = 0, s = 1) {
super(buf || [0, 0, 0, 0], i, s);
}

*[Symbol.iterator]() {
yield this[0];
yield this[1];
yield this[2];
yield this[3];
}

get mode() {
return ColorMode.HSLA;
}

get length() {
return 4;
}

copy() {
return new HSLA([this[0], this[1], this[2], this[3]]);
}

copyView() {
return new HSLA(this.buf, this.offset, this.stride);
}

empty() {
return new HSLA();
}

eqDelta(o: HSLA, eps = EPS): boolean {
return eqDelta4(this, o, eps);
}
}

declareIndices(HSLA.prototype, ["h", "s", "v", "a"]);
2 changes: 2 additions & 0 deletions packages/color/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,5 @@ export * from "./cosine-gradients";
export * from "./matrix";
export * from "./porter-duff";

export * from "./hsla";
export * from "./rgba";
51 changes: 51 additions & 0 deletions packages/color/src/rgba.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { EPS } from "@thi.ng/math/api";
import { IVector, Vec } from "@thi.ng/vectors3/api";
import { eqDelta4 } from "@thi.ng/vectors3/eqdelta";
import { declareIndices } from "@thi.ng/vectors3/internal/accessors";
import { AVec } from "@thi.ng/vectors3/internal/avec";
import { ColorMode, IColor } from "./api";

export class RGBA extends AVec implements
IColor,
IVector<RGBA> {

r: number;
g: number;
b: number;
a: number;
[id: number]: number;

constructor(buf?: Vec, offset = 0, stride = 1) {
super(buf || [0, 0, 0, 0], offset, stride);
}

*[Symbol.iterator]() {
yield* [this.r, this.g, this.b, this.a];
}

get mode() {
return ColorMode.RGBA;
}

get length() {
return 4;
}

copy() {
return new RGBA([this.r, this.g, this.b, this.a]);
}

copyView() {
return new RGBA(this.buf, this.offset, this.stride);
}

empty() {
return new RGBA();
}

eqDelta(o: RGBA, eps = EPS): boolean {
return eqDelta4(this, o, eps);
}
}

declareIndices(RGBA.prototype, ["r", "g", "b", "a"]);

0 comments on commit 610699a

Please sign in to comment.