Published
Edited
Jan 11, 2022
Importers
1 star
Insert cell
Insert cell
$ = tex
Insert cell
$$ = tex.block
Insert cell
isThumbnailDaemon = !!navigator.userAgent.match('HeadlessChrome')
Insert cell
Insert cell
sprintf = (await require('sprintf-js@1.1.2/dist/sprintf.min.js')).sprintf
Insert cell
qs = require('qs@6.9.1/dist/qs.js')
Insert cell
function sig(fn, desc = '') {
const pattern = /\)(?= *?\{)/;
const head = fn.toString().split(pattern, 1)[0] + ')';
const code = md`\`\`\`javascript\n${head}\n\`\`\``;
return html`<div style="border:1px solid #eee;padding:.5em 1em;margin-bottom:1em">
<div style="border-bottom:1px solid #eee">${code}</div>
${desc}
`;
}
Insert cell
function decodeHash (hash) {
try {
var parts = hash.replace(/^#/,'').split('&').map(x => x.split('=').map(x => decodeURIComponent(x)))
var output = {}
for (var i = 0; i < parts.length; i++) {
output[parts[i][0]] = parts[i][1]
}
} catch (e) {
return {}
}
return output
}
Insert cell
h = ({ f: 'z', x: [1, 2] })
Insert cell
encodeHash(h)
Insert cell
function encodeHash(hash) {
const q = new URLSearchParams();
for (const [key, value] of Object.entries(hash)) {
q.set(key, value);
}
return q.toString();
}
Insert cell
parseQueryString("f=z&x=1%2C2")
Insert cell
parseQueryString = {
return function parseQueryString(str) {
let asNumber;
const q = new URLSearchParams(str);
const obj = {};
for (let [key, value] of q.entries()) {
if (value.length === 0 || value === "true") {
value = true;
} else if (value === "false") {
value = false;
} else if (!isNaN((asNumber = parseFloat(value)))) {
value = asNumber;
} else {
value = decodeURIComponent(value);
}
if (obj.hasOwnProperty(key)) {
if (!Array.isArray(obj[key])) obj[key] = [obj[key]];
obj[key].push(value);
} else {
obj[key] = value;
}
}
return obj;
};
}
Insert cell
function floatRgbToHex (rgb) {
return '#' + rgb.map(x => Math.floor(Math.max(0, Math.min(255, x * 255))).toString(16).padStart(2, '0')).join('')
}
Insert cell
function hexRgbToFloat (hex) {
let match
if ((match = hex.match(/#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/))) {
return [parseInt(match[1], 16) / 255, parseInt(match[2], 16) / 255, parseInt(match[3], 16) / 255]
} else if ((match = hex.match(/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/))) {
return [parseInt(match[1], 16) / 15, parseInt(match[2], 16) / 15, parseInt(match[3], 16) / 15]
}
return [0, 0, 0]
}
Insert cell
function hexToFloatRgba(hex, alpha) {
let match;
alpha = alpha === undefined ? 1 : +alpha;
if (
(match = hex.match(/#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})/))
) {
return [
parseInt(match[1], 16) / 255,
parseInt(match[2], 16) / 255,
parseInt(match[3], 16) / 255,
alpha
];
} else if ((match = hex.match(/#([0-9a-fA-F])([0-9a-fA-F])([0-9a-fA-F])/))) {
return [
parseInt(match[1], 16) / 15,
parseInt(match[2], 16) / 15,
parseInt(match[3], 16) / 15,
alpha
];
}
return [0, 0, 0, alpha];
}
Insert cell
mouseEventOffset = {
// Obtained from: https://github.com/mattdesl/mouse-event-offset
//
// The MIT License (MIT) Copyright (c) 2014 Matt DesLauriers
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the "Software"),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
// and/or sell copies of the Software, and to permit persons to whom the
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
var rootPosition = { left: 0, top: 0 };

function getBoundingClientOffset(element) {
if (
element === window ||
element === document ||
element === document.body
) {
return rootPosition;
} else {
return element.getBoundingClientRect();
}
}

function mouseEventOffset(ev, target, out) {
target = target || ev.currentTarget || ev.srcElement;
if (!Array.isArray(out)) {
out = [0, 0];
}
var cx = ev.clientX || 0;
var cy = ev.clientY || 0;
var rect = getBoundingClientOffset(target);
out[0] = cx - rect.left;
out[1] = cy - rect.top;
return out;
}

return mouseEventOffset;
}
Insert cell
Insert cell
assert = {
function assert (ok, message) {
if (!ok) throw new Error('✗ '+(message ? message : 'not ok'));
}
assert.almostEqual = function assertAlmostEqual (a, b, msg, tol) {
if (!almostEqual(a, b)) throw new Error('✗ '+(msg ? msg + ' ' : '')+'Expected '+a+' to equal '+b+' within tolerance '+tol)
}
assert.arrayAlmostEqual = function assertArrayAlmostEqual (a, b, tol) {
tol = almostEqual.DBL_EPSILON
if (a.length !== b.length) throw new Error('✗ Expected a.length (='+a.length+') to equal b.length (='+b.length+')')
for (var i = 0; i < a.length; i++) {
if (!almostEqual(a[i], b[i], tol, tol)) throw new Error('✗ Expected a['+i+'] (='+a[i]+') to equal b['+i+'] (='+b[i]+') within tolerance '+tol)
}
}
return assert;
}
Insert cell
Insert cell
function binarySearch(x, value) {
let lo = 0,
hi = x.length - 1;
if (value <= x[0]) return lo;
if (value >= x[hi]) return hi;
while (lo < hi - 1) {
let m = ((lo + hi) / 2) | 0;
let xm = x[m];
if (xm > value) {
hi = m;
} else if (xm < value) {
lo = m;
} else {
return m;
}
}
return lo;
}
Insert cell
Insert cell
function arrayAlmostEqual (a, b, absoluteError, relativeError) {
if (a.length !== b.length) return false
for (var i = 0; i < a.length; i++) {
if (!almostEqual(a[i], b[i], absoluteError, relativeError)) return false
}
return true
}
Insert cell
Insert cell
arrayAlmostEqual([0, 1], [1e-16, 1], 1e-4, 1e-4)
Insert cell
Insert cell
Insert cell
function arrowhead (opts) {
opts = opts || {}
const w = opts.width === undefined ? 9 : opts.width
const l = opts.length === undefined ? 11 : opts.length
const c = opts.cut === undefined ? 1 : opts.cut
return function (el) {
return el.attr('refX', l / 2)
.attr('refY', w / 2)
.attr('markerWidth', l)
.attr('markerHeight', w)
.attr('viewbox', `0 0 ${l} ${w}`)
.attr('orient', 'auto-start-reverse')
.append('path')
.attr('d', `M2,2L${l - 2},${w / 2}L2,${w - 2}L${2 + c},${w / 2}L2,2`)
}
}
Insert cell
function downloadURI(uri, filename) {
var link = document.createElement("a");
link.target = '_blank';
link.download = filename;
link.href = uri;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
}
Insert cell
Insert cell
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