import { uniq } from 'lodash'; import { mean, min, max } from 'd3'; import { images } from '../inputs/dataPaths'; // extract attribution date range from data export const getTimeRange = (data) => { const maxAttributionDate = max(data, (d) => d.attributionDate); return([min(data, (d) => d.attributionDate), new Date( maxAttributionDate.getFullYear(), maxAttributionDate.getMonth() + 5 )]); }; // preload images export const preloadImages = (data) => { data.forEach((d) => (new Image()).src = `${images}${d.caseHash}.jpg`); } // split string in array export const splitString = (s) => { if (s === '' || s === ',') return ['unspecified']; return(s .split(',') .map((d) => d.trim()) .filter((d) => d !== '')); }; // clean countries array export const cleanCountries = (countries) => countries .map((c) => c .trim() .replace(/^US$/, 'United States of America') .replace(/^United States$/, 'United States of America') ); // check, if there's an overlap between array and filter export const haveOverlap = (filter, arr) => filter.filter((d) => d.selected).map((d) => d.id).some((item) => arr.includes(item)); // check, if a number is within a 2D range (given as array with length 2) export const withinRange = (arr, num) => num >= arr[0] && num <= arr[1]; // check, if a search string (filter) is included in a string export const includesTextSearch = (filter, s) => s.indexOf(filter.toUpperCase()) > -1; // check if case id filter is set and if id is matching export const isCaseId = (filter, id) => filter === undefined ? true : (filter === id); // extract filter items from data export const extractFilterCategories = (data, name) => uniq(data.map((d) => d[name]).flat()); // functions to compute density // https://www.d3-graph-gallery.com/graph/density_basic.html export const kernelEpanechnikov = (k) => (v) => Math.abs((v /= k)) <= 1 ? (0.75 * (1 - v * v)) / k : 0; export const kernelDensityEstimator = (kernel, X) => (V) => X.map((x) => [ x, mean(V, function (v) { return kernel(x - v); }), ]); // extract host name from URL // https://stackoverflow.com/questions/8498592/extract-hostname-name-from-string export const extractHostname = (url) => { let hostname = url.indexOf('//') > -1 ? url.split('/')[2] : url.split('/')[0]; hostname = hostname.split(':')[0]; hostname = hostname.split('?')[0]; return hostname; }; // consistent sort function export const sortConsistently = (itemA, itemB, property, key) => { let valueA = itemA[property]; let valueB = itemB[property]; if (typeof valueA === 'string') valueA = valueA.trim().toLowerCase(); if (typeof valueB === 'string') valueB = valueB.trim().toLowerCase(); if (typeof valueA === 'number') valueA = +valueA; if (typeof valueB === 'number') valueB = +valueB; if (typeof valueA === 'number' && isNaN(valueA)) valueA = 0; if (typeof valueB === 'number' && isNaN(valueB)) valueB = 0; let r = valueA > valueB ? -1 : valueA < valueB ? 1 : 0; if (r === 0) { r = typeof itemA[key] !== 'undefined' && typeof itemB[key] !== 'undefined' ? +itemA[key] - +itemB[key] : 0; } return r; }; // scroll-to function (also set on window to make it available outside svelte) export const scrollTo = (targetId, collapsibleId) => { if (collapsibleId) { document.getElementById(collapsibleId).checked = true; } document.querySelector('.draw-wrapper').classList.add('no-pointer-events'); setTimeout(() => { document.getElementById(targetId).scrollIntoView({behavior: 'smooth'}); setTimeout(() => { document.querySelector('.draw-wrapper').classList.remove('no-pointer-events'); }, 1000); }, 200); return(false); }; window.scrollsmooth = scrollTo;