Public
Edited
Sep 10, 2023
Importers
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
viewof drawingConfig.getCurrent()
Insert cell
viewof drawingConfig.getPresets()
Insert cell
Insert cell
schemes = ({
oranges: d3.schemeOranges[9],
blues: d3.schemeBlues[9],
BrBG: d3.schemeBrBG[11],
PiYG: d3.schemePiYG[9],
dark: d3.schemeDark2,
greens: d3.schemeGreens[9],
pastel1: d3.schemePastel1,
pastel2: d3.schemePastel2
})
Insert cell
presets = ({
"BrBG squares": {
colorScheme: "BrBG",
shape: "square",
size: 29,
count: 1000,
seed: 1
},
"Blue stars": {
colorScheme: "blues",
shape: "star",
size: 30,
count: 452,
seed: 259
},
Confetti: {
colorScheme: "dark",
shape: "circle",
size: 13,
count: 1000,
seed: 5
}
})
Insert cell
function presetMenu(form, presets = {}, options = {}) {
const {
initialPreset = null,
label = "presets",
alwaysSelected = false,
editable = true,
callback = () => {}
} = options;
const container = html`<div style="display:flex">`;
const addButton = htl.html`<button style="margin-right:2px">➕`;
const presetName = htl.html`<input type=text style="margin-right:2px; width:10em" value="">`;
const presetCount = () => [...Object.keys(presets)].length;
if (presetCount() == 0 && alwaysSelected)
throw "The 'alwaysSelected' option requires at least one preset";
const delButton = htl.html`<button style="margin-right:2px">🗑️`;
const presetButtons = [];
const defaultValue = Object.assign({}, form.value);
if (alwaysSelected && !initialPreset)
initialPreset = [...Object.keys(presets)][0];
let current = initialPreset;
if (current) form.value = presets[current];
const updateCurrent = () => {
if (current) {
presets[current] = Object.assign({}, form.value);
}
container.value = Object.assign({}, form.value);
container.dispatchEvent(new CustomEvent("input"));
callback(container.value, presets, current);
};
const nextName = () => {
let name = presetName.value;
if (name == "" || presets[name]) {
let count = presetCount();
do {
name = `@${++count}`;
} while (presets[name]);
}
return name;
};
presetName.setAttribute("placeholder", nextName());
updateCurrent();
const populate = () => {
presetButtons.length = 0;
const n = container.children.length;
for (let i = 0; i < n; i++)
container.removeChild(container.firstElementChild);
if (label)
container.append(
html`<label style="width:120px;font:10pt sans-serif">${label}`
);
for (let key of Object.keys(presets)) {
const presetButton = htl.html`<button style="margin-right:2px">${key}`;
if (key == current) {
presetButton.setAttribute("class", "current");
presetButton.style.border = "2px solid darkred";
presetButton.style.borderRadius = "4px";
}
container.append(presetButton);
presetButton.onclick = () => {
current = key;
form.value = Object.assign({}, presets[key]);
populate();
updateCurrent();
};
}
if (editable) container.append(delButton);
if (!current || (alwaysSelected && presetCount() < 2))
Object.assign(delButton.style, { cursor: "not-allowed" });
else Object.assign(delButton.style, { cursor: "auto" });
if (editable) {
container.append(addButton);
container.append(presetName);
}
};
addButton.onclick = () => {
current = nextName();
presets[current] = Object.assign({}, form.value);
updateCurrent();
populate();
presetName.value = "";
presetName.setAttribute("placeholder", nextName());
};
delButton.onclick = () => {
if (!current || (alwaysSelected && presetCount() < 2)) return;
delete presets[current];
if (alwaysSelected) {
const keys = [...Object.keys(presets)];
current = keys[0];
} else {
current = null;
}
updateCurrent();
populate();
};
populate();
form.addEventListener("input", updateCurrent);
container.getPresets = () => presets;
container.getCurrent = () => current;
return container;
}
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