Published
Edited
Feb 16, 2021
Importers
6 stars
Insert cell
Insert cell
Insert cell
Insert cell
math_css = `
<style>
.observablehq .katex,
.observablehq .katex-display>.katex { font-size: 1.08em; }
</style>`
Insert cell
$css = html`${math_css}`
Insert cell
$ = {
$css;
var $ = tex.options({trust: true});
$.options = (opts) => tex.options(Object.assign({trust: true}, opts));
return $;
}
Insert cell
$$ = $css, tex.options({displayMode: true, trust: true})
Insert cell
Insert cell
responsive_katex = (cell_invalidation, katex_root) => {
const div = html`<div>${katex_root}`;
div.style.transformOrigin = `top left`;

const width_updates = width_observer();
cell_invalidation.then(() => width_updates.return());
(async function (){
// wait for the content to render before measuring size
await new Promise(callback => requestAnimationFrame(callback));
const katex_width = [...katex_root.querySelectorAll('.katex-html .base')]
.reduce((acc, elem) => acc + elem.getBoundingClientRect().width, 0);
const katex_height = katex_root.getBoundingClientRect().height;

// listen to changes in width and rescale as necessary.
for await (const width of width_updates) {
const scale = Math.min(width/katex_width, 1);
const vertical_gap = (1-scale)*katex_height;
div.style.transform = `scale(${scale})`;
div.style.marginBottom = `-${vertical_gap}px`;
}
})();
return div;
}
Insert cell
width_observer = () => Generators.observe(callback => {
let current_width, previous_width;
const resized = () => {
if ((current_width = document.body.clientWidth) !== previous_width)
callback(previous_width = current_width); };
resized(), window.addEventListener('resize', resized);
return () => window.removeEventListener('resize', resized);
})
Insert cell
Insert cell
little_endian = new Int8Array(new Int16Array([0x0001]).buffer)[0];
Insert cell
Insert cell
thumbnail_daemon = navigator.userAgent.match('HeadlessChrome')
Insert cell
Insert cell
animate = {
intersection_observer_polyfill;
return function animate(element, cell_invalidation, drawframe) {
if (thumbnail_daemon) { drawframe(+new Date); return element }
let frame, tick, cleanup, intersect;
tick = function tick(timestamp) { drawframe(timestamp); frame = requestAnimationFrame(tick); }
cleanup = function cleanup() { cancelAnimationFrame(frame); };
intersect = function intersect(entries) {
for (let e of entries) e.isIntersecting ? tick(+new Date) : cleanup(); }
new IntersectionObserver(intersect).observe(element);
cell_invalidation.then(cleanup);
tick();
return element;
}
}
Insert cell
intersection_observer_polyfill = {
if (window.IntersectionObserver)
return html`<code>native IntersectionObserver`;
await require('intersection-observer@0.9/intersection-observer.js').catch(
() => window["IntersectionObserver"])
return html`<code>polyfilled IntersectionObserver`;
}
Insert cell
IntersectionObserver = {
intersection_observer_polyfill;
return window.IntersectionObserver; }
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