Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ <h1 class="txt-h4 txt-fancy block mb6">@mapbox/to-color</h1>
['deli', 6],
[1234, 6],
[5678, 6],
['mapbox.mapbox-streets-v8', 16],
['mapbox.mapbox-streets-v8', 16, { saturation: 1.25, limit: ['blue'] }],
['mapbox.mapbox-streets-v8', 16, { saturation: 0.5 }],
['mapbox.mapbox-streets-v8', 16, { saturation: 1.25 }],
['mapbox.mapbox-streets-v8', 16, { brightness: 0.5 }],
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@mapbox/to-color",
"version": "2.3.0",
"version": "2.3.1",
"description": "Procedurally generate a deterministic, perceptually distributed color palette.",
"main": "dist/to-color.js",
"scripts": {
Expand Down
31 changes: 17 additions & 14 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ import { Hsluv } from 'hsluv';
export default class toColor {
HUE_MAX = 360;

// HSLuv hue ranges. Each covers the full saturation/lightness spread of
// its color so neighbors overlap. Red wraps around 0, so it starts negative.
hues = {
red: [-26, 18],
orange: [18, 46],
yellow: [46, 62],
green: [62, 178],
blue: [178, 257],
purple: [257, 282],
pink: [282, 334]
red: [-20, 34],
orange: [18, 71],
yellow: [59, 89],
green: [86, 190],
blue: [185, 277],
purple: [268, 295],
pink: [285, 360]
};

constructor(seed, options) {
Expand Down Expand Up @@ -109,8 +111,8 @@ export default class toColor {
const raw = hsl(c);

// Convert and round
const hRounded = Math.round(this._clamp(raw.h, 0, 360));
const sRounded = Math.round(this._clamp(raw.s * 100, 0, 100));
const hRounded = Math.round(this._clamp(raw.h || 0, 0, 360));
const sRounded = Math.round(this._clamp((raw.s || 0) * 100, 0, 100));
const lRounded = Math.round(this._clamp(raw.l * 100, 0, 100));

return {
Expand All @@ -128,17 +130,18 @@ export default class toColor {

hue = this._pseudoRandom([min, max]);

// Red is on both ends of the color spectrum. Instead of storing red as two
// ranges, lookup is grouped in `this.hue` as negative numbers.
if (hue < 0) hue = this.HUE_MAX + hue;

// Limit the max of some hues if the option is passed.
const { limit } = this.options;

if (limit && limit.length) {
for (let i = 0; i !== limit.length; i++) {
const hueRange = this.hues?.[limit[i]];
if (hueRange && hue > hueRange[0] && hue <= hueRange[1]) {
if (
hueRange &&
[hue, hue - this.HUE_MAX].some(
(h) => h > hueRange[0] && h <= hueRange[1]
)
) {
return this._pickHue();
}
}
Expand Down
20 changes: 15 additions & 5 deletions src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,22 +48,22 @@ describe('toColor', () => {
});

describe('brightness/saturation', () => {
const color = new toColor('penny', { brightness: 0.5, saturation: 0.5 });
const color = new toColor('penny', { brightness: 1.5, saturation: 0.5 });

it('returns deterministic color on getColor', () => {
expect(color.getColor()).toEqual({
hsl: {
formatted: 'hsl(87, 14%, 31%)',
raw: [87, 14, 31]
formatted: 'hsl(0, 0%, 100%)',
raw: [0, 0, 100]
}
});
});

it('returns a different determinisic value calling getColor again', () => {
expect(color.getColor()).toEqual({
hsl: {
formatted: 'hsl(337, 32%, 24%)',
raw: [337, 32, 24]
formatted: 'hsl(338, 37%, 69%)',
raw: [338, 37, 69]
}
});
});
Expand All @@ -89,6 +89,16 @@ describe('toColor', () => {
}
});
});

it('never renders a limited hue', () => {
['hi', 'mapbox.mapbox-streets-v8'].forEach((seed) => {
const color = new toColor(seed, { saturation: 1.25, limit: ['blue'] });
for (let i = 0; i !== 100; i++) {
const [h] = color.getColor().hsl.raw;
expect(h > 180 && h < 255).toBe(false);
}
});
});
});

describe('getColor seeding', () => {
Expand Down
Loading