UNPKG

gobierto-vizzs

Version:

Shared data visualizations for Gobierto projects

136 lines (115 loc) 3.54 kB
import { select, pointer } from "d3-selection"; import { timeFormatDefaultLocale } from "d3-time-format"; import { version } from "../../package.json" import { es, ca, gl } from "./locales" import "./palette.css" import "./tooltip.css" const DEFAULT_LOCALES = { "es-ES": es, "ca-ES": ca, "gl-ES": gl, } export default class Base { constructor(container, _, options) { this.container = container this.version = version this.locale = options.locale || window.navigator.language this.PALETTE = Array.from({ length: 12 }, (_, i) => `var(--gv-color-${i + 1})`) window.addEventListener("resize", this.resizeListener.bind(this)); } async getLocale() { // unpkg does not keep non-regional locales (2-letters code), so it's worthless make the request if (this.locale.length > 2) { // request the locale when it does not exists by default const i18n = DEFAULT_LOCALES[this.locale] || await fetch(`https://unpkg.com/d3-time-format/locale/${this.locale}.json`).then(r => r.json()) if (i18n) { timeFormatDefaultLocale(i18n) } } } async setLocale(value) { this.locale = value await this.getLocale() this.build() } // defined in the inherited classes getDimensions() {} // defined in the inherited classes build() {} resizeListener() { this.getDimensions(); this.build(); } remove() { window.removeEventListener("resize", this.resizeListener.bind(this)); } isSmallDevice() { return screen.width < 768 } wrap(text, width, marginLeft = 0) { text.each(function () { var text = select(this), words = text.text().split(/\s+/).reverse(), word, line = [], lineHeight = 1, y = text.attr("y"), dy = 0, tspan = text .text(null) .append("tspan") .attr("x", marginLeft) while ((word = words.pop())) { line.push(word); tspan.text(line.join(" ")); if (tspan.node().getComputedTextLength() > width) { text.attr("class", "wrap-text") line.pop(); tspan.text(line.join(" ")); line = [word]; tspan = text .append("tspan") .attr("x", marginLeft) .attr("dy", lineHeight + dy + "em") .text(word); } } }); } tooltipPosition(event, element, offset = 0) { const [x,y] = pointer(event, this.container) const { width: pW, height: pH } = this.container.getBoundingClientRect(); const { width, height } = element.getBoundingClientRect(); const isLeft = x < pW * 0.5; const isTop = y < pH * 0.5; return isLeft && isTop ? [x + offset, y + offset] : isLeft && !isTop ? [x + offset, (y - height) - offset] : !isLeft && isTop ? [x - width - offset, y + offset] : [x - width - offset, y - height - offset]; } seed(len = 24) { return [...Array(len)].map(() => Math.random().toString(36)[2]).join('') } debounce(func, timeout) { let timer = undefined; return (...args) => { const next = () => func(...args); if (timer) { clearTimeout(timer); } timer = setTimeout(next, timeout > 0 ? timeout : 300); }; } groupBy(arr, key) { return arr.reduce((acc, item) => ((acc[item[key]] = [...(acc[item[key]] || []), item]), acc), {}) } sortBy(prop) { return (a, b) => a[prop] > b[prop] ? 1 : -1 } isDate(...value) { return !Number.isNaN(+new Date(...value)) } }