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

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more