main
vue 112 lines 2.75 KB
Raw
1 <template>
2 <VChart class="w-full" autoresize :option="chartOption" :style="{ height: `${height}px` }" />
3 </template>
4
5 <script setup lang="ts">
6 import type { GaugeSeriesOption } from "echarts/charts"
7 import type { GridComponentOption, TooltipComponentOption } from "echarts/components"
8 import type { ComposeOption } from "echarts/core"
9 import { GaugeChart } from "echarts/charts"
10 import { GridComponent, TooltipComponent } from "echarts/components"
11 import { use } from "echarts/core"
12 import { CanvasRenderer } from "echarts/renderers"
13 import { computed, toRefs } from "vue"
14 import VChart from "vue-echarts"
15 import { useThemeStore } from "@/stores/theme"
16
17 const props = withDefaults(
18 defineProps<{
19 value: number
20 title?: string
21 height?: number
22 }>(),
23 {
24 title: "CPU Idle",
25 height: 220
26 }
27 )
28
29 use([CanvasRenderer, GaugeChart, TooltipComponent, GridComponent])
30
31 type ChartOption = ComposeOption<TooltipComponentOption | GridComponentOption | GaugeSeriesOption>
32
33 /** Arco a gradiente come nell'esempio gauge-grade. */
34 const GRADE_AXIS_COLORS: [number, string][] = [
35 [0.25, "#FF6E76"],
36 [0.5, "#FDDD60"],
37 [0.75, "#58D9F9"],
38 [1, "#7CFFB2"]
39 ]
40
41 const GAUGE_POINTER_ICON = "path://M12.8,0.7l12,40.1H0.7L12.8,0.7z"
42
43 const { value, title, height } = toRefs(props)
44 const style = computed(() => useThemeStore().style)
45
46 const chartOption = computed((): ChartOption => {
47 const fgSecondary = style.value["fg-secondary-color"]
48 const gaugeValue = Math.min(1, Math.max(0, Math.round(value.value * 10) / 10 / 100))
49
50 return {
51 backgroundColor: "transparent",
52 series: [
53 {
54 type: "gauge",
55 startAngle: 180,
56 endAngle: 0,
57 center: ["50%", "75%"],
58 radius: "90%",
59 min: 0,
60 max: 1,
61 splitNumber: 8,
62 axisLine: {
63 lineStyle: {
64 width: 6,
65 color: GRADE_AXIS_COLORS
66 }
67 },
68 pointer: {
69 icon: GAUGE_POINTER_ICON,
70 length: "12%",
71 width: 20,
72 offsetCenter: [0, "-60%"],
73 itemStyle: { color: "auto" }
74 },
75 axisTick: {
76 length: 12,
77 lineStyle: { color: "auto", width: 2 }
78 },
79 splitLine: {
80 length: 20,
81 lineStyle: { color: "auto", width: 5 }
82 },
83 axisLabel: {
84 color: fgSecondary,
85 fontSize: 11,
86 distance: -48,
87 rotate: "tangential",
88 formatter: (axisValue: number) => {
89 if (axisValue === 0) return "0%"
90 if (axisValue === 0.5) return "50%"
91 if (axisValue === 1) return "100%"
92 return ""
93 }
94 },
95 title: {
96 color: fgSecondary,
97 fontSize: 13,
98 offsetCenter: [0, "-10%"]
99 },
100 detail: {
101 fontSize: 22,
102 offsetCenter: [0, "-35%"],
103 valueAnimation: true,
104 formatter: (detailValue: number) => `${Math.round(detailValue * 100)}%`,
105 color: "inherit"
106 },
107 data: [{ value: gaugeValue, name: title.value }]
108 }
109 ]
110 }
111 })
112 </script>