Public
Edited
Aug 28, 2024
Importers
2 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
lightnessPlot = Plot.plot({
x: { label: "swatch step" },
y: { label: "lightness (%)" },
title: "Change in lightness ",
// subtitle: "Here is a subtitle",
// caption:
// "Lightness decreases linearily over the palette's swatches from a starting value of 99% to an ending value of 40%.",
marks: [
Plot.frame({ strokeWidth: 1 }),
Plot.gridY({ strokeOpacity: 0.3 }),
Plot.lineY(
inputPaletteToPlot.get("lightness").map((d) => d * 100),
{ stroke: "var(--color-accent)", strokeWidth: 2, x: (d, i) => i + 1 }
),
Plot.dot(
inputPaletteToPlot.get("lightness").map((d, i) => [i + 1, d * 100]),
{
fill: "var(--color-accent)",
r: 4,
stroke: "var(--background-color)"
}
)
]
})
Insert cell
chromaPlot = Plot.plot({
x: { label: "swatch step" },
y: { label: "chroma" },
title: "Change in chroma",
// caption:
// "Chroma increases from a starting value of 0.04 to a maximum value of 0.19 at step seven, then declines to 0.16 for the darkest swatch at step nine.",
marks: [
Plot.frame({ strokeWidth: 1 }),
Plot.gridY({ strokeOpacity: 0.3 }),
Plot.lineY(inputPaletteToPlot.get("chroma"), {
stroke: "var(--color-accent)",
strokeWidth: 2,
x: (d, i) => i + 1
}),
Plot.dot(
inputPaletteToPlot.get("chroma").map((d, i) => [i + 1, d]),
{
fill: "var(--color-accent)",
r: 4,
stroke: "var(--background-color)"
}
)
]
})
Insert cell
huePlot = Plot.plot({
x: { label: "swatch step" },
y: { label: "hue" },
title: "Change in hue",
// caption:
// "Hue decreases from a starting value of 120 degrees to a minimum value of 20 degrees at step seven, then increases slightly to 30 degrees for the darkest swatch at step nine.",
marks: [
Plot.frame({ strokeWidth: 1 }),
Plot.gridY({ strokeOpacity: 0.3 }),
Plot.lineY(inputPaletteToPlot.get("hue"), {
stroke: "var(--color-accent)",
strokeWidth: 2,
x: (d, i) => i + 1
}),
Plot.dot(
inputPaletteToPlot.get("hue").map((d, i) => [i + 1, d]),
{
fill: "var(--color-accent)",
r: 4,
stroke: "var(--background-color)"
}
)
]
})
Insert cell
defaultPalette = JSON.parse(
'["#ffffe0", "#ffe0a9", "#ffbe84", "#ff986d", "#f47361", "#e35056", "#cb2f44", "#ae112a", "#8b0000"]'
)
Insert cell
inputPalette = {
let toReturn = [];
try {
JSON.stringify(paletteInputTextbox);
toReturn = parseInputValues(paletteInputTextbox);
} catch (error) {
console.log(error);
}
return toReturn;
}
Insert cell
parseInputValues = (str) => {
const separatorNewline = "\n";
const separatorComma = ",";
const defaultSeparator = /\s/;

let split = [];

if (str.includes(separatorNewline)) {
split = str.split(separatorNewline);
} else if (str.includes(separatorComma)) {
split = str.split(separatorComma);
} else {
// resort to attempting to split on white space
split = str.split(defaultSeparator);
}

return split.map((d) => d.replace(/('|")/gi, "").trim());
}
Insert cell
inputPaletteParsed = inputPalette.map(toColorOklch)
Insert cell
inputPaletteToPlot = {
const coords = inputPaletteParsed.map((color) => color.coords);
const lightness = coords.map((values) => values[0]);
const chromas = coords.map((values) => values[1]);
const hues = coords.map((values) => values[2]);
return new Map([
["lightness", lightness],
["chroma", chromas],
["hue", hues]
]);
}
Insert cell
toColorOklch = (colorStr) => new Color(colorStr).to("oklch")
Insert cell
// `space` specifies a fallback color space if oklch is not supported,
// see: https://colorjs.io/docs/output#get-a-displayable-css-color-value
getCssColorString = (color, space = "hsl") => color.display({ space })
Insert cell
createPaletteContainer = (
visPalette
) => htl.html`<div class="palette-container">
<style>
.palette-container {
position: relative;
width: ${width}px;
}
.palette-container .tooltip {
position: absolute;
}
</style>
${visPalette}
<!-- TODO: show LCH values in tooltip on hover -->
<div class="tooltip" />
</div>`
Insert cell
createPaletteVisVertical = (colorsArray = [], backgroundColor = "white") => {
const size = SWATCH_SIZE + SWATCH_STROKE * 2;

const paletteListItem = (index) => {
const colorOklch = colorsArray[index];
return htl.html`<li class="palette-swatch">
<svg viewBox="0 0 ${size} ${size}" style="max-height:120px;">
${createSwatch(getCssColorString(colorOklch), "#ccc")}
</svg>
<div>
${dl(index)}
</div>
</li>`;
};

const dl = (index) => {
const colorOklch = colorsArray[index];
const props = ["lightness", "chroma", "hue"];
return htl.html`<dl>${colorOklch.coords.map((value, index) =>
dtdd(props[index], value)
)}</dl>`;
};

const dtdd = (key, value) => htl.html`<div>
<dt>${key}:</dt>
<dd>${value?.toFixed(2)}</dd>
</div>`;

const container = htl.html`<div class="palette-vis-vert-container">
<style>
.palette-vis-vert-container {
padding: 16px;
font-family: sans-serif;
}
.palette-swatch {
display: flex;
align-items: center;
gap: 8px;
max-height: 120px;
}
dl {
margin: 0;
padding: 0;
display: flex;
align-items: baseline;
gap: 8px;
font-family: monospace;
}

dl div {
display: flex;
align-items: baseline;
gap: 4px;
}
dl div:not(:last-of-type)::after {
content: "|"
}
dd,
dt {
margin: 0;
}
dd {
font-weight: bold;
}
</style>
${colorsArray.map((oklch, index) => paletteListItem(index))}
</div>`;

return container;
}
Insert cell
createPaletteVis = (
colorsArray,
backgroundColor = "white",
maxHeightPx = MAX_PALETTE_HEIGHT
) => {
const n = colorsArray.length;
const w = n * SWATCH_SIZE + SWATCH_STROKE * 2;
const h = SWATCH_SIZE + SWATCH_STROKE * 2;
return htl.svg`<svg viewBox="0 0 ${w} ${h}">
<rect x="0" y="0" width="${w}" height="${h}" fill="${backgroundColor}" />
${colorsArray.map((oklch, index) =>
createSwatch(
getCssColorString(oklch),
backgroundColor,
index * SWATCH_SIZE + SWATCH_STROKE
)
)}
</svg>`;
}
Insert cell
createSwatch = (
value,
stroke = "white",
x = SWATCH_STROKE,
y = SWATCH_STROKE,
w = SWATCH_SIZE,
h = SWATCH_SIZE
) =>
htl.svg`<rect fill="${value}" x="${x}" y="${y}" width="${w}" height="${h}" stroke="${stroke}" stroke-width="${SWATCH_STROKE}" />`
Insert cell
MAX_PALETTE_HEIGHT = SWATCH_SIZE * 2
Insert cell
Insert cell
Insert cell
Insert cell
<style>
:root {
--color-accent: #cd12cf;
--background-color: white;
}
</style>
Insert cell
new Color("magenta").toString({ format: "hex" })
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more