From 3a66879b889dce85d7498e216980a2c08288b36f Mon Sep 17 00:00:00 2001
From: Terry Truong <terry06890@gmail.com>
Date: Fri, 6 Jan 2023 23:58:25 +1100
Subject: Keep track of a 'current' timeline

Make timeline addition and searching use the current timeline.
Add keyboard controls for timeline panning, zooming, switching, opening, and closing.
Fix zoomTimeline() bug when not centering zoom on pointer.
---
 src/components/TimeLine.vue | 47 +++++++++++++++++++++++++++++++++++++++------
 1 file changed, 41 insertions(+), 6 deletions(-)

(limited to 'src/components/TimeLine.vue')

diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue
index 1583aef..d6bb36a 100644
--- a/src/components/TimeLine.vue
+++ b/src/components/TimeLine.vue
@@ -58,7 +58,7 @@
 		</div>
 	</div>
 	<!-- Timeline position label -->
-	<div class="absolute top-2 left-2 z-20 text-lg text-stone-50">
+	<div class="absolute top-2 left-2 z-20 text-lg" :class="[current ? 'text-yellow-300' : 'text-stone-50']">
 		{{timelinePosStr}}
 	</div>
 	<!-- Buttons -->
@@ -71,7 +71,7 @@
 </template>
 
 <script setup lang="ts">
-import {ref, onMounted, computed, watch, watchEffect, PropType, Ref, shallowRef, ShallowRef} from 'vue';
+import {ref, onMounted, onUnmounted, computed, watch, watchEffect, PropType, Ref, shallowRef, ShallowRef} from 'vue';
 // Components
 import IconButton from './IconButton.vue';
 // Icons
@@ -98,6 +98,7 @@ const props = defineProps({
 	initialState: {type: Object as PropType<TimelineState>, required: true},
 	eventTree: {type: Object as PropType<RBTree<HistEvent>>, required: true},
 	unitCountMaps: {type: Object as PropType<Map<number, number>[]>, required: true},
+	current: {type: Boolean, required: true},
 	searchTarget: {type: Object as PropType<[null | HistEvent, boolean]>, required: true},
 });
 const emit = defineEmits(['close', 'state-chg', 'event-display', 'info-click']);
@@ -820,7 +821,7 @@ function panTimeline(scrollRatio: number){
 	startOffset.value = newStartOffset;
 	endOffset.value = newEndOffset;
 }
-function zoomTimeline(zoomRatio: number){
+function zoomTimeline(zoomRatio: number, ignorePointer=false){
 	if (zoomRatio > 1
 			&& startDate.value.equals(MIN_DATE, scale.value)
 			&& endDate.value.equals(MAX_DATE, scale.value)){
@@ -833,9 +834,9 @@ function zoomTimeline(zoomRatio: number){
 	let startChg: number;
 	let endChg: number;
 	let ptrOffset = props.vert ? pointerY : pointerX;
-	if (ptrOffset == null){
+	if (ptrOffset == null || ignorePointer){
 		let unitChg = newNumUnits - numUnits;
-		startChg = unitChg / 2;
+		startChg = -unitChg / 2;
 		endChg = unitChg / 2;
 	} else { // Pointer-centered zoom
 		// Get element-relative ptrOffset
@@ -1122,7 +1123,7 @@ function onStateChg(){
 		ID, startDate.value, endDate.value, startOffset.value, endOffset.value, scaleIdx.value
 	));
 }
-watch(firstDate, onStateChg);
+watch(startDate, onStateChg);
 
 // For jumping to search result
 const searchEvent = ref(null as null | HistEvent); // Holds most recent search result
@@ -1163,6 +1164,40 @@ watch(() => props.searchTarget, () => {
 	searchEvent.value = event;
 });
 
+// For keyboard shortcuts
+function onKeyDown(evt: KeyboardEvent){
+	if (!props.current || store.disableShortcuts){
+		return;
+	}
+	if (evt.key == 'ArrowUp'){
+		if (evt.shiftKey){
+			zoomTimeline(1/store.zoomRatio, true);
+		} else if (props.vert){
+			panTimeline(-store.scrollRatio);
+		}
+	} else if (evt.key == 'ArrowDown'){
+		if (evt.shiftKey){
+			zoomTimeline(store.zoomRatio, true);
+		} else if (props.vert){
+			panTimeline(store.scrollRatio);
+		}
+	} else if (evt.key == 'ArrowLeft'){
+		if (!props.vert){
+			panTimeline(-store.scrollRatio);
+		}
+	} else if (evt.key == 'ArrowRight'){
+		if (!props.vert){
+			panTimeline(store.scrollRatio);
+		}
+	}
+}
+onMounted(() => {
+	window.addEventListener('keydown', onKeyDown);
+});
+onUnmounted(() => {
+	window.removeEventListener('keydown', onKeyDown);
+});
+
 // For skipping transitions on startup (and on horz/vert swap)
 const skipTransition = ref(true);
 onMounted(() => setTimeout(() => {skipTransition.value = false}, 100));
-- 
cgit v1.2.3

