Factor out color-util.ts. (#130)
This fixes #129 and also factors out a new function, `clampedBytesToRGBColor()`.pull/131/head
rodzic
902dfa23fa
commit
f3ab28f70d
|
@ -0,0 +1,25 @@
|
||||||
|
import { clampedBytesToRGBColor, clampedByteToHex } from "./color-util";
|
||||||
|
|
||||||
|
describe("clampedBytesToRGBColor", () => {
|
||||||
|
it("works", () => {
|
||||||
|
expect(clampedBytesToRGBColor([999, 5, 171])).toBe("#ff05ab");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("clampedByteToHex", () => {
|
||||||
|
it("clamps values over 255 to 255", () => {
|
||||||
|
expect(clampedByteToHex(500)).toBe("ff");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("clamps values under 0 to 0", () => {
|
||||||
|
expect(clampedByteToHex(-50)).toBe("00");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("zero-pads values", () => {
|
||||||
|
expect(clampedByteToHex(10)).toBe("0a");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("works with numbers that don't need zero-padding", () => {
|
||||||
|
expect(clampedByteToHex(22)).toBe("16");
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**
|
||||||
|
* Clamp the given number to be between 0 and 255, then
|
||||||
|
* convert it to hexadecimal.
|
||||||
|
*/
|
||||||
|
export function clampedByteToHex(value: number): string {
|
||||||
|
if (value < 0) {
|
||||||
|
value = 0;
|
||||||
|
} else if (value > 255) {
|
||||||
|
value = 255;
|
||||||
|
}
|
||||||
|
let hex = value.toString(16);
|
||||||
|
if (hex.length === 1) {
|
||||||
|
hex = "0" + hex;
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert the given array of numbers to an RGB hex value.
|
||||||
|
*/
|
||||||
|
export function clampedBytesToRGBColor(values: number[]): string {
|
||||||
|
return "#" + values.map(clampedByteToHex).join("");
|
||||||
|
}
|
|
@ -7,7 +7,6 @@ import type {
|
||||||
AvroSvgCompositionContext,
|
AvroSvgCompositionContext,
|
||||||
} from "./mandala-design.avsc";
|
} from "./mandala-design.avsc";
|
||||||
import * as avro from "avro-js";
|
import * as avro from "avro-js";
|
||||||
import { clampedByteToHex } from "../../random-colors";
|
|
||||||
import {
|
import {
|
||||||
MANDALA_DESIGN_DEFAULTS,
|
MANDALA_DESIGN_DEFAULTS,
|
||||||
ExtendedMandalaCircleParams,
|
ExtendedMandalaCircleParams,
|
||||||
|
@ -15,6 +14,7 @@ import {
|
||||||
getCirclesFromDesign,
|
getCirclesFromDesign,
|
||||||
} from "./core";
|
} from "./core";
|
||||||
import { fromBase64, toBase64 } from "../../base64";
|
import { fromBase64, toBase64 } from "../../base64";
|
||||||
|
import { clampedBytesToRGBColor } from "../../color-util";
|
||||||
|
|
||||||
const avroMandalaDesign = avro.parse<AvroMandalaDesign>(MandalaAvsc);
|
const avroMandalaDesign = avro.parse<AvroMandalaDesign>(MandalaAvsc);
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ export const ColorPacker: Packer<string, number> = {
|
||||||
const red = (number >> 16) & 0xff;
|
const red = (number >> 16) & 0xff;
|
||||||
const green = (number >> 8) & 0xff;
|
const green = (number >> 8) & 0xff;
|
||||||
const blue = number & 0xff;
|
const blue = number & 0xff;
|
||||||
return "#" + [red, green, blue].map(clampedByteToHex).join("");
|
return clampedBytesToRGBColor([red, green, blue]);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,8 @@
|
||||||
import {
|
import {
|
||||||
clampedByteToHex,
|
|
||||||
createRandomColorPalette,
|
createRandomColorPalette,
|
||||||
RANDOM_PALETTE_ALGORITHMS,
|
RANDOM_PALETTE_ALGORITHMS,
|
||||||
} from "./random-colors";
|
} from "./random-colors";
|
||||||
|
|
||||||
describe("clampedByteToHex", () => {
|
|
||||||
it("clamps values over 255 to 255", () => {
|
|
||||||
expect(clampedByteToHex(500)).toBe("ff");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("clamps values under 0 to 0", () => {
|
|
||||||
expect(clampedByteToHex(-50)).toBe("00");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("zero-pads values", () => {
|
|
||||||
expect(clampedByteToHex(10)).toBe("0a");
|
|
||||||
});
|
|
||||||
|
|
||||||
it("works with numbers that don't need zero-padding", () => {
|
|
||||||
expect(clampedByteToHex(22)).toBe("16");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe("createRandomColorPalette()", () => {
|
describe("createRandomColorPalette()", () => {
|
||||||
for (let alg of RANDOM_PALETTE_ALGORITHMS) {
|
for (let alg of RANDOM_PALETTE_ALGORITHMS) {
|
||||||
it(`works using the '${alg}' algorithm`, () => {
|
it(`works using the '${alg}' algorithm`, () => {
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { Random } from "./random";
|
||||||
import { range, clamp } from "./util";
|
import { range, clamp } from "./util";
|
||||||
import * as colorspaces from "colorspaces";
|
import * as colorspaces from "colorspaces";
|
||||||
import { ColorTuple, hsluvToHex } from "hsluv";
|
import { ColorTuple, hsluvToHex } from "hsluv";
|
||||||
|
import { clampedBytesToRGBColor } from "./color-util";
|
||||||
|
|
||||||
type RandomPaletteGenerator = (numEntries: number, rng: Random) => string[];
|
type RandomPaletteGenerator = (numEntries: number, rng: Random) => string[];
|
||||||
//type ColorFunction = (rng: Random) => string[];
|
//type ColorFunction = (rng: Random) => string[];
|
||||||
|
@ -18,26 +19,9 @@ export type RandomPaletteAlgorithm = "RGB" | "CIELUV" | "threevals";
|
||||||
export const DEFAULT_RANDOM_PALETTE_ALGORITHM: RandomPaletteAlgorithm =
|
export const DEFAULT_RANDOM_PALETTE_ALGORITHM: RandomPaletteAlgorithm =
|
||||||
"threevals";
|
"threevals";
|
||||||
|
|
||||||
/**
|
|
||||||
* Clamp the given number to be between 0 and 255, then
|
|
||||||
* convert it to hexadecimal.
|
|
||||||
*/
|
|
||||||
export function clampedByteToHex(value: number): string {
|
|
||||||
if (value < 0) {
|
|
||||||
value = 0;
|
|
||||||
} else if (value > 255) {
|
|
||||||
value = 255;
|
|
||||||
}
|
|
||||||
let hex = value.toString(16);
|
|
||||||
if (hex.length === 1) {
|
|
||||||
hex = "0" + hex;
|
|
||||||
}
|
|
||||||
return hex;
|
|
||||||
}
|
|
||||||
|
|
||||||
function createRandomRGBColor(rng: Random): string {
|
function createRandomRGBColor(rng: Random): string {
|
||||||
const rgb = range(3).map(() => rng.inRange({ min: 0, max: 255, step: 1 }));
|
const rgb = range(3).map(() => rng.inRange({ min: 0, max: 255, step: 1 }));
|
||||||
return "#" + rgb.map(clampedByteToHex).join("");
|
return clampedBytesToRGBColor(rgb);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createRandomCIELUVColor(rng: Random): string {
|
function createRandomCIELUVColor(rng: Random): string {
|
||||||
|
|
|
@ -11,8 +11,8 @@ import {
|
||||||
} from "./svg-symbol";
|
} from "./svg-symbol";
|
||||||
import toml from "toml";
|
import toml from "toml";
|
||||||
import { validateSvgSymbolMetadata } from "./svg-symbol-metadata";
|
import { validateSvgSymbolMetadata } from "./svg-symbol-metadata";
|
||||||
import { clampedByteToHex } from "./random-colors";
|
|
||||||
import { withoutNulls } from "./util";
|
import { withoutNulls } from "./util";
|
||||||
|
import { clampedBytesToRGBColor } from "./color-util";
|
||||||
|
|
||||||
const SUPPORTED_SVG_TAG_ARRAY: SvgSymbolElement["tagName"][] = ["g", "path"];
|
const SUPPORTED_SVG_TAG_ARRAY: SvgSymbolElement["tagName"][] = ["g", "path"];
|
||||||
const SUPPORTED_SVG_TAGS = new Set(SUPPORTED_SVG_TAG_ARRAY);
|
const SUPPORTED_SVG_TAGS = new Set(SUPPORTED_SVG_TAG_ARRAY);
|
||||||
|
@ -108,7 +108,7 @@ function parseRadialGradient(el: cheerio.TagElement): SvgSymbolDef {
|
||||||
.map((value) => parseInt(value));
|
.map((value) => parseInt(value));
|
||||||
stops.push({
|
stops.push({
|
||||||
offset: getNonEmptyAttrib(child, "offset"),
|
offset: getNonEmptyAttrib(child, "offset"),
|
||||||
color: "#" + rgb.map(clampedByteToHex).join(""),
|
color: clampedBytesToRGBColor(rgb),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue