Published
Edited
Aug 27, 2020
5 forks
Importers
23 stars
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
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
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
function config(type, settings = {}) {
let value = {};
const form = html`<form style="font: 12px var(--sans-serif); display: flex; flex-direction: column; justify-content: center; min-height: 33px;">
${Object.entries(settings).map(([name, {min, max}]) => html`<label style="display: flex; align-items: center;">
<input type="range" name="${name}" min="${min}" max="${max}" step="any" style="width: 180px;">
<div style="margin-left: 0.5em;"><i>${type}</i>.${name}(<output></output>)</div>
</label>`)}
</form>`;
for (const [name, {value: defaultValue, transform = x => +x}] of Object.entries(settings)) {
value[name] = transform(defaultValue);
form[name].value = defaultValue;
form[name].parentNode.querySelector("output").value = value[name].toFixed(2);
form[name].oninput = () => {
form.value = value = {...value, [name]: +transform(form[name].valueAsNumber).toPrecision(3)};
form[name].parentNode.querySelector("output").value = value[name].toFixed(2);
};
}
form.value = value;
return form;
}
Insert cell
function chart(eases) {
const line = d3.line();

const svg = d3.create("svg")
.attr("viewBox", [0, 0, width, height])
.style("max-width", `${width}px`)
.style("overflow", "visible");

svg.append("g")
.attr("fill", "none")
.attr("stroke", "black")
.attr("stroke-width", 1.5)
.attr("stroke-linecap", "round")
.selectAll("path")
.data(eases)
.join("path")
.attr("stroke-width", (e, i) => i < eases.length - 1 ? 0.25 : null)
.attr("d", e => line(d3.ticks(0, 1, width).map(t => [x(t), y(e(t))])));

svg.append("g")
.call(xAxis)
.call(g => g.append("text")
.attr("x", width - margin.right)
.attr("y", -3)
.attr("fill", "currentColor")
.attr("font-weight", "bold")
.text("t"));

svg.append("g")
.call(yAxis)
.call(g => g.select(".tick:last-of-type text").clone()
.attr("x", 3)
.attr("text-anchor", "start")
.attr("font-weight", "bold")
.text("t′"));

return svg.node();
}
Insert cell
x = d3.scaleLinear().range([margin.left, width - margin.right])
Insert cell
y = d3.scaleLinear().range([height - margin.bottom, margin.top])
Insert cell
xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom + 6})`)
.call(d3.axisBottom(x.copy().interpolate(d3.interpolateRound)).ticks(width / 60))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("stroke-opacity", 0.1)
.attr("y1", margin.bottom + margin.top - height - 12))
Insert cell
yAxis = g => g
.attr("transform", `translate(${margin.left - 6},0)`)
.call(d3.axisLeft(y.copy().interpolate(d3.interpolateRound)).ticks(5))
.call(g => g.select(".domain").remove())
.call(g => g.selectAll(".tick line").clone()
.attr("stroke-opacity", 0.1)
.attr("x1", width - margin.left - margin.right + 12))
Insert cell
width = 640
Insert cell
height = 240
Insert cell
margin = ({top: 10, right: 20, bottom: 20, left: 30})
Insert cell
d3 = require("d3@6")
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