207 lines
4.3 KiB
Vue
207 lines
4.3 KiB
Vue
<template>
|
|
<div class="d-flex justify-center my-2 position-relative">
|
|
<svg class="radar-svg" height="260" viewBox="0 0 120 120" width="260">
|
|
<polygon
|
|
v-for="grid in [20, 40, 60, 80, 100]"
|
|
:key="grid"
|
|
fill="none"
|
|
:points="getPolygonPoints(grid)"
|
|
stroke="#E0E0E0"
|
|
stroke-width="0.3"
|
|
/>
|
|
|
|
<line
|
|
v-for="i in 5"
|
|
:key="`axis-${i}`"
|
|
stroke="#E0E0E0"
|
|
stroke-width="0.3"
|
|
x1="60"
|
|
:x2="getAxisEndPoint(i - 1).x"
|
|
y1="60"
|
|
:y2="getAxisEndPoint(i - 1).y"
|
|
/>
|
|
|
|
<polygon
|
|
fill="rgba(33, 150, 243, 0.12)"
|
|
:points="getPolygonPoints(65)"
|
|
stroke="#2196F3"
|
|
stroke-dasharray="1 1"
|
|
stroke-width="0.5"
|
|
/>
|
|
|
|
<polygon
|
|
fill="rgba(71, 194, 166, 0.35)"
|
|
:points="userDataPoints"
|
|
stroke="#1D7063"
|
|
stroke-width="1.2"
|
|
/>
|
|
|
|
<circle
|
|
v-for="(point, index) in userDataCoordArray"
|
|
:key="`dot-${index}`"
|
|
:cx="point.x"
|
|
:cy="point.y"
|
|
fill="#E66926"
|
|
r="1.5"
|
|
stroke="#FFFFFF"
|
|
stroke-width="0.5"
|
|
/>
|
|
|
|
<text
|
|
fill="#1D7063"
|
|
font-size="4"
|
|
font-weight="bold"
|
|
text-anchor="middle"
|
|
x="60"
|
|
y="8"
|
|
>
|
|
心肺 ({{ radarData.cardio }})
|
|
</text>
|
|
|
|
<text
|
|
fill="#1D7063"
|
|
font-size="4"
|
|
font-weight="bold"
|
|
text-anchor="start"
|
|
x="110"
|
|
y="44"
|
|
>
|
|
肌力 ({{ radarData.strength }})
|
|
</text>
|
|
|
|
<text
|
|
fill="#1D7063"
|
|
font-size="4"
|
|
font-weight="bold"
|
|
text-anchor="start"
|
|
x="94"
|
|
y="104"
|
|
>
|
|
平衡 ({{ radarData.balance }})
|
|
</text>
|
|
|
|
<text
|
|
fill="#1D7063"
|
|
font-size="4"
|
|
font-weight="bold"
|
|
text-anchor="end"
|
|
x="26"
|
|
y="104"
|
|
>
|
|
柔軟 ({{ radarData.flexibility }})
|
|
</text>
|
|
|
|
<text
|
|
fill="#1D7063"
|
|
font-size="4"
|
|
font-weight="bold"
|
|
text-anchor="end"
|
|
x="10"
|
|
y="44"
|
|
>
|
|
敏捷 ({{ radarData.agility }})
|
|
</text>
|
|
</svg>
|
|
|
|
<!-- <div class="radar-legend d-flex flex-column">
|
|
<div class="d-flex align-center text-caption mb-1">
|
|
<span class="legend-color bg-primary mr-1" />
|
|
<span>我的指標</span>
|
|
</div>
|
|
|
|
<div class="d-flex align-center text-caption">
|
|
<span class="legend-color bg-blue mr-1 border-dashed" />
|
|
<span>同齡參考</span>
|
|
</div>
|
|
</div> -->
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
|
|
interface RadarData {
|
|
strength: number
|
|
balance: number
|
|
flexibility: number
|
|
agility: number
|
|
cardio: number
|
|
}
|
|
|
|
const { radarData } = defineProps<{
|
|
radarData: RadarData
|
|
}>()
|
|
|
|
const centerX = 60
|
|
const centerY = 60
|
|
const radius = 45
|
|
|
|
function getAxisEndPoint (index: number, pointRadius = radius) {
|
|
const angle = -Math.PI / 2 + (index * 2 * Math.PI) / 5
|
|
|
|
return {
|
|
x: centerX + pointRadius * Math.cos(angle),
|
|
y: centerY + pointRadius * Math.sin(angle),
|
|
}
|
|
}
|
|
|
|
function getPolygonPoints (percent: number) {
|
|
const pointRadius = (percent / 100) * radius
|
|
const points = []
|
|
|
|
for (let index = 0; index < 5; index++) {
|
|
const point = getAxisEndPoint(index, pointRadius)
|
|
points.push(`${point.x},${point.y}`)
|
|
}
|
|
|
|
return points.join(' ')
|
|
}
|
|
|
|
const userDataCoordArray = computed(() => {
|
|
const values = [
|
|
radarData.cardio,
|
|
radarData.strength,
|
|
radarData.balance,
|
|
radarData.flexibility,
|
|
radarData.agility,
|
|
]
|
|
|
|
return values.map((value, index) => {
|
|
const pointRadius = (Math.max(5, Math.min(100, value)) / 100) * radius
|
|
return getAxisEndPoint(index, pointRadius)
|
|
})
|
|
})
|
|
|
|
const userDataPoints = computed(() => {
|
|
return userDataCoordArray.value.map(point => `${point.x},${point.y}`).join(' ')
|
|
})
|
|
</script>
|
|
|
|
<style scoped>
|
|
.radar-legend {
|
|
position: absolute;
|
|
right: 0;
|
|
bottom: 0;
|
|
padding: 6px 8px;
|
|
background-color: rgba(255, 255, 255, 0.85);
|
|
border: 1px solid rgba(0, 0, 0, 0.05);
|
|
border-radius: 8px;
|
|
}
|
|
|
|
.legend-color {
|
|
display: inline-block;
|
|
width: 12px;
|
|
height: 12px;
|
|
border-radius: 2px;
|
|
}
|
|
|
|
.border-dashed {
|
|
background-color: rgba(33, 150, 243, 0.12) !important;
|
|
border: 1px dashed #2196f3;
|
|
}
|
|
|
|
.radar-svg text {
|
|
font-family: inherit;
|
|
}
|
|
</style>
|