From 20d69469a4c80a196de23625d0420487b0ed04a6 Mon Sep 17 00:00:00 2001 From: Terry Truong Date: Thu, 29 Dec 2022 16:17:39 +1100 Subject: Show event-count data on timeline Backend: Send event-count data to client in EventResponse instance Fix certain usages of gregorian calendar instead of julian Move HistDate, SCALES, etc, into cal.py Frontend: Make App update a unitCountMaps object using event-count data from server Make TimeLine show visual indication of unit counts Add showEventCounts option to store Update unit tests --- src/components/TimeLine.vue | 85 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 64 insertions(+), 21 deletions(-) (limited to 'src/components/TimeLine.vue') diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue index b1607ef..1050c62 100644 --- a/src/components/TimeLine.vue +++ b/src/components/TimeLine.vue @@ -4,7 +4,11 @@ @pointercancel.prevent="onPointerUp" @pointerout.prevent="onPointerUp" @pointerleave.prevent="onPointerUp" @wheel.exact.prevent="onWheel" @wheel.shift.exact.prevent="onShiftWheel" ref="rootRef"> - +
+ + @@ -42,7 +46,7 @@ -
+
@@ -51,7 +55,7 @@
- @@ -67,7 +71,8 @@ import IconButton from './IconButton.vue'; import CloseIcon from './icon/CloseIcon.vue'; // Other import {WRITING_MODE_HORZ, MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES, MIN_CAL_YEAR, - getDaysInMonth, HistDate, CalDate, stepDate, getScaleRatio, getNumSubUnits, getUnitDiff, getEventPrecision, + getDaysInMonth, HistDate, CalDate, stepDate, getScaleRatio, getNumSubUnits, getUnitDiff, + getEventPrecision, dateToUnit, moduloPositive, TimelineState, HistEvent, getImagePath} from '../lib'; import {useStore} from '../store'; import {RBTree} from '../rbtree'; @@ -84,6 +89,7 @@ const props = defineProps({ closeable: {type: Boolean, default: true}, initialState: {type: Object as PropType, required: true}, eventTree: {type: Object as PropType>, required: true}, + unitCountMaps: {type: Object as PropType[]>, required: true}, }); const emit = defineEmits(['remove', 'state-chg', 'event-req', 'event-display']); @@ -349,30 +355,24 @@ const ticks = computed((): Tick[] => { ticks = [...ticksBefore, ...ticks, ...ticksAfter]; return ticks; }); -const firstDate = computed((): HistDate => { // Date of first visible tick - if (ticks.value.length == 0){ - return startDate.value; - } - return ticks.value.find((tick: Tick) => tick.offset > 0)!.date; -}); -const firstOffset = computed((): number => { // Offset of first visible tick - if (ticks.value.length == 0){ - return startOffset.value; - } - return ticks.value.find((tick: Tick) => tick.offset > 0)!.offset; +const firstIdx = computed((): number => { // Index of first visible tick + return ticks.value.findIndex((tick: Tick) => tick.offset >= 0); }); -const lastDate = computed((): HistDate => { +const firstDate = computed(() => // Date of first visible tick + firstIdx.value < 0 ? startDate.value : ticks.value[firstIdx.value]!.date); +const firstOffset = computed(() => // Offset of first visible tick + firstIdx.value < 0 ? startOffset.value : ticks.value[firstIdx.value]!.offset); +const lastIdx = computed((): number => { let numUnits = getNumDisplayUnits(); - let date = endDate.value; for (let i = ticks.value.length - 1; i >= 0; i--){ let tick = ticks.value[i]; - if (tick.offset < numUnits){ - date = tick.date; - break; + if (tick.offset <= numUnits){ + return i; } } - return date; + return -1; }); +const lastDate = computed(() => lastIdx.value < 0 ? endDate.value : ticks.value[lastIdx.value]!.date); // For displayed events function dateToOffset(date: HistDate){ @@ -614,6 +614,31 @@ watchEffect(() => { // Used instead of computed() in order to access old values eventLines.value = newEventLines; }); +// For event-count indicators +const tickToCount = computed((): Map => { + let tickToCount: Map = new Map(); // Maps tick index to event count + let unitToTickIdx: [number, number][] = []; // Holds tick units with their tick indexes in tickToCount + for (let tickIdx = firstIdx.value; tickIdx < lastIdx.value; tickIdx++){ + tickToCount.set(tickIdx, 0); + let unit = dateToUnit(ticks.value[tickIdx].date, minorScale.value); + unitToTickIdx.push([unit, tickIdx]); + } + // Accumulate counts for ticks + const firstUnit = dateToUnit(firstDate.value, minorScale.value); + const lastUnit = dateToUnit(lastDate.value, minorScale.value); + for (let [unit, count] of props.unitCountMaps[minorScaleIdx.value].entries()){ + if (unit >= firstUnit && unit < lastUnit){ + let i = 0; + while (i + 1 < unitToTickIdx.length && unitToTickIdx[i + 1][0] <= unit){ + i += 1; + } + const tickIdx = unitToTickIdx[i][1]; + tickToCount.set(tickIdx, tickToCount.get(tickIdx)! + count); + } + } + return tickToCount; +}); + // For panning/zooming function panTimeline(scrollRatio: number){ let numUnits = getNumDisplayUnits(); @@ -1088,4 +1113,22 @@ function eventLineStyles(eventId: number){ transitionTimingFunction: 'ease-out', }; } +function countDivStyles(tickIdx: number, count: number): Record { + let tick = ticks.value[tickIdx]; + let numMajorUnits = getNumDisplayUnits(); + let pxOffset = tick.offset / numMajorUnits * availLen.value; + let nextPxOffset = ticks.value[tickIdx + 1].offset / numMajorUnits * availLen.value; + let len = nextPxOffset - pxOffset; + let countLevel = Math.min(Math.ceil(Math.log10(count+1)), 4); + let breadth = countLevel * 4 + 4; + return { + top: props.vert ? pxOffset + 'px' : (mainlineOffset.value - breadth / 2) + 'px', + left: props.vert ? (mainlineOffset.value - breadth / 2) + 'px' : pxOffset + 'px', + width: props.vert ? breadth + 'px' : len + 'px', + height: props.vert ? len + 'px' : breadth + 'px', + transitionProperty: 'top, left, width, height', + transitionDuration: store.transitionDuration + 'ms', + transitionTimingFunction: 'linear', + } +} -- cgit v1.2.3