// extracted d3 code to bypass version conflicts // https://github.com/d3/d3-array/blob/main/src/group.js export function rollups(values, reduce, ...keys) { return nest(values, Array.from, reduce, keys); } function nest(values, map, reduce, keys) { return (function regroup(values, i) { if (i >= keys.length) return reduce(values); const groups = new Map(); const keyof = keys[i++]; let index = -1; for (const value of values) { const key = keyof(value, ++index, values); const group = groups.get(key); if (group) group.push(value); else groups.set(key, [value]); } for (const [key, values] of groups) { groups.set(key, regroup(values, i)); } return map(groups); })(values, 0); } function debounce(func, ms) { let isCooldown = false; return function () { if (isCooldown) return; func.apply(this, arguments); isCooldown = true; setTimeout(() => (isCooldown = false), ms); }; } function throttle(func, ms) { let isThrottled = false; let savedArgs; let savedThis; function wrapper() { if (isThrottled) { savedArgs = arguments; savedThis = this; return; } func.apply(this, arguments); isThrottled = true; setTimeout(function () { isThrottled = false; if (savedArgs) { wrapper.apply(savedThis, savedArgs); savedArgs = savedThis = null; } }, ms); } return wrapper; } function getBase64(url, callback) { const xhr = new XMLHttpRequest(); xhr.onload = function () { const reader = new FileReader(); reader.onloadend = function () { callback(reader.result); }; reader.readAsDataURL(xhr.response); }; xhr.open("GET", url); xhr.responseType = "blob"; xhr.send(); }