Published
Edited
Aug 21, 2021
4 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
// Convert SVG to canvas
canvasImage = {
const canvas = DOM.canvas(renderedHeight, renderedWidth);
const ctx = canvas.getContext("2d");
const v = canvg.Canvg.fromString(ctx, serialize(quoteSvg));
v.start();
ctx.drawImage(
logo,
Math.round(canvas.width - renderedPadding - renderedLineHeight),
Math.round(canvas.height - renderedPadding - renderedLineHeight),
Math.round(renderedLineHeight),
Math.round(renderedLineHeight)
);
yield canvas;
}
Insert cell
Insert cell
mutable fontsLoaded = false
Insert cell
// Inspired by https://observablehq.com/@grantcuster/minimal-font-loading-test
{
var font = new FontFaceObserver("Orelega One");
font.load().then(
() => {
mutable fontsLoaded = true;
},
() => {
console.log("Font is not available");
}
);
return "Fonts loaded.";
}
Insert cell
// // Load fonts
html`
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Orelega+One&display=swap" rel="stylesheet">
`
Insert cell
// This simply supresses the display of the giant-ass SVG.
html`<div style="display: none;">${quoteSvg}</div>`
Insert cell
// Render the svg
quoteSvg = {
if (!fontsLoaded) {
return html`<p>Awaiting fonts...</p>`;
}

const svg = d3
.create("svg")
.attr("width", renderedWidth)
.attr("height", renderedHeight);

// Explicitly set a background rectangle to effectively set a background
// color. Otherwise, the rasterizer makes a transparent background.
const bg = svg
.append("rect")
.attr("width", renderedWidth)
.attr("height", renderedHeight)
.attr("fill", backgroundColor);

svg
.append("g")
.append("text")
.attr("font-size", `${renderedQuoteSize}px`)
.attr("fill", textColor)
.attr("font-family", "Orelega One, sans-serif")
.attr("x", (d) => renderedPadding)
.attr("y", (d) => renderedQuoteSize + renderedPadding)
.selectAll("tspan")
.data(quoteLines)
.join("tspan")
.attr("x", (d) => renderedPadding)
.attr("y", (d) => renderedQuoteSize + renderedPadding)
.attr("dx", 0)
.attr("dy", (d, i) => i * renderedLineHeight)
.text((d) => d);

svg
.append("g")
.append("text")
.attr("font-size", `${renderedQuoteSize}px`)
.attr("fill", textColor)
.attr("font-family", "Orelega One, sans-serif")
.attr("x", (d) => renderedPadding)
.attr("y", (d) => renderedHeight - renderedPadding)
.text((d) => `— ${quoteAuthor}`);

return svg.node();
}
Insert cell
// Notebook styles
stylesheet = html`
<style>
.observablehq button {
font-size: 1.35em;
border-radius: .35em;
padding: .3em .5em;
color: white;
background-color: #1FBEC3;
border: none;
}
/* Fake old inputs into new format */
.observablehq form div > div {
display: inline-block;
font-weight: normal !important;
font-size: 0.75em !important;
width: 124px;
}
</style>`
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
FontFaceObserver = require("https://bundle.run/fontfaceobserver@2.1.0")
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