aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTerry Truong <terry06890@gmail.com>2023-01-21 14:08:48 +1100
committerTerry Truong <terry06890@gmail.com>2023-01-21 14:12:30 +1100
commitd581e5b61a771ef8619a5bfbc84a6e337c7ca13f (patch)
treee372aab2a7ab95d6fd22dcfe99f3f1985456ecc7
parentbf357e48dc261dab08598bd93071ca53ef386402 (diff)
Move general utility funcs into util.ts
-rw-r--r--src/App.vue10
-rw-r--r--src/components/BaseLine.vue3
-rw-r--r--src/components/SearchModal.vue3
-rw-r--r--src/components/TimeLine.vue12
-rw-r--r--src/lib.ts133
-rw-r--r--src/store.ts2
-rw-r--r--src/util.ts126
-rw-r--r--tests/lib.test.ts12
8 files changed, 155 insertions, 146 deletions
diff --git a/src/App.vue b/src/App.vue
index 0e7e912..99ba03c 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -72,10 +72,12 @@ import SettingsIcon from './components/icon/SettingsIcon.vue';
import PlusIcon from './components/icon/PlusIcon.vue';
import SearchIcon from './components/icon/SearchIcon.vue';
-import {HistDate, HistEvent, queryServer,
- EventResponseJson, jsonToHistEvent, EventInfo, EventInfoJson, jsonToEventInfo,
- SCALES, stepDate, TimelineState, cmpHistEvent, dateToUnit, DateRangeTree,
- makeThrottled, makeThrottledSpaced} from './lib';
+import {makeThrottled, makeThrottledSpaced} from './util';
+import {
+ HistDate, HistEvent, EventInfo, cmpHistEvent,
+ queryServer, EventResponseJson, jsonToHistEvent, EventInfoJson, jsonToEventInfo,
+ SCALES, stepDate, dateToUnit, TimelineState, DateRangeTree,
+} from './lib';
import {useStore} from './store';
import {RBTree, rbtree_shallow_copy} from './rbtree';
diff --git a/src/components/BaseLine.vue b/src/components/BaseLine.vue
index 3cca6d7..91f5b69 100644
--- a/src/components/BaseLine.vue
+++ b/src/components/BaseLine.vue
@@ -16,7 +16,8 @@
<script setup lang="ts">
import {ref, computed, onMounted, PropType, Ref} from 'vue';
-import {MIN_DATE, MAX_DATE, SCALES, MONTH_SCALE, DAY_SCALE, WRITING_MODE_HORZ, TimelineState, stepDate} from '../lib';
+import {WRITING_MODE_HORZ} from '../util';
+import {MIN_DATE, MAX_DATE, SCALES, MONTH_SCALE, DAY_SCALE, stepDate, TimelineState} from '../lib';
import {useStore} from '../store';
const rootRef = ref(null as HTMLElement | null);
diff --git a/src/components/SearchModal.vue b/src/components/SearchModal.vue
index 543c7f3..ec1b4cd 100644
--- a/src/components/SearchModal.vue
+++ b/src/components/SearchModal.vue
@@ -36,7 +36,8 @@
import {ref, computed, onMounted, PropType} from 'vue';
import SearchIcon from './icon/SearchIcon.vue';
import InfoIcon from './icon/InfoIcon.vue';
-import {HistEvent, queryServer, EventInfoJson, jsonToEventInfo, SuggResponseJson, animateWithClass} from '../lib';
+import {animateWithClass} from '../util';
+import {HistEvent, queryServer, EventInfoJson, jsonToEventInfo, SuggResponseJson} from '../lib';
import {useStore} from '../store';
import {RBTree} from '../rbtree';
diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue
index ab37342..a040233 100644
--- a/src/components/TimeLine.vue
+++ b/src/components/TimeLine.vue
@@ -88,11 +88,13 @@ import {ref, onMounted, onUnmounted, computed, watch, PropType, Ref} from 'vue';
import IconButton from './IconButton.vue';
import CloseIcon from './icon/CloseIcon.vue';
-import {WRITING_MODE_HORZ, MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES, MONTH_NAMES, MIN_CAL_DATE,
- getDaysInMonth, HistDate, stepDate, getScaleRatio, getNumSubUnits, getUnitDiff,
- getEventPrecision, dateToUnit, dateToScaleDate,
- moduloPositive, TimelineState, HistEvent, getImagePath,
- animateWithClass, getTextWidth} from '../lib';
+import {WRITING_MODE_HORZ, moduloPositive, animateWithClass, getTextWidth} from '../util';
+import {
+ getDaysInMonth, MIN_CAL_DATE, MONTH_NAMES, HistDate, HistEvent, getImagePath,
+ MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES,
+ stepDate, getScaleRatio, getNumSubUnits, getUnitDiff, getEventPrecision, dateToUnit, dateToScaleDate,
+ TimelineState,
+} from '../lib';
import {useStore} from '../store';
import {RBTree} from '../rbtree';
diff --git a/src/lib.ts b/src/lib.ts
index 7c65d6b..e8ed448 100644
--- a/src/lib.ts
+++ b/src/lib.ts
@@ -1,134 +1,12 @@
/*
- * Project-wide globals
+ * Common project globals
*/
+import {moduloPositive, intToOrdinal, getNumTrailingZeros} from './util';
import {RBTree} from './rbtree';
export const DEBUG = true;
-// ========== For device detection ==========
-
-export type Breakpoint = 'sm' | 'md' | 'lg';
-
-export function getBreakpoint(): Breakpoint {
- const w = window.innerWidth;
- if (w < 768){
- return 'sm';
- } else if (w < 1024){
- return 'md';
- } else {
- return 'lg';
- }
-}
-
-// Returns true for a touch device
-export function onTouchDevice(){
- return window.matchMedia('(pointer: coarse)').matches;
-}
-
-// For detecting writing mode
- // Used with ResizeObserver callbacks, to determine which resized dimensions are width and height
-export let WRITING_MODE_HORZ = true;
-
-if ('writing-mode' in window.getComputedStyle(document.body)){ // Can be null when testing
- const bodyStyles = window.getComputedStyle(document.body);
- if ('writing-mode' in bodyStyles){
- WRITING_MODE_HORZ = (bodyStyles['writing-mode'] as string).startsWith('horizontal');
- }
-}
-
-// ========== For handler throttling ==========
-
-// For creating throttled version of handler function
-export function makeThrottled(hdlr: (...args: any[]) => void, delay: number){
- let timeout = 0;
- return (...args: any[]) => {
- clearTimeout(timeout);
- timeout = window.setTimeout(async () => hdlr(...args), delay);
- };
-}
-// Like makeThrottled(), but accepts an async function
-export function makeThrottledAsync(hdlr: (...args: any[]) => Promise<void>, delay: number){
- let timeout = 0;
- return async (...args: any[]) => {
- clearTimeout(timeout);
- timeout = window.setTimeout(async () => await hdlr(...args), delay);
- };
-}
-// Like makeThrottled(), but, for runs of fast handler calls, calls it at spaced intervals, and at the start/end
-export function makeThrottledSpaced(hdlr: (...args: any[]) => void, delay: number){
- let lastHdlrTime = 0; // Used for throttling
- let endHdlr = 0; // Used to call handler after ending a run of calls
- return (...args: any[]) => {
- clearTimeout(endHdlr);
- const currentTime = new Date().getTime();
- if (currentTime - lastHdlrTime > delay){
- lastHdlrTime = currentTime;
- hdlr(...args);
- lastHdlrTime = new Date().getTime();
- } else {
- endHdlr = window.setTimeout(async () => {
- endHdlr = 0;
- hdlr(...args);
- lastHdlrTime = new Date().getTime();
- }, delay);
- }
- };
-}
-
-// ========== General utility functions ==========
-
-// Similar to %, but for negative LHS, return a positive offset from a lower RHS multiple
-export function moduloPositive(x: number, y: number){
- return x - Math.floor(x / y) * y;
-}
-
-// For positive int n, converts 1 to '1st', 2 to '2nd', etc
-export function intToOrdinal(n: number){
- if (n == 1 || n > 20 && n % 10 == 1){
- return `${n == 1 ? '' : Math.floor(n / 10)}1st`;
- } else if (n == 2 || n > 20 && n % 10 == 2){
- return `${n == 2 ? '' : Math.floor(n / 10)}2nd`;
- } else if (n == 3 || n > 20 && n % 10 == 3){
- return `${n == 3 ? '' : Math.floor(n / 10)}3rd`;
- } else {
- return String(n) + 'th';
- }
-}
-
-// For positive int n, returns number of trailing zeros in decimal representation
-export function getNumTrailingZeros(n: number): number {
- let pow10 = 10;
- while (pow10 != Infinity){
- if (n % pow10 != 0){
- return Math.log10(pow10 / 10);
- }
- pow10 *= 10;
- }
- throw new Error('Exceeded floating point precision');
-}
-
-// Removes a class from an element, triggers reflow, then adds the class
-export function animateWithClass(el: HTMLElement, className: string){
- el.classList.remove(className);
- el.offsetWidth; // Triggers reflow
- el.classList.add(className);
-}
-
-// Used to async-await for until after a timeout
-export async function timeout(ms: number){
- return new Promise(resolve => setTimeout(resolve, ms))
-}
-
-// For estimating text width (via https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript)
-const _getTextWidthCanvas = document.createElement('canvas');
-export function getTextWidth(text: string, font: string): number {
- const context = _getTextWidthCanvas.getContext('2d')!;
- context.font = font;
- const metrics = context.measureText(text);
- return metrics.width;
-}
-
// ========== For calendar conversion (mostly copied from backend/hist_data/cal.py) ==========
export function gregorianToJdn(year: number, month: number, day: number): number {
@@ -430,7 +308,7 @@ export function cmpHistEvent(event: HistEvent, event2: HistEvent){
return cmp != 0 ? cmp : event.id - event2.id;
}
-// ========== For date display ==========
+// ========== For [event] date display ==========
export function dateToDisplayStr(date: HistDate){
if (date.year <= -1e4){ // N.NNN billion/million/thousand years ago
@@ -515,7 +393,6 @@ export function boundedDateToStr(start: HistDate, end: HistDate | null) : string
return `${startStr} to ${endStr}`;
}
-
// ========== For server requests ==========
const SERVER_DATA_URL = (new URL(window.location.href)).origin + '/data/'
@@ -613,7 +490,7 @@ export function jsonToImgInfo(json: ImgInfoJson | null): ImgInfo | null {
return json == null ? null : new ImgInfo(json.url, json.license, json.artist, json.credit);
}
-// ========== For dates in a timeline ==========
+// ========== For timeline dates/data ==========
export const MIN_DATE = new YearDate(-13.8e9);
export const MAX_DATE = new CalDate(2030, 1, 1);
@@ -825,8 +702,6 @@ export function dateToScaleDate(date: HistDate, scale: number): HistDate {
}
}
-// ========== For sending timeline-bound data to BaseLine ==========
-
export class TimelineState {
id: number;
startDate: HistDate;
diff --git a/src/store.ts b/src/store.ts
index d05b49f..5bbf584 100644
--- a/src/store.ts
+++ b/src/store.ts
@@ -3,8 +3,8 @@
*/
import {defineStore} from 'pinia';
+import {Breakpoint, getBreakpoint, onTouchDevice} from './util';
import {HistDate, CalDate} from './lib';
-import {getBreakpoint, Breakpoint, onTouchDevice} from './lib';
// ========== For store state ==========
diff --git a/src/util.ts b/src/util.ts
new file mode 100644
index 0000000..bb0d162
--- /dev/null
+++ b/src/util.ts
@@ -0,0 +1,126 @@
+/*
+ * General utility functions
+ */
+
+// ========== For device detection ==========
+
+export type Breakpoint = 'sm' | 'md' | 'lg';
+
+export function getBreakpoint(): Breakpoint {
+ const w = window.innerWidth;
+ if (w < 768){
+ return 'sm';
+ } else if (w < 1024){
+ return 'md';
+ } else {
+ return 'lg';
+ }
+}
+
+// Returns true for a touch device
+export function onTouchDevice(){
+ return window.matchMedia('(pointer: coarse)').matches;
+}
+
+// For detecting writing mode
+ // Used with ResizeObserver callbacks, to determine which resized dimensions are width and height
+export let WRITING_MODE_HORZ = true;
+
+if ('writing-mode' in window.getComputedStyle(document.body)){ // Can be null when testing
+ const bodyStyles = window.getComputedStyle(document.body);
+ if ('writing-mode' in bodyStyles){
+ WRITING_MODE_HORZ = (bodyStyles['writing-mode'] as string).startsWith('horizontal');
+ }
+}
+
+// ========== For handler throttling ==========
+
+// For creating throttled version of handler function
+export function makeThrottled(hdlr: (...args: any[]) => void, delay: number){
+ let timeout = 0;
+ return (...args: any[]) => {
+ clearTimeout(timeout);
+ timeout = window.setTimeout(async () => hdlr(...args), delay);
+ };
+}
+// Like makeThrottled(), but accepts an async function
+export function makeThrottledAsync(hdlr: (...args: any[]) => Promise<void>, delay: number){
+ let timeout = 0;
+ return async (...args: any[]) => {
+ clearTimeout(timeout);
+ timeout = window.setTimeout(async () => await hdlr(...args), delay);
+ };
+}
+// Like makeThrottled(), but, for runs of fast handler calls, calls it at spaced intervals, and at the start/end
+export function makeThrottledSpaced(hdlr: (...args: any[]) => void, delay: number){
+ let lastHdlrTime = 0; // Used for throttling
+ let endHdlr = 0; // Used to call handler after ending a run of calls
+ return (...args: any[]) => {
+ clearTimeout(endHdlr);
+ const currentTime = new Date().getTime();
+ if (currentTime - lastHdlrTime > delay){
+ lastHdlrTime = currentTime;
+ hdlr(...args);
+ lastHdlrTime = new Date().getTime();
+ } else {
+ endHdlr = window.setTimeout(async () => {
+ endHdlr = 0;
+ hdlr(...args);
+ lastHdlrTime = new Date().getTime();
+ }, delay);
+ }
+ };
+}
+
+// ========== Other ==========
+
+// Similar to %, but for negative LHS, return a positive offset from a lower RHS multiple
+export function moduloPositive(x: number, y: number){
+ return x - Math.floor(x / y) * y;
+}
+
+// For positive int n, converts 1 to '1st', 2 to '2nd', etc
+export function intToOrdinal(n: number){
+ if (n == 1 || n > 20 && n % 10 == 1){
+ return `${n == 1 ? '' : Math.floor(n / 10)}1st`;
+ } else if (n == 2 || n > 20 && n % 10 == 2){
+ return `${n == 2 ? '' : Math.floor(n / 10)}2nd`;
+ } else if (n == 3 || n > 20 && n % 10 == 3){
+ return `${n == 3 ? '' : Math.floor(n / 10)}3rd`;
+ } else {
+ return String(n) + 'th';
+ }
+}
+
+// For positive int n, returns number of trailing zeros in decimal representation
+export function getNumTrailingZeros(n: number): number {
+ let pow10 = 10;
+ while (pow10 != Infinity){
+ if (n % pow10 != 0){
+ return Math.log10(pow10 / 10);
+ }
+ pow10 *= 10;
+ }
+ throw new Error('Exceeded floating point precision');
+}
+
+// Removes a class from an element, triggers reflow, then adds the class
+export function animateWithClass(el: HTMLElement, className: string){
+ el.classList.remove(className);
+ el.offsetWidth; // Triggers reflow
+ el.classList.add(className);
+}
+
+// Used to async-await for until after a timeout
+export async function timeout(ms: number){
+ return new Promise(resolve => setTimeout(resolve, ms))
+}
+
+// For estimating text width (via https://stackoverflow.com/questions/118241/calculate-text-width-with-javascript)
+const _getTextWidthCanvas = document.createElement('canvas');
+export function getTextWidth(text: string, font: string): number {
+ const context = _getTextWidthCanvas.getContext('2d')!;
+ context.font = font;
+ const metrics = context.measureText(text);
+ return metrics.width;
+}
diff --git a/tests/lib.test.ts b/tests/lib.test.ts
index 407d1d1..4810c55 100644
--- a/tests/lib.test.ts
+++ b/tests/lib.test.ts
@@ -1,12 +1,14 @@
+import {moduloPositive, intToOrdinal, getNumTrailingZeros} from '/src/util.ts';
import {
- moduloPositive, intToOrdinal, getNumTrailingZeros,
- gregorianToJdn, julianToJdn, jdnToGregorian, jdnToJulian, gregorianToJulian, julianToGregorian, getDaysInMonth,
- YearDate, CalDate, dateToDisplayStr, boundedDateToStr, HistEvent,
+ gregorianToJdn, julianToJdn, jdnToGregorian, jdnToJulian, julianToGregorian, gregorianToJulian, getDaysInMonth,
+ YearDate, CalDate,
+ HistEvent,
+ dateToDisplayStr, boundedDateToStr,
queryServer, jsonToHistDate, jsonToHistEvent,
DAY_SCALE, MONTH_SCALE, stepDate, inDateScale, getScaleRatio, getUnitDiff,
- getEventPrecision, dateToUnit, dateToScaleDate,
+ getEventPrecision, dateToUnit, dateToScaleDate,
DateRangeTree,
-} from '/src/lib.ts'
+} from '/src/lib.ts';
// ========== General utility functions ==========