aboutsummaryrefslogtreecommitdiff
path: root/src/components/TimeLine.vue
diff options
context:
space:
mode:
authorTerry Truong <terry06890@gmail.com>2023-01-06 23:58:25 +1100
committerTerry Truong <terry06890@gmail.com>2023-01-06 23:58:25 +1100
commit3a66879b889dce85d7498e216980a2c08288b36f (patch)
treeb6967865e64bf3d61f80feea00b6a180553331bb /src/components/TimeLine.vue
parentd5b2c3d55b614914331525801ffb38ce824a5e8f (diff)
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.
Diffstat (limited to 'src/components/TimeLine.vue')
-rw-r--r--src/components/TimeLine.vue47
1 files changed, 41 insertions, 6 deletions
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));