Public
Edited
Nov 20, 2024
Importers
Insert cell
Insert cell
viewof color = colorInputWithPicker(viewof picker, {
value: "#ff0000"
})
Insert cell
color
Insert cell
viewof picker = pickColorFromImage(pickImageFile)
Insert cell
picker
Insert cell
Insert cell
//
// Reactively changes the image to pick from
//
colorPickFileReactivity = {
if (newPickImageFile) {
mutable pickImageFile = newPickImageFile.image();
return newPickImageFile;
}
return "original file";
}
Insert cell
viewof fourColorSelect = {
let div = htl.html`<div>`;
Object.assign(div.style, {
display: "flex",
maxWidth: "300px"
});
let picker = pickColorFromImage(pickImageFile);
Object.assign(picker.style, {
flex: 2,
maxWidth: "200px"
});
let colorInputs = {
c1: colorInputWithPicker(picker, { value: "#ffffff" }),
c2: colorInputWithPicker(picker, { value: "#0000ff" }),
c3: colorInputWithPicker(picker, { value: "#ff0000" }),
c4: colorInputWithPicker(picker, { value: "#000000" })
};
let form = Inputs.form(colorInputs);
Object.assign(form.style, {
flex: 1,
maxWidth: "70px"
});
div.append(form, picker);
Object.defineProperty(div, "value", {
get() {
return form.value;
},
set(v) {
form.value = v;
}
});
for (let ci of Object.keys(colorInputs)) {
colorInputs[ci].addEventListener("input", () => {
div.dispatchEvent(new CustomEvent("input"));
});
}
form.addEventListener("input", () => {
div.dispatchEvent(new CustomEvent("input"));
});
return div;
}
Insert cell
fourColorSelect
Insert cell
Insert cell
mutable pickImageFile = FileAttachment("Lenna_(test_image).png").image()
Insert cell
function colorInputWithPicker(picker, options) {
let div = htl.html`<div>`;
Object.assign(div.style, {
maxWidth: "200px",
display: "flex"
});
let colorInput = Inputs.color(options);
colorInput.querySelector("output").style.display = "none";
Object.assign(colorInput.style, {
maxWidth: "30px",
flex: 1
//display: "inline"
});
Object.defineProperty(div, "value", {
get() {
return colorInput.value;
},
set(v) {
colorInput.value = v;
}
});
colorInput.addEventListener("input", (evt) => {
div.dispatchEvent(new CustomEvent("input"));
});
let pickerPanel = htl.html`<div>`;
Object.assign(pickerPanel.style, {
maxWidth: "28px",
maxHeight: "28px",
background: "#EEE",
borderRadius: "5px",
flex: 2
});
let pickIcon = svg`${pickIconCode}`;
Object.assign(pickIcon.style, {
paddingLeft: "2px",
paddingTop: "2px"
});
let waitIcon = svg`${waitIconCode}`;
Object.assign(waitIcon.style, {
paddingLeft: "2px",
paddingTop: "2px"
});
pickerPanel.onmouseenter = () => (pickerPanel.style.background = "#CCC");
pickerPanel.onmouseleave = () => (pickerPanel.style.background = "#EEE");
pickerPanel.onmousedown = () => {
pickerPanel.innerHTML = "";
pickerPanel.prepend(waitIcon);
div.style.cursor = "pointer";
picker.setCallback((color) => {
colorInput.value = d3.color(color).hex();
colorInput.dispatchEvent(new CustomEvent("input"));
div.dispatchEvent(new CustomEvent("input"));
div.style.cursor = "default";
pickerPanel.innerHTML = "";
pickerPanel.prepend(pickIcon);
picker.setCallback(null);
});
};

pickerPanel.append(pickIcon);
div.append(colorInput, pickerPanel);
return div;
}
Insert cell
Insert cell
pickIconCode = `<svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M7 13.161L12.4644 7.6966C12.8549 7.30607 13.4881 7.30607 13.8786 7.6966L15.9999 9.81792C16.3904 10.2084 16.3904 10.8416 15.9999 11.2321L14.0711 13.161M7 13.161L4.82764 15.3334C4.73428 15.4267 4.66034 15.5376 4.61007 15.6597L3.58204 18.1563C3.07438 19.3892 4.30728 20.6221 5.54018 20.1145L8.03681 19.0865C8.1589 19.0362 8.26981 18.9622 8.36317 18.8689L14.0711 13.161M7 13.161H14.0711" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M13.878 3.45401L15.9993 5.57533M20.242 9.81798L18.1206 7.69666M15.9993 5.57533L17.4135 4.16112C17.8041 3.7706 18.4372 3.7706 18.8277 4.16112L19.5349 4.86823C19.9254 5.25875 19.9254 5.89192 19.5349 6.28244L18.1206 7.69666M15.9993 5.57533L18.1206 7.69666" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>`
Insert cell
waitIconCode = `<svg width="24px" height="24px" viewBox="0 0 24 24" stroke-width="1.5" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M12 6L12 12L18 12" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M21.8883 10.5C21.1645 5.68874 17.013 2 12 2C6.47715 2 2 6.47715 2 12C2 17.5228 6.47715 22 12 22C16.1006 22 19.6248 19.5318 21.1679 16" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M17 16H21.4C21.7314 16 22 16.2686 22 16.6V21" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>`
Insert cell
function pickColorFromImage(
img,
{ height = 256, callback = null, color = "red" } = {}
) {
const aspect = img.width / img.height;
const width = height * aspect;
const div = htl.html`<div>`;
Object.assign(div.style, {
height: `${height}px`,
width: `${width}px`,
display: "flex",
flexDirection: "row"
});
const canvas = htl.html`<canvas width=${width} height=${height}>`;
Object.assign(canvas.style, {
flex: 1
});
const samplePane = htl.html`<div>`;
Object.assign(samplePane.style, {
maxWidth: "80px",
maxHeight: "80px",
display: "flex",
flexDirection: "column",
paddingLeft: "10px",
flex: 2
});
const sample = htl.html`<div>`;
Object.assign(sample.style, {
maxWidth: "40px",
minWidth: "40px",
minHeight: "40px",
maxHeight: "40px",
background: color,
border: "1px solid gray",
flex: 1
});
const colorName = htl.html`<span>${color}`;
Object.assign(colorName.style, {
maxWidth: "20em",
paddingTop: "10px",
font: "10pt sans-serif",
flex: 2
});
samplePane.append(sample, colorName);
const ctx = canvas.getContext("2d");
canvas.onmousemove = (evt) => {
const [x, y] = [evt.offsetX, evt.offsetY];
if (x < 0 || y < 0 || x >= width || y >= height) return;
const myImageData = ctx.getImageData(x, y, 1, 1);
const d = myImageData.data;
const color = `rgb(${d[0]},${d[1]},${d[2]})`;
sample.style.background = color;
colorName.innerHTML = color;
};
canvas.onmousedown = (evt) => {
canvas.onmousemove(evt);
let hexColor = d3.color(colorName.innerHTML).hex();
div.value = hexColor;
div.dispatchEvent(new CustomEvent("input"));
if (callback) callback(colorName.innerHTML);
};
ctx.drawImage(img, 0, 0, width, height);
div.append(canvas, samplePane);
div.setCallback = (cb) => {
callback = cb;
if (callback) {
canvas.style.cursor = "pointer";
} else {
canvas.style.cursor = "default";
}
};
div.setCallback(callback);
div.value = d3.color(color).hex();
return div;
}
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