Published
Edited
Jul 21, 2021
Importers
3 stars
Insert cell
Insert cell
Insert cell
serializeSVG = {
const xmlns = "http://www.w3.org/2000/xmlns/";
const xlinkns = "http://www.w3.org/1999/xlink";
const svgns = "http://www.w3.org/2000/svg";
return function serializeSVG(svg) {
svg = svg.cloneNode(true);
svg.setAttributeNS(xmlns, "xmlns", svgns);
svg.setAttributeNS(xmlns, "xmlns:xlink", xlinkns);
const serializer = new window.XMLSerializer;
const string = serializer.serializeToString(svg);
return new Blob([string], {type: "image/svg+xml"});
};
}
Insert cell
function rasterizeSVG(svg) {
let resolve, reject;
const promise = new Promise((y, n) => (resolve = y, reject = n));
const image = new Image;
image.onerror = reject;
image.onload = () => {
const rect = svg.getBoundingClientRect();
const context = DOM.context2d(rect.width, rect.height);
context.drawImage(image, 0, 0, rect.width, rect.height);
context.canvas.toBlob(resolve);
};
image.src = URL.createObjectURL(serializeSVG(svg));
return promise;
}
Insert cell
function makeSliderWithValue(name, inputMin, inputMax, inputStep, initialValue, units) {
const div = html`<input type=range min=${inputMin} max=${inputMax} step=${inputStep} style="width:75%"> <code style="color:${codeColor};">${name}:</code> <strong><output></output></strong> ${units}`;
const range = div.querySelector("[type=range]");
const number = div.querySelector("output");
div.value = range.value = initialValue;
number.textContent = initialValue;
range.addEventListener("input", () => number.textContent = div.value = range.valueAsNumber);
return div;
}
Insert cell
function makeMultipleSlider(options) {
/****
* parameters:
* {
* name: string,
* inputMin: number, inputMax: number, inputStep: number,
* initialValue: number, units: string,
*
* }
****/
const values = {};
const ui = html`
${options.map(option => {
const inputId = `range_${option.name}`;
const outputId = `output_${option.name}`;
const div = html`
<input id=${inputId} type=range min=${option.inputMin} max=${option.inputMax} step=${option.inputStep}>
<code style="color:${codeColor}">${option.name}:</code>
<strong>
<output id=${outputId}></output>
</strong>
<span style="margin-right:50px;">${option.units}</span>`
const range = div.querySelector("#"+inputId);
const number = div.querySelector("#"+outputId);

values[option.name] = range.value = option.initialValue;
number.textContent = option.initialValue;
range.addEventListener("input", () => number.textContent = values[option.name] = range.valueAsNumber);
return div;
})
}`;

ui.value =values;
return ui;
}
Insert cell
function makeSelect(name, options, label, selectedIndex) {
// Options should be an array or array of objects in format: [{ label: "Option A", value: "A" }, ...]
options = options.map(o => {
return typeof o === "object" ? o : { value: o, label: o }
});
if ((!selectedIndex) || ((selectedIndex + 1) > options.length)) {
selectedIndex = 0;
}
if (!label) {
label = ""
}
const form = html`
<form>
<label>
<select name=inputVal>
${options.map(({ value, label }) => Object.assign(html`<option>`, {
value,
selected: options[selectedIndex].value === value,
textContent: label
}))}
</select>
&nbsp; <code style="color:${codeColor};">${name}</code> ${label ? label : ""}
</label>
</form>
`;
form.oninput = () => {
form.value = form.inputVal.value;
};
form.oninput();
return form;
}
Insert cell
function makeCheckbox(name, checked, label) {
const form = html`
<form>
<label>
<input name=inputVal type="checkbox" ${checked ? "checked" : ""}>
<code style="color:${codeColor};">${name}</code> ${label ? label : ""}
</label>
</form>
`;
form.oninput = () => {
form.value = form.inputVal.checked;
};
form.oninput();
return form;
}
Insert cell
function makeColorSwatch(name, initialColor, label) {
const form = html`
<form>
<label>
<input name=inputVal type=color value=${initialColor}>
<code style="color:${codeColor};">${name}</code>: <output name=outputVal></output> ${label ? label : ""}
</label>
</form>
`;
form.oninput = () => {
form.value = form.inputVal.value;
form.outputVal.value = form.inputVal.value;
};
form.oninput();
return form;
}
Insert cell
function makeTextField(name, value, label) {
const form = html`
<form>
<label>
<input name=inputVal type="text" value=${value ? value : ""}>
<code style="color:${codeColor};">${name}</code>: <output name=outputVal></output> ${label ? label : ""}
</label>
</form>
`
form.oninput = () => {
form.value = form.inputVal.value
form.outputVal.value = form.inputVal.value
}
form.oninput()
return form
}
Insert cell
function makeNumberField(name, value, label) {
const form = html`
<form>
<label>
<input name=inputVal type="number" value=${isNaN(value) ? null : value}>
<code style="color:${codeColor};">${name}</code>: <output name=outputVal></output> ${label ? label : ""}
</label>
</form>
`
form.oninput = () => {
form.value = form.inputVal.valueAsNumber
form.outputVal.value = form.inputVal.valueAsNumber
}
form.oninput()
return form
}
Insert cell
function getHexPos(index, total, w, h, r, spacing, margin) {
const verticalHexSeparation = Math.sqrt(0.75) // Math.sqrt((r*r) - ((r/2)*(r/2)))
let colCount = Math.floor((w - margin.left - margin.right) / (2 * r + spacing))
colCount = colCount - 1
if (colCount === 0) colCount = 1
const row = Math.floor(index / colCount)
const reset = (colCount * ((2 * r) + spacing)) * row
const center = margin.left
let xPos = (margin.left + ((2 * r) * index + r) + (spacing * index)) - reset
const yPos = margin.top + r + (row * ((r * 2) + spacing) * verticalHexSeparation)
if (row % 2 != 0) xPos = xPos - (r + (spacing / 2))
const rows = Math.ceil(total / colCount)
const stackHeight = (margin.top + margin.bottom + (2 * r) + (rows * ((2 * r) + spacing))) * verticalHexSeparation
return {"x": xPos + center, "y": yPos, "h": stackHeight}
}
Insert cell
function doesHexGridFit(total, w, h, r, spacing, margin) {
const verticalHexSeparation = Math.sqrt(0.75) // Math.sqrt((r*r) - ((r/2)*(r/2)))
let colCount = Math.floor((w - margin.left - margin.right) / (2 * r + spacing))
if (colCount === 0) colCount = 1
const rows = Math.ceil(total / colCount)
const stackHeight = (margin.top + margin.bottom + (2 * r) + (rows * ((2 * r) + spacing))) * verticalHexSeparation
if (stackHeight > h) return false
else return true
}
Insert cell
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