diff options
| -rw-r--r-- | src/components/BaseLine.vue | 40 | ||||
| -rw-r--r-- | src/components/TimeLine.vue | 7 | ||||
| -rw-r--r-- | src/lib.ts | 1 |
3 files changed, 35 insertions, 13 deletions
diff --git a/src/components/BaseLine.vue b/src/components/BaseLine.vue index 84a3846..6f2dbc9 100644 --- a/src/components/BaseLine.vue +++ b/src/components/BaseLine.vue @@ -1,11 +1,11 @@ <template> -<div class="bg-stone-900 text-stone-50 flex relative" :class="{'flex-col': vert}"> +<div class="bg-stone-900 text-stone-50 flex relative" :class="{'flex-col': vert}" ref="rootRef"> <div v-for="p in periods" :key="p.label" :style="periodStyles(p)"> <div :style="labelStyles">{{p.label}}</div> </div> <TransitionGroup name="fade"> <div v-for="d in timelineData" :key="d.id" - class="absolute bg-yellow-200/50" :style="spanStyles(d)"> + class="absolute bg-yellow-200/30" :style="spanStyles(d)"> {{d.id}} </div> </TransitionGroup> @@ -13,9 +13,12 @@ </template> <script setup lang="ts"> -import {ref, computed} from 'vue'; +import {ref, computed, onMounted} from 'vue'; import {MIN_DATE, MAX_DATE} from '../lib'; +// Refs +const rootRef = ref(null as HTMLElement | null); + // Props const props = defineProps({ vert: {type: Boolean, required: true}, @@ -29,6 +32,21 @@ const periods = ref([ {label: 'Three', len: 1}, ]); +// For size tracking +const width = ref(0); +const height = ref(0); +const WRITING_MODE_HORZ = window.getComputedStyle(document.body)['writing-mode'].startsWith('horizontal'); +const resizeObserver = new ResizeObserver((entries) => { + for (const entry of entries){ + if (entry.contentBoxSize){ + const boxSize = Array.isArray(entry.contentBoxSize) ? entry.contentBoxSize[0] : entry.contentBoxSize; + width.value = WRITING_MODE_HORZ ? boxSize.inlineSize : boxSize.blockSize; + height.value = WRITING_MODE_HORZ ? boxSize.blockSize : boxSize.inlineSize; + } + } +}); +onMounted(() => resizeObserver.observe(rootRef.value as HTMLElement)); + // Styles function periodStyles(period){ return { @@ -44,21 +62,25 @@ const labelStyles: Record<string,string> = computed(() => ({ })); function spanStyles(d){ let styles: Record<string,string>; - let beforeFrac = Math.max(0, (d.start - MIN_DATE) / (MAX_DATE - MIN_DATE)); // Clip at zero due to end-padding - let lenFrac = Math.min(1 - beforeFrac, (d.end - d.start) / (MAX_DATE - MIN_DATE)); + let availLen = props.vert ? height.value : width.value; + let startFrac = (d.start - MIN_DATE) / (MAX_DATE - MIN_DATE); + let lenFrac = (d.end - d.start) / (MAX_DATE - MIN_DATE); + let startPx = Math.max(0, availLen * startFrac); // Prevent negatives due to end-padding + let lenPx = Math.min(availLen - startPx, availLen * lenFrac); + lenPx = Math.max(1, lenPx); if (props.vert){ styles = { - top: beforeFrac * 100 + '%', + top: startPx + 'px', left: 0, - height: lenFrac * 100 + '%', + height: lenPx + 'px', width: '100%', } } else { styles = { top: 0, - left: beforeFrac * 100 + '%', + left: startPx + 'px', height: '100%', - width: lenFrac * 100 + '%', + width: lenPx + 'px', } } return { diff --git a/src/components/TimeLine.vue b/src/components/TimeLine.vue index 1c7dee6..12dd7bc 100644 --- a/src/components/TimeLine.vue +++ b/src/components/TimeLine.vue @@ -24,7 +24,7 @@ </text> </svg> <!-- Icons --> - <icon-button :size="30" class="absolute bottom-2 right-2 text-stone-50 bg-yellow-600" + <icon-button :size="30" class="absolute top-2 right-2 text-stone-50 bg-yellow-600" @click="onClose" title="Remove timeline"> <minus-icon/> </icon-button> @@ -33,7 +33,7 @@ <script setup lang="ts"> import {ref, onMounted, computed, watch} from 'vue'; -import {MIN_DATE, MAX_DATE} from '../lib'; +import {MIN_DATE, MAX_DATE, SCALES} from '../lib'; // Components import IconButton from './IconButton.vue'; // Icons @@ -78,7 +78,6 @@ onMounted(() => resizeObserver.observe(rootRef.value as HTMLElement)); // Vars const startDate = ref(props.initialStart); // Lowest date on displayed timeline const endDate = ref(props.initialEnd); -const SCALES = [200, 50, 10, 1, 0.2]; // The timeline get divided into units of SCALES[0], then SCALES[1], etc let scaleIdx = 0; // Index of current scale in SCALES const SCROLL_SHIFT_CHG = 0.2; // Proportion of timeline length to shift by upon scroll const ZOOM_RATIO = 1.5; // When zooming out, the timeline length gets multiplied by this ratio @@ -228,7 +227,7 @@ function zoomTimeline(frac: number){ scaleIdx++; } } else { - if (newDateLen / tickDiff < MIN_LAST_TICKS){ + if (availLen.value / tickDiff < MIN_LAST_TICKS){ console.log('INFO: Reached zoom in limit'); return; } @@ -4,3 +4,4 @@ export const MIN_DATE = -1000; export const MAX_DATE = 1000; +export const SCALES = [200, 50, 10, 1, 0.2]; // Timeline gets divided into units of SCALES[0], then SCALES[1], etc |
