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

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