feat: 新增切換機構的progress bars動畫
@ -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" />
|
||||||
|
BIN
public/img/building/building_1.jpg
Normal file
After Width: | Height: | Size: 118 KiB |
BIN
public/img/building/building_2.jpg
Normal file
After Width: | Height: | Size: 184 KiB |
BIN
public/img/building/building_3.jpg
Normal file
After Width: | Height: | Size: 99 KiB |
BIN
public/img/building/building_4.jpg
Normal file
After Width: | Height: | Size: 124 KiB |
BIN
public/img/building/building_5.jpg
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
public/img/building/building_6.jpg
Normal file
After Width: | Height: | Size: 54 KiB |
BIN
public/img/building/building_7.jpg
Normal file
After Width: | Height: | Size: 163 KiB |
@ -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>
|
||||||
|
@ -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>
|
|