feat: 新增切換機構的progress bars動畫

This commit is contained in:
MJM_2025_05\polly 2025-09-05 13:17:39 +08:00
parent 197322eb1c
commit d785ab54bd
11 changed files with 862 additions and 641 deletions

View File

@ -8,6 +8,7 @@
rel="stylesheet" rel="stylesheet"
href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css" href="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/style.min.css"
/> />
<script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script> <script src="https://developer.api.autodesk.com/modelderivative/v2/viewers/7.*/viewer3D.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

View File

@ -20,21 +20,19 @@
<div class="relative"> <div class="relative">
<progress <progress
v-bind="$attrs" v-bind="$attrs"
class="progress w-full h-5 bg-brand-gray-lighter text-brand-green-light text-left rounded-none [&::-webkit-progress-bar]:rounded-none [&::-webkit-progress-value]:rounded-none [&::-moz-progress-bar]:rounded-none" class="progress w-full h-5 bg-brand-gray-lighter text-brand-green-light text-left [&::-webkit-progress-bar]:rounded-none [&::-webkit-progress-value]:rounded-none [&::-moz-progress-bar]:rounded-none"
:class="heightClass" :value="animatedValue"
:value="current"
:max="total" :max="total"
role="progressbar" role="progressbar"
:aria-valuenow="current" :aria-valuenow="animatedValue"
aria-valuemin="0" aria-valuemin="0"
:aria-valuemax="total" :aria-valuemax="total"
></progress> ></progress>
<span <span
class="w-full absolute bottom-0 flex justify-between items-center text-[20px] font-nats pe-5 text-brand-black/80 group-hover:text-brand-purple-dark" class="w-full absolute bottom-0 flex justify-between items-center text-[20px] font-nats pe-5 text-brand-black/80 group-hover:text-brand-purple-dark left-2"
:class="textPosClass"
> >
{{ currentLocale }} / {{ totalLocale }} {{ animatedValueLocale }} / {{ totalLocale }}
<span aria-hidden="true"> <span aria-hidden="true">
<svg <svg
class="text-brand-gray/50" class="text-brand-gray/50"
@ -55,7 +53,7 @@
</template> </template>
<script setup> <script setup>
import { computed } from "vue"; import { ref, watch, computed } from "vue";
defineOptions({ inheritAttrs: false }); defineOptions({ inheritAttrs: false });
const props = defineProps({ const props = defineProps({
@ -66,32 +64,56 @@ const props = defineProps({
chartKey: { type: String, required: true }, chartKey: { type: String, required: true },
currentLegend: { type: String, required: true }, currentLegend: { type: String, required: true },
totalLegend: { type: String, required: true }, totalLegend: { type: String, required: true },
height: { type: [Number, String], default: 5 }, duration: { type: Number, default: 100 },
}); });
const emit = defineEmits(["select"]); const emit = defineEmits(["select"]);
const heightClass = computed(() => `h-${props.height}`); const animatedValue = ref(0);
const textPosClass = computed(() => { const animatedValueLocale = computed(() => animatedValue.value.toLocaleString());
switch (props.textAlign) {
case "center":
return "left-1/2 -translate-x-1/2";
case "right":
return "right-2";
default:
return "left-2";
}
});
const currentLocale = computed(() => props.current.toLocaleString());
const totalLocale = computed(() => props.total.toLocaleString()); const totalLocale = computed(() => props.total.toLocaleString());
watch(
() => props.current,
(newVal) => {
animateValue(newVal);
},
{ immediate: true }
);
function animateValue(target) {
const start = animatedValue.value;
const diff = target - start;
const startTime = performance.now();
function step(now) {
const elapsed = now - startTime;
const progress = Math.min(elapsed / props.duration, 1);
animatedValue.value = Math.round(start + diff * progress);
if (progress < 1) {
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
}
function handleSelect() { function handleSelect() {
//
emit("select", { emit("select", {
key: props.chartKey, key: props.chartKey,
legends: [props.currentLegend, props.totalLegend], legends: [props.currentLegend, props.totalLegend],
titleText: `progress ${currentLocale.value} / ${totalLocale.value}`, titleText: `${props.currentLegend} ${animatedValueLocale.value} / ${totalLocale.value}`,
}); });
} }
</script> </script>
<style scoped>
progress::-webkit-progress-value {
transition: width 0.2s ease-out;
height: 20px; /* 恢復原本高度 */
}
progress::-moz-progress-bar {
transition: width 0.2s ease-out;
height: 20px; /* 恢復原本高度 */
}
</style>

View File

@ -1,75 +0,0 @@
<template>
<div
class="absolute top-3 inset-x-0 z-[1000] pointer-events-none flex justify-center"
>
<div
class="pointer-events-auto inline-flex items-center text-sm text-brand-gray-dark bg-white bg-opacity-90 border border-gray-300 rounded-md shadow-md ps-3"
role="group"
aria-label="顯示資訊切換"
>
<div class="flex items-center">
<p class="py-2 pr-2">顯示資訊</p>
<!-- 不顯示 -->
<button class="flex items-center gap-2 px-3 py-2 rounded-md">
<span class="" inline-block>
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 15 15"
>
<path
fill="currentColor"
d="M3.64 2.27L7.5 6.13l3.84-3.84A.92.92 0 0 1 12 2a1 1 0 0 1 1 1a.9.9 0 0 1-.27.66L8.84 7.5l3.89 3.89A.9.9 0 0 1 13 12a1 1 0 0 1-1 1a.92.92 0 0 1-.69-.27L7.5 8.87l-3.85 3.85A.92.92 0 0 1 3 13a1 1 0 0 1-1-1a.9.9 0 0 1 .27-.66L6.16 7.5L2.27 3.61A.9.9 0 0 1 2 3a1 1 0 0 1 1-1c.24.003.47.1.64.27"
/>
</svg>
</span>
<span>不顯示</span>
</button>
<!-- 住民 -->
<button class="flex items-center gap-2 px-3 py-2 rounded-md">
<span class="inline-block">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 16 16"
>
<path
fill="currentColor"
d="M3 14s-1 0-1-1s1-4 6-4s6 3 6 4s-1 1-1 1zm5-6a3 3 0 1 0 0-6a3 3 0 0 0 0 6"
/>
</svg>
</span>
<span>入住情況</span>
</button>
<!-- 葷素資訊 -->
<button class="flex items-center gap-2 px-3 py-2 rounded-md">
<span class="inline-block">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
>
<path
fill="currentColor"
d="M17.5 2.75a.75.75 0 0 0-1.5 0v4.015c-2.026-1.358-4.867-.881-6.293 1.215L2.353 18.786c-.556.818-.45 1.91.255 2.608a2.1 2.1 0 0 0 2.667.23l10.79-7.469A4.454 4.454 0 0 0 17.24 8h4.009a.75.75 0 0 0 0-1.5h-2.69l3.22-3.22a.75.75 0 0 0-1.06-1.06L17.5 5.439z"
/>
</svg>
</span>
<span>飲食情況</span>
</button>
</div>
</div>
</div>
</template>
<script>
export default {};
</script>
<style lang="scss" scoped></style>

File diff suppressed because it is too large Load Diff