1+ <script setup>
2+ import { ref , computed , onMounted } from " vue" ;
3+ import mainConfig from " ../default_configs.json" ;
4+ import { useNestedProp } from " ../useNestedProp" ;
5+ import { createUid , dataLabel , interpolateColorHex } from " ../lib" ;
6+
7+ const props = defineProps ({
8+ config: {
9+ type: Object ,
10+ default () {
11+ return {}
12+ }
13+ },
14+ dataset: {
15+ type: Object ,
16+ default (){
17+ return {}
18+ }
19+ }
20+ })
21+
22+ const defaultConfig = ref (mainConfig .vue_ui_sparkgauge );
23+
24+ const sparkgaugeConfig = computed (() => {
25+ return useNestedProp ({
26+ userConfig: props .config ,
27+ defaultConfig: defaultConfig .value
28+ })
29+ });
30+
31+ const svg = computed (() => {
32+ return {
33+ height: sparkgaugeConfig .value .style .height ,
34+ width: 128 ,
35+ base: sparkgaugeConfig .value .style .basePosition
36+ }
37+ })
38+
39+ console .log (svg .value )
40+
41+ const bounds = computed (() => {
42+ const min = props .dataset .min ?? 0 ;
43+ const max = props .dataset .max ?? 0 ;
44+ const diff = max - min;
45+ return {
46+ min,
47+ max,
48+ diff
49+ }
50+ })
51+
52+ const currentScore = ref (sparkgaugeConfig .value .style .animation .show ? bounds .value .min : props .dataset .value );
53+
54+ const animationTick = computed (() => {
55+ return bounds .value .diff / sparkgaugeConfig .value .style .animation .speedMs ;
56+ })
57+
58+ onMounted (() => {
59+ function animate () {
60+ currentScore .value += animationTick .value ;
61+ if (currentScore .value < props .dataset .value ) {
62+ requestAnimationFrame (animate)
63+ } else {
64+ currentScore .value = props .dataset .value
65+ }
66+ }
67+ if (sparkgaugeConfig .value .style .animation .show ) {
68+ currentScore .value = bounds .value .min ;
69+ animate ();
70+ }
71+ })
72+
73+ const nameLabel = computed (() => {
74+ return props .dataset .title ?? ' '
75+ })
76+
77+ const valueRatio = computed (() => {
78+ if (currentScore .value >= 0 ) {
79+ return (currentScore .value - bounds .value .min ) / bounds .value .diff
80+ } else {
81+ return (Math .abs (bounds .value .min ) - Math .abs (currentScore .value )) / bounds .value .diff
82+ }
83+ })
84+
85+ const currentColor = computed (() => {
86+ return interpolateColorHex (sparkgaugeConfig .value .style .colors .min , sparkgaugeConfig .value .style .colors .max , bounds .value .min , bounds .value .max , currentScore .value )
87+ })
88+
89+ const labelColor = computed (() => {
90+ if (! sparkgaugeConfig .value .style .dataLabel .autoColor ) {
91+ return sparkgaugeConfig .value .style .dataLabel .color ;
92+ } else {
93+ return currentColor .value ;
94+ }
95+ })
96+
97+ const trackColor = computed (() => {
98+ if (! sparkgaugeConfig .value .style .track .autoColor ) {
99+ return sparkgaugeConfig .value .style .track .color ;
100+ } else {
101+ return currentColor .value ;
102+ }
103+ })
104+ < / script>
105+
106+ < template>
107+ < div : style= " `font-family:${sparkgaugeConfig.style.fontFamily};width: 100%; background:${sparkgaugeConfig.style.background}`" >
108+ <!-- TITLE TOP -->
109+ < div v- if = " sparkgaugeConfig.style.title.show && nameLabel && sparkgaugeConfig.style.title.position === 'top'" class = " vue-data-ui-sparkgauge-label" : style= " `font-size:${sparkgaugeConfig.style.title.fontSize}px;text-align:${sparkgaugeConfig.style.title.textAlign};font-weight:${sparkgaugeConfig.style.title.bold ? 'bold': 'normal'};©`" >
110+ {{ nameLabel }}
111+ < / div>
112+ < svg : viewBox= " `0 0 ${svg.width} ${svg.height}`" : style= " `overflow: visible; background:${sparkgaugeConfig.style.background}; width:100%;`" >
113+ <!-- GUTTER -->
114+ < path
115+ : d= " `M${10} ${svg.base} A 1 1 0 1 1 ${118} ${svg.base}`"
116+ : stroke= " sparkgaugeConfig.style.gutter.color"
117+ : stroke- width= " 8"
118+ : stroke- linecap= " sparkgaugeConfig.style.gutter.strokeLinecap"
119+ fill= " none"
120+ / >
121+ <!-- TRACK -->
122+ < path
123+ v- if = " valueRatio !== 0"
124+ : d= " `M${10} ${svg.base} A 1 1 0 1 1 ${118} ${svg.base}`"
125+ : stroke= " trackColor"
126+ : stroke- width= " 8"
127+ : stroke- linecap= " sparkgaugeConfig.style.track.strokeLinecap"
128+ fill= " none"
129+ : stroke- dasharray= " 169.5"
130+ : stroke- dashoffset= " 169.5 - (169.5 * valueRatio)"
131+ : class = " {'vue-ui-sparkgauge-track' : sparkgaugeConfig.style.animation.show }"
132+ : style= " sparkgaugeConfig.style.animation.show ? `animation: vue-ui-sparkgauge-animation ${sparkgaugeConfig.style.animation.speedMs}ms ease-in;`: ''"
133+ / >
134+ <!-- DATALABEL -->
135+ < text
136+ text- anchor= " middle"
137+ : x= " svg.width / 2"
138+ : y= " svg.base + 6 + sparkgaugeConfig.style.dataLabel.offsetY"
139+ : font- size= " sparkgaugeConfig.style.dataLabel.fontSize"
140+ : fill= " labelColor"
141+ : font- weight= " sparkgaugeConfig.style.dataLabel.bold ? 'bold' : 'normal'"
142+ >
143+ {{ dataLabel ({ p: sparkgaugeConfig .style .dataLabel .prefix , v: currentScore, s: sparkgaugeConfig .style .dataLabel .suffix , r: sparkgaugeConfig .style .dataLabel .rounding }) }}
144+ < / text>
145+ < / svg>
146+ <!-- TITLE BOTTOM -->
147+ < div v- if = " sparkgaugeConfig.style.title.show && nameLabel && sparkgaugeConfig.style.title.position === 'bottom'" class = " vue-data-ui-sparkgauge-label" : style= " `font-size:${sparkgaugeConfig.style.title.fontSize}px;text-align:${sparkgaugeConfig.style.title.textAlign};font-weight:${sparkgaugeConfig.style.title.bold ? 'bold': 'normal'};font-weight:${sparkgaugeConfig.style.title.bold ? 'bold': 'normal'}`" >
148+ {{ nameLabel }}
149+ < / div>
150+ < / div>
151+ < / template>
152+
153+ < style>
154+ @keyframes vue- ui- sparkgauge- animation {
155+ from {
156+ stroke- dashoffset: 169.5 ;
157+ opacity: - 1 ;
158+ }
159+ }
160+ < / style>
0 commit comments