Public
Edited
Jul 13, 2024
Comments locked
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
colors = {
const { items } = JSON.parse(tokens.textContent.trim());
yield items.map(({ name, value }) =>
Object.assign(
{
name
},
((color) => ({
hex: color.formatHex(),
rgb: color + "",
p3: toP3(value)
}))(d3.color(value))
)
);
}
Insert cell
Insert cell
Insert cell
toP3("#0f0")
Insert cell
toP3("rgb(0, 255, 0)", { use: parseRGB })
Insert cell
toP3("#0f00")
Insert cell
toP3("rgba(0, 255, 0, 0%)", { use: parseRGB })
Insert cell
toP3("#00ff00")
Insert cell
toP3("rgba(none 255 none / none)", { use: parseRGB })
Insert cell
toP3("#00ff00ff")
Insert cell
toP3("rgba(0, 255, 0, 100%)", { use: parseRGB })
Insert cell
toP3("rgba(0, 254.9, 0, 1%)", { use: parseRGB })
Insert cell
toP3("rgba(., 255., 0, .)", { use: parseRGB })
Insert cell
toP3("rgba(none 255.0 0 / .%)", { use: parseRGB })
Insert cell
Insert cell
{
/*!
* Many thanks to Dean Jackson, Nikita Vasilyev, David Darnes, and Andy Bell! - mg
*/
const color = "rgb(35, 64, 88)";
yield md`
<style>
/* sRGB color */
:root {
--salty-dog: ${color};
}

h1[id] {
color: var(--salty-dog);
}

@media (color-gamut: p3) {
/* Display P3 color, when supported */
:root {
--salty-dog: ${toP3(color, { use: parseRGB })};
}
}

style:only-child:before { content: "## Tweak main heading color (${hasP3})…" !important; }
</style>
`;
}
Insert cell
hasP3 = window.matchMedia("(color-gamut: p3)").matches
Insert cell
toP3 = (value, { colorspace = "display-p3", use = parseHex } = {}) => {
const { 3: alpha = NaN, ...components } = use(value);
return `color(${colorspace} ${Object.values(components).join(" ")}${
+alpha == alpha ? ` / ${alpha}` : ""
})`;
}
Insert cell
parseHex = (value = "") => {
// Calculate richer P3 colors from HEX values
try {
let count;
const { 0: match } = value.trim().match(/^#(?:[0-9a-f]{3,4}){1,2}$/i);
switch (match.length) {
case 5: // #RGBA
case 4: // #RGB
count = 1;
break;
case 9: // #RRGGBBAA
case 7: // #RRGGBB
count = 2;
break;
}
const _ = (x) => (parseInt(x, 16) / 255).toFixed(6) * 1;
const process = [(x) => _(x + x), (x) => _(x)][count - 1];
const components = match
.slice(1)
.match(new RegExp(`.{${count}}`, "g"))
.map(process);
return components;
} catch (e) {
throw Error("Argument is not an hexadecimal color");
}
}
Insert cell
Insert cell
Insert cell
parseRGB = (() => {
const fractional = ["(?:[.]0*)?", "(?:[.]\\d*)?"];
const percentage =
"(?:100" + fractional[0] + "|[1-9]?\\d?" + fractional[1] + ")%";
const isRGB = new RegExp(
/* rgb(R G B[ / A]) | rgba(R G B[ / A]) */
[
"^rgba?\\(",
/* component values: none | 0 to 255 | 0% to 100% */
["R", "G", "B"]
.map(
(C) =>
["(?<", C, ">"].join("") +
[
"none",
"(?:255" +
fractional[0] +
"|(?:25[0-4]|2[0-4]\\d|1\\d{1,2}|[1-9]?\\d?)" +
fractional[1] +
")",
percentage
].join("|") +
")"
)
.join("(?:\\s*,\\s*|\\s+)"),
/* alpha channel value: none | 0 to 1 | 0% to 100% */
"(?:\\s*[,\\/]\\s*",
"(?<A>" +
[
"none",
"(?:1" + fractional[0] + "|0?" + fractional[1] + ")",
percentage
].join("|") +
")",
")?",
"\\)$"
].join(""),
"i"
);
return (rgba = "") => {
// Calculate richer P3 colors from sRGB absolute values
try {
const components = rgba
.trim()
.match(isRGB)
.slice(1)
.map((x, i) =>
["none", ".", ".%"].includes(x)
? i < 3
? /* R, G, or B */ 0
: /* A */ [0, NaN][+(x === "none")]
: (
parseFloat(x, 10) /
((x || "").match(/%$/)
? /* percentage */ 100
: i < 3
? /* R, G, or B */ 255
: /* A */ 1)
).toFixed(6) * 1
);
return components;
} catch (e) {
throw Error("Argument is not a sRGB color");
}
};
})()
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more