Published
Edited
Oct 28, 2020
10 stars
Insert cell
Insert cell
Insert cell
Insert cell
blurs = {
const a = [];
for (const [blur, label] of [
[blurredFilter, "Filter"], // reference solution; however: doesn't work on Safari; very slow on Firefox
[blurredCircular, "Circular"], // good speed; ok for text, not so good for lines
[blurredVertical, "Vertical"], // bad for text; sort-of nice for horizontal lines
[blurredHorizontal, "Horizontal"] // bad for text; sort-of nice for vertical lines
]) {
a.push(await show(blur, label));
}

return html`${a}`;
}
Insert cell
async function show(blur, text) {
const context = DOM.context2d(width, height);

await Promises.delay(Math.random() * 1000);

const grd = context.createLinearGradient(0, 0, width, 0);
for (let i = 0; i < 1; i += .1) grd.addColorStop(i, d3.interpolateInferno(i));

context.lineWidth = 15;
const radius = 5;

context.font = "30px Arial";

const a = performance.now();
for (let i = 0; i < 100; i++) {
context.clearRect(0, 0, width, height);
blur(context, () => context.fillText(text, 100, 100), 2.5);
blur(context, () => context.stroke(path), radius);

context.translate(0, 40);
context.strokeStyle = "red";
blur(context, () => context.stroke(path), radius);

context.translate(0, 40);

context.strokeStyle = grd;
blur(context, () => context.stroke(path), radius);

context.translate(0, -80);
}

context.font = "11px Arial";
context.fillText(
`${Math.round(performance.now() - a)}ms / ${100}`,
10,
height - 20
);

return context.canvas;
}
Insert cell
function blurredCircular(context, operation, radius, step = .2) {
radius /= 2;
const alpha = context.globalAlpha;
context.globalAlpha = alpha * step * 1.4;
for (let a = 0; a < 1; a += step) {
const x = radius * Math.cos(a * tau),
y = radius * Math.sin(a * tau);
context.translate(x, y);
operation();
context.translate(-x, -y);
}
context.globalAlpha = alpha;
}
Insert cell
function blurredVertical(context, operation, radius, step = 1) {
const alpha = context.globalAlpha;
context.save();
let w = 0;
for (let i = -radius; i <= radius; i += step) w += factor(i / radius);
w = 1.4 / w;
for (let i = -radius; i <= radius; i += step) {
context.globalAlpha = alpha * factor(i / radius) * w;
context.translate(0, i);
operation();
context.translate(0, -i);
}
context.restore();

function factor(x) {
return Math.exp(-(x * x));
}
}
Insert cell
function blurredHorizontal(context, operation, radius, step = 1) {
const alpha = context.globalAlpha;
context.save();
let w = 0;
for (let i = -radius; i <= radius; i += step) w += factor(i / radius);
w = 1.4 / w;
for (let i = -radius; i <= radius; i += step) {
context.globalAlpha = alpha * factor(i / radius) * w;
context.translate(i, 0);
operation();
context.translate(-i, 0);
}
context.restore();

function factor(x) {
return Math.exp(-(x * x));
}
}
Insert cell
function blurredFilter(context, operation, radius) {
const alpha = context.globalAlpha;
context.save();
context.filter = `blur(${radius}px)`; // doesn't work in Safari
operation();
context.restore();
}
Insert cell
tau = 2 * Math.PI
Insert cell
path = {
const random = d3.randomLcg(114);
let y = 100;
return new Path2D(
d3.line().curve(d3.curveBasis)(
d3.range(30, width - 30, 20).map(x => [x, (y += 100 * (random() - .5))])
)
);
}
Insert cell
height = 300
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