diff --git a/index.html b/index.html index c46682cc..00b5590f 100644 --- a/index.html +++ b/index.html @@ -7691,7 +7691,7 @@ - + diff --git a/modules/dynamic/editors/cultures-editor.js b/modules/dynamic/editors/cultures-editor.js index f5a148bc..43d0daba 100644 --- a/modules/dynamic/editors/cultures-editor.js +++ b/modules/dynamic/editors/cultures-editor.js @@ -6,6 +6,7 @@ import {rn} from "/src/utils/numberUtils"; import {capitalize} from "@/utils/stringUtils"; import {si} from "@/utils/unitUtils"; import {abbreviate} from "@/utils/languageUtils"; +import {debounce} from "@/utils/functionUtils"; const $body = insertEditorHtml(); addListeners(); diff --git a/modules/dynamic/editors/religions-editor.js b/modules/dynamic/editors/religions-editor.js index 291ee828..4891f546 100644 --- a/modules/dynamic/editors/religions-editor.js +++ b/modules/dynamic/editors/religions-editor.js @@ -5,6 +5,7 @@ import {byId} from "/src/utils/shorthands"; import {rn} from "/src/utils/numberUtils"; import {si} from "@/utils/unitUtils"; import {abbreviate} from "@/utils/languageUtils"; +import {debounce} from "@/utils/functionUtils"; const $body = insertEditorHtml(); addListeners(); diff --git a/modules/dynamic/overview/charts-overview.js b/modules/dynamic/overview/charts-overview.js index e2558a02..eee2f532 100644 --- a/modules/dynamic/overview/charts-overview.js +++ b/modules/dynamic/overview/charts-overview.js @@ -1,10 +1,10 @@ -import {rollups} from "../../../utils/functionUtils.js"; import {isWater} from "/src/utils/graphUtils"; import {tip} from "/src/scripts/tooltips"; import {byId} from "/src/utils/shorthands"; import {rn} from "/src/utils/numberUtils"; import {capitalize} from "@/utils/stringUtils"; import {si, convertTemperature} from "@/utils/unitUtils"; +import {rollups} from "@/utils/functionUtils"; const entitiesMap = { states: { diff --git a/modules/io/export.js b/modules/io/export.js index f68c84ee..0487f6c8 100644 --- a/modules/io/export.js +++ b/modules/io/export.js @@ -3,6 +3,7 @@ import {unique} from "/src/utils/arrayUtils"; import {tip} from "/src/scripts/tooltips"; import {getCoordinates} from "@/utils/coordinateUtils"; import {rn} from "/src/utils/numberUtils"; +import {getBase64} from "@/utils/functionUtils"; // download map as SVG async function saveSVG() { diff --git a/modules/ui/3d.js b/modules/ui/3d.js index c320f20e..6360dced 100644 --- a/modules/ui/3d.js +++ b/modules/ui/3d.js @@ -1,5 +1,6 @@ import {tip} from "/src/scripts/tooltips"; import {rn} from "/src/utils/numberUtils"; +import {throttle} from "@/utils/functionUtils"; window.ThreeD = (function () { const options = { diff --git a/modules/ui/heightmap-editor.js b/modules/ui/heightmap-editor.js index ef16756b..d2f01bd8 100644 --- a/modules/ui/heightmap-editor.js +++ b/modules/ui/heightmap-editor.js @@ -6,6 +6,7 @@ import {byId} from "/src/utils/shorthands"; import {rn, minmax, lim} from "/src/utils/numberUtils"; import {link} from "@/utils/linkUtils"; import {prompt} from "@/scripts/prompt"; +import {throttle} from "@/utils/functionUtils"; export function editHeightmap(options) { const {mode, tool} = options || {}; diff --git a/modules/ui/layers.js b/modules/ui/layers.js index 493422dd..7652753f 100644 --- a/modules/ui/layers.js +++ b/modules/ui/layers.js @@ -11,6 +11,7 @@ import {isCtrlClick} from "@/utils/keyboardUtils"; import {prompt} from "@/scripts/prompt"; import {rand, P} from "@/utils/probabilityUtils"; import {convertTemperature} from "@/utils/unitUtils"; +import {getBase64} from "@/utils/functionUtils"; let presets = {}; restoreCustomPresets(); // run on-load diff --git a/modules/ui/style.js b/modules/ui/style.js index c12974c3..d9957091 100644 --- a/modules/ui/style.js +++ b/modules/ui/style.js @@ -1,6 +1,7 @@ import {tip} from "/src/scripts/tooltips"; import {rn} from "/src/utils/numberUtils"; import {parseTransform} from "@/utils/stringUtils"; +import {getBase64} from "@/utils/functionUtils"; // add available filters to lists { diff --git a/modules/ui/submap.js b/modules/ui/submap.js index d5ad6054..b5059f1e 100644 --- a/modules/ui/submap.js +++ b/modules/ui/submap.js @@ -2,6 +2,7 @@ import {byId} from "/src/utils/shorthands"; import {clearMainTip} from "/src/scripts/tooltips"; import {parseError} from "@/utils/errorUtils"; import {rn, minmax} from "/src/utils/numberUtils"; +import {debounce} from "@/utils/functionUtils"; window.UISubmap = (function () { byId("submapPointsInput").addEventListener("input", function () { diff --git a/modules/zoom.js b/modules/zoom.js index 5def47fd..7573eeee 100644 --- a/modules/zoom.js +++ b/modules/zoom.js @@ -1,9 +1,9 @@ -"use strict"; +import {debounce} from "@/utils/functionUtils"; // temporary expose to global -let scale = 1; -let viewX = 0; -let viewY = 0; +window.scale = 1; +window.viewX = 0; +window.viewY = 0; window.Zoom = (function () { function onZoom() { diff --git a/src/scripts/events.ts b/src/scripts/events.ts index b353e8c0..31402f66 100644 --- a/src/scripts/events.ts +++ b/src/scripts/events.ts @@ -2,6 +2,7 @@ import {dragLegendBox} from "../modules/legend"; import {findCell, findGridCell} from "../utils/graphUtils"; import {tip, showMainTip} from "./tooltips"; import {si, convertTemperature} from "@/utils/unitUtils"; +import {debounce} from "@/utils/functionUtils"; export function restoreDefaultEvents() { Zoom.setZoomBehavior(); diff --git a/src/utils/functionUtils.js b/src/utils/functionUtils.js deleted file mode 100644 index c670496b..00000000 --- a/src/utils/functionUtils.js +++ /dev/null @@ -1,77 +0,0 @@ -// 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(); -} diff --git a/src/utils/functionUtils.ts b/src/utils/functionUtils.ts new file mode 100644 index 00000000..909aedf5 --- /dev/null +++ b/src/utils/functionUtils.ts @@ -0,0 +1,84 @@ +// extracted d3 code to bypass version conflicts +// https://github.com/d3/d3-array/blob/main/src/group.js +function nest( + values: TObject[], + map: (arrayLike: Map) => T[], + reduce: (value: TObject[]) => TReduce, + keys: ((value: TObject, index: number, values: TObject[]) => TKey)[] +) { + 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); +} + +export function rollups( + values: TObject[], + reduce: (value: TObject[]) => TReduce, + keys: ((value: TObject, index: number, values: TObject[]) => TKey)[] +) { + return nest(values, Array.from, reduce, keys); +} + +export function debounce any>(func: T, waitFor: number) { + let timeout: ReturnType; + return (...args: Parameters): ReturnType => { + let result: any; + timeout && clearTimeout(timeout); + timeout = setTimeout(() => { + result = func(...args); + }, waitFor); + return result; + }; +} + +export function throttle(func: Function, waitFor: number = 300) { + let inThrottle: boolean; + let lastFn: ReturnType; + let lastTime: number; + + return function (this: any) { + const context = this; + const args = arguments; + + if (!inThrottle) { + func.apply(context, args); + lastTime = Date.now(); + inThrottle = true; + } else { + clearTimeout(lastFn); + lastFn = setTimeout(() => { + if (Date.now() - lastTime >= waitFor) { + func.apply(context, args); + lastTime = Date.now(); + } + }, Math.max(waitFor - (Date.now() - lastTime), 0)); + } + }; +} + +export function getBase64(url: string, callback: (base64: string | ArrayBuffer | null) => void) { + 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(); +}