function paletteFromCurve(options = {}) {
const {
width = 800,
height = 600,
image = null,
ncolors = 5,
cornerColors = ["red", "blue", "green", "white"]
} = options;
const ctx = DOM.context2d(width, height, 1);
const canvas = ctx.canvas;
if (image) {
ctx.drawImage(image, 0, 0, width, height);
} else {
const interpolateTop = d3.interpolateHsl(cornerColors[0], cornerColors[1]);
const interpolateBottom = d3.interpolateHsl(
cornerColors[2],
cornerColors[3]
);
for (let x = 0; x < width; x++) {
const c0 = interpolateTop(x / width);
const c1 = interpolateBottom(x / width);
const gradient = ctx.createLinearGradient(x, 0, x, height);
gradient.addColorStop(0, c0);
gradient.addColorStop(1, c1);
ctx.fillStyle = gradient;
ctx.fillRect(x, 0, x + 1, height);
}
}
let imgData = ctx.getImageData(0, 0, width, height);
let points = [
[width * 0.1, height * 0.1],
[width * 0.6, height * 0.4],
[width * 0.9, height * 0.9]
];
let container = htl.html`<div>`;
container.append(canvas);
container.value = null;
let change = (ctx, pts) => {
ctx.putImageData(imgData, 0, 0);
for (let p of pts) {
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(...p, 4, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(...p, 3, 0, Math.PI * 2);
ctx.fill();
}
ctx.strokeStyle = "black";
ctx.setLineDash([8, 8]);
ctx.lineWidth = 1;
ctx.beginPath();
for (let i = 0; i < 5; i++) {
pts = fourPoint(pts, false);
}
for (let p of pts) ctx.lineTo(...p);
ctx.stroke();
let curveLookup = arcLengthParameterize(pts);
let delta = 1 / (ncolors - 1);
let palettePoints = [];
for (let i = 0; i < ncolors; i++)
palettePoints.push(curveLookup(i * delta));
ctx.setLineDash([]);
const palette = [];
for (let [x, y] of palettePoints) {
ctx.strokeStyle = "white";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.arc(x, y, 8, 0, Math.PI * 2);
ctx.stroke();
const index = (Math.round(x) + Math.round(y) * width) * 4;
let [r, g, b] = imgData.data.slice(index, index + 3);
palette.push(`rgb(${r},${g},${b})`);
}
container.value = palette;
container.dispatchEvent(new Event("input", { bubbles: true }));
};
polygonDemo(ctx, points, change);
return container;
}