Public
Edited
Apr 10, 2024
Insert cell
Insert cell
// [...document.fonts].map(f => Object.fromEntries(Object.keys(f.constructor.protptype).map(k => [k, f[k]])))
Insert cell
{
fontFamily, fontSize, fontWeight, text;
let f = [...document.fonts]
.map(f => Object.fromEntries(Object.keys(f.constructor.prototype).map(k => [k, f[k]])));

document.fonts.ready.then(
() => {
// const fontList = (
// [...document.fonts]
// .map(f => Object.fromEntries(Object.keys(f.constructor.prototype).map(k => [k, f[k]])))
f = f
.filter(f => f.family === fontFamily && f.status === "loaded")
;
}
);
return f;
}
Insert cell
[...document.fonts].map(f => Object.fromEntries(Object.keys(f.constructor.prototype).map(k => [k, f[k]])))
Insert cell
{
fontFamily, fontSize, fontWeight, text;
document.fonts.ready.then(() => console.log("ready"));
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
{ // Source: https://observablehq.com/@mbostock/autosize-svg
// ref https://talk.observablehq.com/t/getbbox/1222
const svg = html`<svg style="border:solid 1px red;">
<g name="content">
<text style="font-weight: ${fontWeight};font-size:${fontSize};font-family:${fontFamily}">${DOM.text(text)}</text>
</g>
</svg>`;

document.fonts.ready.then(() => {

// Add the SVG element to the DOM so we can determine its size.
document.body.appendChild(svg);

// Computing the bounding box of the content.
const box = svg.querySelector("[name=content]").getBBox();

// Remove the SVG element from the DOM.
svg.remove();

// Set the viewBox.
svg.setAttribute("width", box.width);
svg.setAttribute("height", box.height);
svg.setAttribute("viewBox", `${box.x} ${box.y} ${box.width} ${box.height}`);
});

return svg;
}
Insert cell
viewof BBoxTest = {
const grid = Grid({divisions: 6, aspect: {tall: 2, wide: 16}, opacity: .2}).sketch();
const {pad, plot, q, M} = grid;
const ƒ = (n) => n.toFixed(1);
const {fontFamily, fontWeight, fontSize} = font;

const g = pad
.append("g")
.style("font-family", fontFamily)
.style("font-weight", fontWeight)
.style("font-size", fontSize)
;
const t = g
.append("g")
.attr("transform", `translate(${M(3)}, ${M(1)})`)
;
t
.append("text")
.text(text)
;
const {x, y, width, height} = getBBox(text, font);
t
.append("rect")
.attr("stroke", "red")
.attr("fill", "transparent")
.attr("width", width)
.attr("height", height)
.attr("x", x)
.attr("y", y)
;

const metrics = [
{label: "x", value: x},
{label: "y", value: y},
{label: "width", value: width},
{label: "height", value: height},
{label: "wide", value: width/q()},
{label: "tall", value: height/q()},
];
const texts = g
.append("g")
.attr("transform", `translate(0, ${q(3)})`)
.attr("font-family", fontFamily)
.attr("font-weight", "normal")
.attr("font-size", "18px")
.attr("fill", "grey")
.attr("text-anchor", "end")
.selectAll("text")
.data(metrics)
;
texts
.join("text")
.text(d => `${d.label}:`)
.attr("dx", q(7))
.attr("dy", (_, i) => q(2 * i - 1))
;
texts
.join("text")
.text(d => `${ƒ(d.value)}`)
.attr("dx", q(13))
.attr("dy", (_, i) => q(2 * i - 1))
;
Object.defineProperty(grid.frame.node(), "value", {get: () => ({x, y, width, height})});

return grid.frame.node();
}
Insert cell
function getBBox(txt, {fontFamily, fontSize, fontWeight}) {
const svg = d3.create('svg').attr("name", "margarine");
const tmp = svg
.append("text")
.style("font-family", fontFamily)
.style("font-size", fontSize)
.style("font-weight", fontWeight)
.text(txt)
;
document.body.appendChild(svg.node());
const b = tmp.node().getBBox();
document.body.removeChild(svg.node());
tmp.remove();
return b;
const { x, y, width, height } = b;
return { x, y, width, height };
}
Insert cell
fonts = [
"Roboto Condensed",
"Roboto Slab",
"Roboto",
"PT Sans Narrow",
"Courier",
// "Neutraface Text Book",
// "Neutraface Condensed Thin",
// "Taz SemiBold",
"IBM Plex Mono",
"Noto Sans Mono",
"Noto Sans",
]
Insert cell
font = ({
fontFamily,
fontWeight,
fontSize,
})
Insert cell
<style>
@import url("https://fonts.googleapis.com/css2?family=${fontFamily}:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");
@font-face {
font-family: "Neutraface Text Book";
src: url('${await FileAttachment("Neutraface Text Book.woff2").url()}');
}
/* @font-face {
font-family: "Neutraface Condensed Thin";
src: url('${await FileAttachment("Neutraface Condensed Thin.woff2").url()}');
}
@font-face {
font-family: "Taz SemiBold";
src: url('${await FileAttachment("Taz-SemiBold.woff2").url()}');
} */
</style>
Insert cell
{
const log = document.getElementById("martien");
// log.textContent = "";
const font = new FontFace(
// fontFamily,
// `url("https://fonts.googleapis.com/css2?family=${fontFamily}&display=swap")`
// "Poppins",
// "url(https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap)",
// "url('https://fonts.googleapis.com/css2?family=Poppins&display=swap')"
"FontFamily Oxygen",
// "url(https://fonts.gstatic.com/s/oxygen/v5/qBSyz106i5ud7wkBU-FrPevvDin1pK8aKteLpeZ5c0A.woff2)",
"url(https://fonts.googleapis.com/css2?family=Oxygen)"
// "url('https://fonts.googleapis.com/css2?family=Oxygen:wght@300;400;700&display=swap')"
);
document.fonts.add(font);
// log.textContent += `${font.family}: ${font.status}…`;

let pad = d3.create("svg").attr("width",width);
pad.append("text").text(font.family)
.style("font-size", 72)
.attr("x", 36)
.attr("y", 72)
;
document.fonts.load("1px FontFamily Oxygen").then(
() => {
// log.textContent += `${font.status}`; // font: loaded
pad.style("font-family", font.family)
},
(err) => {
console.error(err);
},
);
return pad.node();
}
Insert cell
Insert cell
document.getElementById("martien")
Insert cell
Insert cell
hallo ="hallo"
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