diff options
| -rwxr-xr-x | backend/histplorer.py | 10 | ||||
| -rw-r--r-- | backend/tests/test_histplorer.py | 2 | ||||
| -rw-r--r-- | src/App.vue | 8 | ||||
| -rw-r--r-- | src/components/TimeLine.vue | 7 | ||||
| -rw-r--r-- | src/lib.ts | 74 | ||||
| -rw-r--r-- | src/store.ts | 6 |
6 files changed, 71 insertions, 36 deletions
diff --git a/backend/histplorer.py b/backend/histplorer.py index e5c6c5a..9f9e8ad 100755 --- a/backend/histplorer.py +++ b/backend/histplorer.py @@ -31,6 +31,7 @@ DEFAULT_REQ_EVENTS = 20 MAX_REQ_EXCLS = 100 MAX_REQ_SUGGS = 50 DEFAULT_REQ_SUGGS = 5 +MIN_CAL_YEAR = -4713 # Disallow within-year dates before this year # Classes for objects sent as responses class HistDate: @@ -41,9 +42,9 @@ class HistDate: - 'gcal' may be: - True: Indicates a Gregorian calendar date - False: Means the date should be converted and displayed as a Julian calendar date - - None: 'month' and 'day' are None (used for dates before the Julian period starting year 4713 BCE) + - None: 'month' and 'day' are 1 (used for dates before the Julian period starting year 4713 BCE) """ - def __init__(self, gcal: bool | None, year: int, month: int | None = None, day: int | None = None): + def __init__(self, gcal: bool | None, year: int, month=1, day=1): self.gcal = gcal self.year = year self.month = month @@ -282,7 +283,10 @@ def eventEntryToResults( if n is None: continue elif fmt == 0: - newDates[i] = HistDate(None, n) + if n >= MIN_CAL_YEAR: + newDates[i] = HistDate(True, n, 1, 1) + else: + newDates[i] = HistDate(None, n) elif fmt == 1: newDates[i] = HistDate(False, *jdnToJulian(n)) elif fmt == 2: diff --git a/backend/tests/test_histplorer.py b/backend/tests/test_histplorer.py index 32f1404..6487977 100644 --- a/backend/tests/test_histplorer.py +++ b/backend/tests/test_histplorer.py @@ -77,7 +77,7 @@ class TestHandleReq(unittest.TestCase): def test_events_req(self): response = handleReq(self.dbFile, {'QUERY_STRING': 'type=events&range=-1999.2002-11-1&incl=3&limit=2'}) self.assertEqual(response, [ - Event(5, 'event five', HistDate(None, 2000), None, HistDate(None, 2001), None, + Event(5, 'event five', HistDate(True, 2000, 1, 1), None, HistDate(True, 2001, 1, 1), None, 'event', 50, 51), Event(3, 'event three', HistDate(True, 1990, 10, 10), HistDate(True, 2000, 10, 10), None, None, 'discovery', 30, 0), diff --git a/src/App.vue b/src/App.vue index 4eed256..c3cf6bf 100644 --- a/src/App.vue +++ b/src/App.vue @@ -39,7 +39,7 @@ import PlusIcon from './components/icon/PlusIcon.vue'; import SettingsIcon from './components/icon/SettingsIcon.vue'; import HelpIcon from './components/icon/HelpIcon.vue'; // Other -import {HistDate, TimelineState, HistEvent, queryServer, HistEventJson, jsonToHistEvent, cmpHistEvent, +import {HistDate, YearDate, TimelineState, HistEvent, queryServer, HistEventJson, jsonToHistEvent, cmpHistEvent, timeout} from './lib'; import {useStore} from './store'; import {RBTree, rbtree_shallow_copy} from './rbtree'; @@ -109,7 +109,7 @@ function cmpDatePairs(datePair1: [HistDate, HistDate], datePair2: [HistDate, His } function isExhaustedRange(startDate: HistDate, endDate: HistDate): boolean { // Check if input range is contained in a stored exhausted range - let itr = exhaustedRanges.lowerBound([startDate, new HistDate(1)]); + let itr = exhaustedRanges.lowerBound([startDate, new YearDate()]); let datePair = itr.data(); if (datePair == null){ datePair = itr.prev(); @@ -129,7 +129,7 @@ function isExhaustedRange(startDate: HistDate, endDate: HistDate): boolean { function addExhaustedRange(startDate: HistDate, endDate: HistDate){ let rangesToRemove: HistDate[] = []; // Holds starts of ranges to remove // Find ranges to remove - let itr = exhaustedRanges.lowerBound([startDate, new HistDate(1)]); + let itr = exhaustedRanges.lowerBound([startDate, new YearDate()]); let prevRange = itr.prev(); if (prevRange != null){ // Check for start-overlapping range if (prevRange[1].isEarlier(startDate)){ @@ -153,7 +153,7 @@ function addExhaustedRange(startDate: HistDate, endDate: HistDate){ } // Remove included/overlapping ranges for (let start of rangesToRemove){ - exhaustedRanges.remove([start, new HistDate(1)]); + exhaustedRanges.remove([start, new YearDate()]); } // Add possibly-merged range if (prevRange != null){ diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue index 5aec9b2..8a6ddc4 100644 --- a/src/components/TimeLine.vue +++ b/src/components/TimeLine.vue @@ -63,9 +63,9 @@ import IconButton from './IconButton.vue'; // Icons import MinusIcon from './icon/MinusIcon.vue'; // Other -import {WRITING_MODE_HORZ, MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES, MIN_CAL_DATE, - HistDate, stepDate, inDateScale, getScaleRatio, getUnitDiff, getDaysInMonth, moduloPositive, TimelineState, - HistEvent, getImagePath} from '../lib'; +import {WRITING_MODE_HORZ, MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES, + MIN_CAL_YEAR, HistDate, CalDate, stepDate, inDateScale, getScaleRatio, getUnitDiff, getDaysInMonth, + moduloPositive, TimelineState, HistEvent, getImagePath} from '../lib'; import {useStore} from '../store'; import {RBTree} from '../rbtree'; @@ -132,6 +132,7 @@ const mainlineOffset = computed(() => { // Distance mainline-area line to side o // Timeline data const ID = props.initialState.id as number; +const MIN_CAL_DATE = new CalDate(MIN_CAL_YEAR, 1, 1); const startDate = ref(props.initialState.startDate); // Earliest date to display const endDate = ref(props.initialState.endDate); const startOffset = ref(store.defaultEndTickOffset); // Fraction of a scale unit before startDate to show @@ -75,11 +75,14 @@ export function getDaysInMonth(year: number, month: number){ } // For date representation +export const MIN_CAL_YEAR = -4713; // Year after which months/day scales are usable export class HistDate { + gcal: boolean | null; year: number; month: number; day: number; - constructor(year: number, month=1, day=1){ + constructor(gcal: boolean | null, year: number, month: number, day: number){ + this.gcal = gcal; this.year = year; this.month = month; this.day = day; @@ -93,15 +96,6 @@ export class HistDate { return Math.floor(this.year / scale) == Math.floor(other.year / scale); } } - cmp(other: HistDate, scale=DAY_SCALE){ - if (this.isEarlier(other, scale)){ - return -1; - } else if (!this.equals(other, scale)){ - return 1; - } else { - return 0; - } - } isEarlier(other: HistDate, scale=DAY_SCALE){ const yearlyScale = scale != DAY_SCALE && scale != MONTH_SCALE; const thisYear = yearlyScale ? Math.floor(this.year / scale) : this.year; @@ -116,14 +110,23 @@ export class HistDate { } } } + cmp(other: HistDate, scale=DAY_SCALE){ + if (this.isEarlier(other, scale)){ + return -1; + } else if (!this.equals(other, scale)){ + return 1; + } else { + return 0; + } + } toInt(){ return this.day + this.month * 50 + this.year * 1000; } toString(){ - if (this.isEarlier(MIN_CAL_DATE)){ - return `${this.year}`; - } else { + if (this.gcal != null){ return `${this.year}-${this.month}-${this.day}`; + } else { + return `${this.year}`; } } toDisplayString(){ @@ -161,7 +164,7 @@ export class HistDate { const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; return monthNames[this.month - 1]; } else { - if (this.day == 1){ // TODO: Show instead of just month name when at day-scale? + if (this.day == 1){ return '1st'; } else if (this.day == 2){ return '2nd'; @@ -172,7 +175,7 @@ export class HistDate { } } } - getDayDiff(other: HistDate){ + getDayDiff(other: HistDate){ // Assumes neither date has gcal=null const jdn2 = gregorianToJdn(this.year, this.month, this.day); const jdn1 = gregorianToJdn(other.year, other.month, other.day); return Math.abs(jdn1 - jdn2); @@ -201,15 +204,38 @@ export class HistDate { return yearDiff; } clone(){ - return new HistDate(this.year, this.month, this.day); + return new HistDate(this.gcal, this.year, this.month, this.day); + } +} +export class YearDate extends HistDate { + declare gcal: null; + declare year: number; + declare month: 1; + declare day: 1; + constructor(year=MIN_CAL_YEAR-1){ + if (year >= MIN_CAL_YEAR){ + throw new Error(`Year must be before ${MIN_CAL_YEAR}`); + } + super(null, year, 1, 1); + } +} +export class CalDate extends HistDate { + declare gcal: boolean; + declare year: number; + declare month: number; + declare day: number; + constructor(year: number, month: number, day: number, gcal=true){ + if (year < MIN_CAL_YEAR){ + throw new Error(`Year must not be before ${MIN_CAL_YEAR}`); + } + super(gcal, year, month, day); } } // Timeline parameters const currentDate = new Date(); -export const MIN_DATE = new HistDate(-13.8e9); -export const MAX_DATE = new HistDate(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDate()); -export const MIN_CAL_DATE = new HistDate(-4700, 1, 1); // Date after which months/day scales are usable +export const MIN_DATE = new YearDate(-13.8e9); +export const MAX_DATE = new CalDate(currentDate.getFullYear(), currentDate.getMonth() + 1, currentDate.getDate()); export const MONTH_SCALE = -1; export const DAY_SCALE = -2; export const SCALES = [1e9, 1e8, 1e7, 1e6, 1e5, 1e4, 1e3, 100, 10, 1, MONTH_SCALE, DAY_SCALE]; @@ -412,8 +438,8 @@ export function getImagePath(imgId: number): string { export type HistDateJson = { gcal: boolean | null, year: number, - month: number | null, - day: number | null, + month: number, + day: number, } export type HistEventJson = { id: number, @@ -427,7 +453,11 @@ export type HistEventJson = { pop: number, } export function jsonToHistDate(json: HistDateJson){ - return new HistDate(json.year, json.month == null ? 1 : json.month, json.day == null ? 1 : json.day); + if (json.gcal == null){ + return new YearDate(json.year); + } else { + return new CalDate(json.year, json.month, json.day, json.gcal); + } } export function jsonToHistEvent(json: HistEventJson){ return { diff --git a/src/store.ts b/src/store.ts index 7cf815f..66d73ac 100644 --- a/src/store.ts +++ b/src/store.ts @@ -3,7 +3,7 @@ */ import {defineStore} from 'pinia'; -import {HistDate} from './lib'; +import {CalDate} from './lib'; export const useStore = defineStore('store', { state: () => { @@ -37,8 +37,8 @@ export const useStore = defineStore('store', { zoomRatio: 1.5, // Ratio of timeline expansion upon zooming out dragInertia: 0.1, // Multiplied by final-drag-speed (pixels-per-sec) to get extra scroll distance // - initialStartDate: new HistDate(1900, 1, 1), - initialEndDate: new HistDate(2000, 1, 1), + initialStartDate: new CalDate(1900, 1, 1), + initialEndDate: new CalDate(2000, 1, 1), color, transitionDuration: 300, }; |
