From 220c9bf8b3bee11f3119860bb14bdb5da3f040e9 Mon Sep 17 00:00:00 2001 From: Terry Truong Date: Tue, 18 Oct 2022 23:20:59 +1100 Subject: Add basic grid-like event layout Add lines linking events to timeline Add scrim on event image --- src/App.vue | 2 +- src/components/TimeLine.vue | 92 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 81 insertions(+), 13 deletions(-) diff --git a/src/App.vue b/src/App.vue index 17760b0..1a8608b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -191,7 +191,7 @@ function reduceEvents(){ exhaustedRanges.clear(); } // For getting events from server -const EVENT_REQ_LIMIT = 10; +const EVENT_REQ_LIMIT = 30; let pendingReq = false; // Used to serialise event-req handling async function onEventReq(startDate: HistDate, endDate: HistDate){ while (pendingReq){ diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue index 88ac62d..c581634 100644 --- a/src/components/TimeLine.vue +++ b/src/components/TimeLine.vue @@ -5,8 +5,6 @@ @wheel.exact.prevent="onWheel" @wheel.shift.exact.prevent="onShiftWheel" ref="rootRef"> - - + + {{date}} + +
{{idToEvent.get(id)!.title}}
@@ -55,6 +59,8 @@ import {WRITING_MODE_HORZ, MIN_DATE, MAX_DATE, MONTH_SCALE, DAY_SCALE, SCALES, M import {useStore} from '../store'; import {RBTree} from '../rbtree'; +const SCRIM_GRADIENT = 'linear-gradient(to bottom, rgba(0,0,0,0.4), #0000 40%)'; + // Refs const rootRef: Ref = ref(null); @@ -73,6 +79,7 @@ const emit = defineEmits(['remove', 'state-chg', 'event-req', 'event-display']); const width = ref(0); const height = ref(0); const availLen = computed(() => props.vert ? height.value : width.value); +const availBreadth = computed(() => props.vert ? width.value : height.value); const prevVert = ref(props.vert); // For skipping transitions on horz/vert swap const mounted = ref(false); onMounted(() => { @@ -273,15 +280,42 @@ const idToPos = computed(() => { return new Map(); } let map: Map = new Map(); // Maps visible event IDs to x/y/w/h - let numUnits = getNumVisibleUnits(); - let minorAxisStep = 0; + // Do basic grid-like layout + let spacing = 10, sz = 80, midOffset = [10, 40]; + let posX = spacing, posY = spacing; for (let event of idToEvent.value.values()){ - let unitOffset = getUnitDiff(event.start, startDate.value, scale.value) + startOffset.value; - let posFrac = unitOffset / numUnits; - let posX = props.vert ? minorAxisStep : availLen.value * posFrac; - let posY = props.vert ? availLen.value * posFrac : minorAxisStep; - map.set(event.id, [posX, posY, 100, 100]); - minorAxisStep += 10; + map.set(event.id, [posX, posY, sz, sz]); + if (props.vert){ + posY += sz + spacing; + if (posY + sz + spacing > availLen.value){ // If at end of column + posY = spacing; + posX += sz + spacing; + // Avoid collision with timeline + if (posX <= availBreadth.value / 2 + midOffset[1] && + posX + sz >= availBreadth.value / 2 - midOffset[0]){ + posX = availBreadth.value / 2 + midOffset[1]; + } + // If finished last row + if (posX + sz + spacing > availBreadth.value){ + break; + } + } + } else { + posX += sz + spacing; + if (posX + sz + spacing > availLen.value){ // If at end of row + posX = spacing; + posY += sz + spacing; + // Avoid collision with timeline + if (posY <= availBreadth.value / 2 + midOffset[1] && + posY + sz >= availBreadth.value / 2 - midOffset[0]){ + posY = availBreadth.value / 2 + midOffset[1]; + } + // If finished last column + if (posY + sz + spacing > availBreadth.value){ + break; + } + } + } } // If more events could be displayed, notify parent if (map.size < 3){ @@ -292,6 +326,31 @@ const idToPos = computed(() => { // return map; }); +const eventLines = computed(() => { + let lineCoords: Map = new Map(); + // Maps event ID to x, y, length, and angle + let numUnits = getNumVisibleUnits(); + for (let [id, [eventX, eventY, eventW, eventH]] of idToPos.value){ + let x = eventX + eventW/2; + let y = eventY + eventH/2; + let x2: number; + let y2: number; + let event = idToEvent.value.get(id)!; + let unitOffset = getUnitDiff(event.start, startDate.value, scale.value) + startOffset.value; + let posFrac = unitOffset / numUnits; + if (props.vert){ + x2 = availBreadth.value / 2; + y2 = posFrac * availLen.value; + } else { + x2 = posFrac * availLen.value; + y2 = availBreadth.value / 2; + } + let l = Math.sqrt((x-x2)**2 + (y-y2)**2); + let a = Math.atan2(y2-y, x2-x) * 180 / Math.PI; + lineCoords.set(id, [x, y, l, a]); + } + return lineCoords; +}); // For panning/zooming function panTimeline(scrollRatio: number){ @@ -748,11 +807,20 @@ function eventStyles(eventId: number){ top: y + 'px', width: w + 'px', height: h + 'px', - backgroundImage: `url(${getImagePath(event.imgId)})`, + backgroundImage: `${SCRIM_GRADIENT},url(${getImagePath(event.imgId)})`, backgroundSize: 'cover', transitionProperty: skipTransition.value ? 'none' : 'all', transitionDuration, transitionTimingFunction, }; } +function eventLineStyles(eventId: number){ + const [x, y, l, a] = eventLines.value.get(eventId)!; + return { + transform: `translate(${x}px, ${y}px) rotate(${a}deg) scaleX(${l})`, + transitionProperty: skipTransition.value ? 'none' : 'transform', + transitionDuration, + transitionTimingFunction, + }; +} -- cgit v1.2.3