Public
Edited
May 31, 2023
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
SwatchInput(
Object.values({
blue1: "hsl(9.3801, 2.3157%, 1.106%)",
blue2: "hsl(219.83, 100%, 14.094%)",
blue3: "hsl(217.42, 100%, 22.562%)",
blue4: "hsl(216.29, 100%, 31.664%)",
blue5: "hsl(215.66, 100%, 41.296%)",
blue6: "hsl(220.62, 84.26%, 56.743%)",
blue7: "hsl(222.41, 100%, 67.999%)",
blue8: "hsl(223.83, 100%, 76.818%)",
blue9: "hsl(225.1, 100%, 84.911%)",
blue10: "hsl(227.88, 100%, 92.773%)",
blue11: "hsl(233.61, 100%, 96.674%)",
blue12: "hsl(282.39, 100%, 99.27%)"
})
)
Insert cell
Insert cell
Insert cell
Insert cell
// light theme
Insert cell
Insert cell
// dark theme
Insert cell
Insert cell
function createTheme(color, dark = false, colorSpace = "HSL") {
const colorPalette = {};
const format = (arr) =>
(arr.length === 3 ? "rgb(" : "rgba(") + arr.join(", ") + ")";

const formatHSL = (arr) =>
"hsl(" +
Math.round(arr[0]) +
", " +
Math.round(arr[1] * 100) / 100 +
"%, " +
Math.round(arr[2] * 100) / 100 +
"%)";

(dark ? lightnessInputDark : lightnessInput).forEach((lightness, i) => {
let t = i / (lightnessInput.length - 1);
if (dark) t = 1 - t;
if (colorSpace === "HCT") {
const hctColor = colorUtil.Hct.fromInt(
ColorRGB.fromString(color).toInt()
);
const chroma = (dark ? chromaTableDark : chromaTable)[i];
// modify the t and chroma value
hctColor.tone = (lightness * 100) / 11;
//hctColor.chroma = chroma;

// convert back to rgb
const c = ColorRGB.fromInt(hctColor.toInt());
colorPalette[colorName + (i + 1)] = format(c.toTuple());
} else {
// hsl
const hslColor = rgb2hsl(ColorRGB.fromString(color).toTuple());
hslColor[2] = (lightness * 100) / 11;

colorPalette[colorName + (i + 1)] = formatHSL(hslColor);
}
});
return colorPalette;
}
Insert cell
import { SwatchInput } from "@mateh/swatch-input"
Insert cell
RGBToHSL = (r, g, b) => {
const l = Math.max(r, g, b);
const s = l - Math.min(r, g, b);
const h = s
? l === r
? (g - b) / s
: l === g
? 2 + (b - r) / s
: 4 + (r - g) / s
: 0;
return [
60 * h < 0 ? 60 * h + 360 : 60 * h,
100 * (s ? (l <= 0.5 ? s / (2 * l - s) : s / (2 - (2 * l - s))) : 0),
(100 * (2 * l - s)) / 2
];
}
Insert cell
Insert cell
PlotInput = ({
defaultValue = Array.from({ length: 12 }, (_, i) => ({ x: i, y: i }))
} = {}) => {
let data = [].concat(defaultValue);
const width = 600,
height = 400;

const svg = d3.create("svg").attr("width", width).attr("height", height);

let padding = 10;
const xScale = d3
.scaleLinear()
.domain([0, 11])
.range([padding, width - padding]);

const yScale = d3
.scaleLinear()
.domain([0, 11])
.clamp(true)
.range([height - padding, padding]);

const lineGenerator = d3
.line()
.x((d) => xScale(d.x))
.y((d) => yScale(d.y));

const dragger = d3.drag().on("start drag", function (event) {
const x = Math.round(xScale.invert(event.x));
const y = yScale.invert(event.y);
if (x >= 0 && x < 12) {
data[x].y = y;
svg.select(".line").attr("d", lineGenerator(data));
svg
.selectAll(".dot")
.data(data)
.join("circle")
.attr("class", "dot")
.attr("cx", (d) => xScale(d.x))
.attr("cy", (d) => yScale(d.y))
.attr("r", 8);
node.dispatchEvent(new CustomEvent("input"));
}
});

svg
.append("path")
.datum(data)
.attr("class", "line")
.attr("d", lineGenerator)
.attr("fill", "none")
.attr("stroke", "steelblue");

svg
.selectAll(".dot")
.data(data)
.join("circle")
.attr("class", "dot")
.attr("cx", (d) => xScale(d.x))
.attr("cy", (d) => yScale(d.y))
.attr("r", 8);

svg.call(dragger);

const node = svg.node();

// Update the data array whenever a dot is dragged
Object.defineProperty(node, "value", {
get() {
return data.map((d) => d.y);
},
set(newData) {
data = newData.map((d, i) => ({ x: i, y: d }));
svg
.selectAll(".dot")
.data(data)
.join("circle")
.attr("class", "dot")
.attr("cx", (d) => xScale(d.x))
.attr("cy", (d) => yScale(d.y))
.attr("r", 8);

svg
.select(".line")
.datum(data)
.attr("class", "line")
.attr("d", lineGenerator)
.attr("fill", "none")
.attr("stroke", "steelblue");
}
});

// Set the initial data
node.value = data.map((d) => d.y);

return node;
}
Insert cell
function hexToInt(hex) {
const r = parseInt(hex.substring(1, 3), 16);
const g = parseInt(hex.substring(3, 5), 16);
const b = parseInt(hex.substring(5, 7), 16);
const opaqueBlack = 0xff000000;
return opaqueBlack | (r << 16) | (g << 8) | b;
}
Insert cell
import { ramp, generate, interpolateShades, ColorRGB } from "@mateh/palette"
Insert cell
colorUtil = import("https://cdn.skypack.dev/@material/material-color-utilities")
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