-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathProgressBar.vue
More file actions
79 lines (64 loc) · 2.17 KB
/
ProgressBar.vue
File metadata and controls
79 lines (64 loc) · 2.17 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
<script setup lang="ts">
import { useNonNullGraphColors } from '@graph/themes/useGraphColors';
import { computed } from 'vue';
import { PROGRESS_DEFAULTS } from './progressTypes';
import type { ProgressBarOptions } from './progressTypes';
const colors = useNonNullGraphColors();
const props = withDefaults(
defineProps<ProgressBarOptions>(),
PROGRESS_DEFAULTS,
);
const range = computed(() => {
const [start, end] = props.range;
return end - start;
});
const progressPercentage = (progressStep: number) => {
// divide by 0 edge case
if (range.value === 0) return 100;
const [start] = props.range;
const curr = progressStep;
const progress = Math.min(Math.max(curr - start, 0), range.value);
return (progress / range.value) * 100;
};
const getStepFromMouseEvent = (event: MouseEvent) => {
const progressBar = event.currentTarget;
if (!(progressBar instanceof HTMLElement))
throw new Error('Invalid target');
const clickPosition = event.offsetX;
const progressBarWidth = progressBar.offsetWidth;
const clickPercentage = clickPosition / progressBarWidth;
const newProgress = props.range[0] + clickPercentage * range.value;
return Math.round(newProgress);
};
const handleClick = (event: MouseEvent) => {
const step = getStepFromMouseEvent(event);
props.onProgressSet?.(step);
};
const handleMouseOver = (event: MouseEvent) => {
const step = getStepFromMouseEvent(event);
props.onHover?.(step);
};
</script>
<template>
<div
@mousemove="handleMouseOver"
@click="handleClick"
class="relative overflow-hidden h-4 w-full z-1 cursor-pointer"
>
<div
:class="`absolute top-0 left-0 h-full z-0`"
:style="{
backgroundColor: props.color ?? colors.tertiary,
width: `${progressPercentage(progress)}%`,
transition: `width ${props.transitionTimeMs}ms ${props.transitionEasing}`,
}"
></div>
<div
:class="`absolute top-0 left-0 h-full z-10`"
:style="{
backgroundColor: colors.primary + '90',
width: `${progressPercentage(previewProgress ?? props.range[0])}%`,
}"
></div>
</div>
</template>