aboutsummaryrefslogtreecommitdiff
path: root/src/components/AncestryBar.vue
diff options
context:
space:
mode:
authorTerry Truong <terry06890@gmail.com>2022-09-13 19:59:06 +1000
committerTerry Truong <terry06890@gmail.com>2022-09-13 20:00:17 +1000
commit23b5cc80ba02936659564dd03b173d3214ce5978 (patch)
treecdf6a183d1a0bfcb45a924585b764c723dd67b55 /src/components/AncestryBar.vue
parente382d4173c990a49a9ef3db1b3681763a3e2e908 (diff)
Use Vue Composition API and ESLint
Diffstat (limited to 'src/components/AncestryBar.vue')
-rw-r--r--src/components/AncestryBar.vue150
1 files changed, 72 insertions, 78 deletions
diff --git a/src/components/AncestryBar.vue b/src/components/AncestryBar.vue
index 3cfd116..1b4ee81 100644
--- a/src/components/AncestryBar.vue
+++ b/src/components/AncestryBar.vue
@@ -1,92 +1,86 @@
<template>
-<div :style="styles" @wheel.stop="onWheelEvt">
+<div :style="styles" @wheel.stop="onWheelEvt" ref="rootRef">
<tol-tile v-for="(node, idx) in dummyNodes" :key="node.name" class="shrink-0"
:layoutNode="node" :tolMap="tolMap" :nonAbsPos="true" :lytOpts="lytOpts" :uiOpts="uiOpts"
@leaf-click="onTileClick(nodes[idx])" @info-click="onInfoIconClick"/>
</div>
</template>
-<script lang="ts">
-import {defineComponent, PropType} from 'vue';
+<script setup lang="ts">
+import {ref, computed, watch, onMounted, nextTick, PropType} from 'vue';
import TolTile from './TolTile.vue';
import {TolMap} from '../tol';
import {LayoutNode, LayoutOptions} from '../layout';
import {UiOptions} from '../lib';
-export default defineComponent({
- props: {
- nodes: {type: Array as PropType<LayoutNode[]>, required: true},
- vert: {type: Boolean, default: false},
- breadth: {type: Number, required: true},
- // Other
- lytOpts: {type: Object as PropType<LayoutOptions>, required: true},
- uiOpts: {type: Object as PropType<UiOptions>, required: true},
- tolMap: {type: Object as PropType<TolMap>, required: true},
- },
- computed: {
- imgSz(){
- return this.breadth - this.lytOpts.tileSpacing - this.uiOpts.scrollGap;
- // Intentionally omitting extra tileSpacing, to allow for scrollGap with less image shrinkage
- },
- dummyNodes(){ // Childless versions of 'nodes' used to parameterise <tol-tile>s
- return this.nodes.map(n => {
- let newNode = new LayoutNode(n.name, []);
- newNode.dims = [this.imgSz, this.imgSz];
- return newNode;
- });
- },
- styles(): Record<string,string> {
- return {
- // For child layout
- display: 'flex',
- flexDirection: this.vert ? 'column' : 'row',
- alignItems: 'center',
- gap: this.lytOpts.tileSpacing + 'px',
- padding: this.lytOpts.tileSpacing + 'px',
- overflowX: this.vert ? 'hidden' : 'auto',
- overflowY: this.vert ? 'auto' : 'hidden',
- // Other
- backgroundColor: this.uiOpts.ancestryBarBgColor,
- boxShadow: this.uiOpts.shadowNormal,
- };
- },
- },
- methods: {
- // Click events
- onTileClick(node: LayoutNode){
- this.$emit('ancestor-click', node);
- },
- onInfoIconClick(data: string){
- this.$emit('info-click', data);
- },
- // For converting vertical scrolling to horizontal
- onWheelEvt(evt: WheelEvent){
- if (!this.vert && Math.abs(evt.deltaX) < Math.abs(evt.deltaY)){
- this.$el.scrollLeft -= (evt.deltaY > 0 ? -30 : 30);
- }
- },
- // Other
- scrollToEnd(){
- if (this.vert){
- this.$el.scrollTop = this.$el.scrollHeight;
- } else {
- this.$el.scrollLeft = this.$el.scrollWidth;
- }
- },
- },
- watch: {
- // For scrolling-to-end upon node/screen changes
- nodes(){
- this.$nextTick(() => this.scrollToEnd());
- },
- vert(){
- this.$nextTick(() => this.scrollToEnd());
- },
- },
- mounted(){
- this.scrollToEnd();
- },
- components: {TolTile, },
- emits: ['ancestor-click', 'info-click', ],
+// Refs
+const rootRef = ref(null as HTMLDivElement | null);
+
+// Props + events
+const props = defineProps({
+ nodes: {type: Array as PropType<LayoutNode[]>, required: true},
+ vert: {type: Boolean, default: false},
+ breadth: {type: Number, required: true},
+ //
+ lytOpts: {type: Object as PropType<LayoutOptions>, required: true},
+ uiOpts: {type: Object as PropType<UiOptions>, required: true},
+ tolMap: {type: Object as PropType<TolMap>, required: true},
});
+const emit = defineEmits(['ancestor-click', 'info-click']);
+
+// Computed prop data for display
+const imgSz = computed(() =>
+ props.breadth - props.lytOpts.tileSpacing - props.uiOpts.scrollGap
+ // Intentionally omitting extra tileSpacing, to allow for scrollGap with less image shrinkage
+);
+const dummyNodes = computed(() => props.nodes.map(n => {
+ let newNode = new LayoutNode(n.name, []);
+ newNode.dims = [imgSz.value, imgSz.value];
+ return newNode;
+}));
+
+// Click handling
+function onTileClick(node: LayoutNode){
+ emit('ancestor-click', node);
+}
+function onInfoIconClick(data: string){
+ emit('info-click', data);
+}
+
+// Scroll handling
+function onWheelEvt(evt: WheelEvent){ // For converting vertical scrolling to horizontal
+ if (!props.vert && Math.abs(evt.deltaX) < Math.abs(evt.deltaY)){
+ rootRef.value!.scrollLeft -= (evt.deltaY > 0 ? -30 : 30);
+ }
+}
+function scrollToEnd(){
+ let el = rootRef.value!;
+ if (props.vert){
+ el.scrollTop = el.scrollHeight;
+ } else {
+ el.scrollLeft = el.scrollWidth;
+ }
+}
+watch(props.nodes, () => {
+ nextTick(() => scrollToEnd());
+});
+watch(() => props.vert, () => {
+ nextTick(() => scrollToEnd());
+});
+onMounted(() => scrollToEnd());
+
+// Styles
+const styles = computed(() => ({
+ // For child layout
+ display: 'flex',
+ flexDirection: props.vert ? 'column' : 'row',
+ alignItems: 'center',
+ gap: props.lytOpts.tileSpacing + 'px',
+ padding: props.lytOpts.tileSpacing + 'px',
+ overflowX: props.vert ? 'hidden' : 'auto',
+ overflowY: props.vert ? 'auto' : 'hidden',
+ // Other
+ backgroundColor: props.uiOpts.ancestryBarBgColor,
+ boxShadow: props.uiOpts.shadowNormal,
+}));
</script>