56 lines
1.5 KiB
Vue
56 lines
1.5 KiB
Vue
// adapted from: https://css-tricks.com/building-a-donut-chart-with-vue-and-svg/
|
|
<template>
|
|
<div class="donut-chart">
|
|
<svg height="34" width="34" viewBox="0 0 34 34">
|
|
<g v-for="(data, index) of Object.entries(datasets)" :key="index">
|
|
<circle
|
|
:cx="cx"
|
|
:cy="cy"
|
|
:r="radius"
|
|
fill="transparent"
|
|
:stroke="colors[+data[0]]"
|
|
:stroke-dashoffset="
|
|
calculateStrokeDashOffset(data[1].percentage, circumference)
|
|
"
|
|
:stroke-dasharray="circumference"
|
|
stroke-width="3"
|
|
stroke-opacity="0.8"
|
|
:transform="returnCircleTransformValue(index, data[1].percentage)"
|
|
/>
|
|
</g>
|
|
</svg>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { toRefs } from 'vue'
|
|
|
|
interface Props {
|
|
colors: Record<number, string>
|
|
datasets: Record<number, Record<string, number>>
|
|
}
|
|
const props = defineProps<Props>()
|
|
|
|
const { colors, datasets } = toRefs(props)
|
|
let angleOffset = -90
|
|
const cx = 16
|
|
const cy = 16
|
|
const radius = 14
|
|
const circumference = 2 * Math.PI * radius
|
|
|
|
function calculateStrokeDashOffset(
|
|
percentage: number,
|
|
circumference: number
|
|
): number {
|
|
return circumference - percentage * circumference
|
|
}
|
|
function returnCircleTransformValue(
|
|
index: number,
|
|
percentage: number
|
|
): string {
|
|
const rotation = `rotate(${angleOffset}, ${cx}, ${cy})`
|
|
angleOffset = percentage * 360 + angleOffset
|
|
return rotation
|
|
}
|
|
</script>
|