diff options
| author | Terry Truong <terry06890@gmail.com> | 2022-09-13 19:59:06 +1000 |
|---|---|---|
| committer | Terry Truong <terry06890@gmail.com> | 2022-09-13 20:00:17 +1000 |
| commit | 23b5cc80ba02936659564dd03b173d3214ce5978 (patch) | |
| tree | cdf6a183d1a0bfcb45a924585b764c723dd67b55 /src/components/AncestryBar.vue | |
| parent | e382d4173c990a49a9ef3db1b3681763a3e2e908 (diff) | |
Use Vue Composition API and ESLint
Diffstat (limited to 'src/components/AncestryBar.vue')
| -rw-r--r-- | src/components/AncestryBar.vue | 150 |
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> |
