Skip to content

Commit dc4cd73

Browse files
committed
New feature - VueUiGizmo - Add new component
1 parent 8755a20 commit dc4cd73

File tree

1 file changed

+170
-0
lines changed

1 file changed

+170
-0
lines changed

src/components/vue-ui-gizmo.vue

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<script setup>
2+
import { ref, computed, onMounted } from "vue";
3+
import { useConfig } from "../useConfig";
4+
import { createUid, error, objectIsEmpty, shiftHue } from "../lib";
5+
import { useNestedProp } from "../useNestedProp";
6+
7+
const { vue_ui_gizmo: DEFAULT_CONFIG } = useConfig();
8+
9+
const props = defineProps({
10+
config: {
11+
type: Object,
12+
default() {
13+
return {}
14+
}
15+
},
16+
dataset: {
17+
type: Number,
18+
default: 0
19+
},
20+
});
21+
22+
const uid = ref(createUid());
23+
24+
onMounted(() => {
25+
if (!props.dataset && props.dataset !== 0) {
26+
error({
27+
componentName: 'VueUiGizmo',
28+
type: 'dataset'
29+
})
30+
}
31+
if (props.dataset < 0) {
32+
console.warn('VueUiGizmo: dataset cannot be negative.')
33+
}
34+
});
35+
36+
const FINAL_CONFIG = computed(() => {
37+
return useNestedProp({
38+
userConfig: props.config,
39+
defaultConfig: DEFAULT_CONFIG
40+
})
41+
})
42+
43+
const svg = computed(() => {
44+
const options = {
45+
battery: { width: FINAL_CONFIG.value.showPercentage ? 140 : 80, height: 50 },
46+
gauge: { width: 80, height: 80 },
47+
}
48+
return options[FINAL_CONFIG.value.type];
49+
});
50+
51+
const barBody = computed(() => {
52+
const x = 70 * (props.dataset / 100)
53+
return `M 5 10 L 5 10 C 5 13 7 15 10 15 L ${x} 15 C ${x + 3} 15 ${x + 5} 13 ${x + 5} 10 L ${x + 5} 10 C ${x + 5} 7 ${x + 3} 5 ${x} 5 L 10 5 C 7 5 5 7 5 10`
54+
})
55+
56+
const gaugeBody = computed(() => {
57+
const circumference = 35 * (2 + (props.dataset / 100 > 1 ? 0 : 1 - props.dataset / 100)) * Math.PI;
58+
return {
59+
dasharray: `${circumference} ${circumference}`,
60+
dashoffset: circumference - props.dataset / 100 * circumference,
61+
}
62+
})
63+
64+
</script>
65+
66+
<template>
67+
<svg
68+
class="vue-ui-gizmo"
69+
:viewBox="`0 0 ${svg.width} ${svg.height}`"
70+
:width="FINAL_CONFIG.size"
71+
:style="{
72+
background: 'transparent',
73+
fontFamily: FINAL_CONFIG.fontFamily
74+
}"
75+
>
76+
<defs v-if="FINAL_CONFIG.useGradient">
77+
<linearGradient :id="`gizmo_gradient_${uid}`" x1="0%" x2="100%" y1="0%" y2="0%">
78+
<stop offset="0%" :stop-color="FINAL_CONFIG.gradientColor" />
79+
<stop offset="100%" :stop-color="FINAL_CONFIG.color" />
80+
</linearGradient>
81+
</defs>
82+
83+
<!-- BATTERY -->
84+
<template v-if="FINAL_CONFIG.type === 'battery'">
85+
<path
86+
d="M 5 10 L 5 40 C 5 43 7 45 9 45 L 65 45 C 68 45 70 43 70 40 L 70 38 C 73 38 75 38 75 33 L 75 17 C 75 12 73 12 70 12 L 70 10 C 70 7 68 5 65 5 L 10 5 C 7 5 5 7 5 10"
87+
:stroke="FINAL_CONFIG.stroke"
88+
:stroke-width="2"
89+
fill="none"
90+
/>
91+
<path
92+
d="M 70 16 L 70 34"
93+
:stroke="FINAL_CONFIG.stroke"
94+
:stroke-width="2"
95+
fill="none"
96+
style="opacity: 0.5"
97+
/>
98+
<rect
99+
:x="10"
100+
:y="10"
101+
:height="30"
102+
:width="55 * (dataset / 100)"
103+
:fill="FINAL_CONFIG.useGradient ? `url(#gizmo_gradient_${uid})`: FINAL_CONFIG.color"
104+
:rx="2"
105+
/>
106+
<text
107+
v-if="FINAL_CONFIG.showPercentage"
108+
:x="85"
109+
:y="32"
110+
text-anchor="start"
111+
font-size="20"
112+
:fill="FINAL_CONFIG.textColor"
113+
>
114+
{{ Math.round(props.dataset) }}%
115+
</text>
116+
</template>
117+
118+
<!-- GAUGE -->
119+
<template v-if="FINAL_CONFIG.type === 'gauge'">
120+
<defs v-if="FINAL_CONFIG.useGradient">
121+
<filter :id="`blur_${uid}`" x="-50%" y="-50%" width="200%" height="200%">
122+
<feGaussianBlur in="SourceGraphic" :stdDeviation="1" />
123+
</filter>
124+
</defs>
125+
<circle
126+
:cx="40"
127+
:cy="40"
128+
:r="35"
129+
:stroke="FINAL_CONFIG.stroke"
130+
:stroke-width="2 * 4"
131+
fill="none"
132+
/>
133+
<circle
134+
:cx="40"
135+
:cy="40"
136+
:r="35"
137+
:stroke="FINAL_CONFIG.color"
138+
:stroke-width="2 * 4"
139+
:stroke-dasharray="gaugeBody.dasharray"
140+
:stroke-dashoffset="gaugeBody.dashoffset"
141+
stroke-linecap="round"
142+
fill="none"
143+
style="transform:rotate(-90deg);transform-origin: 50% 50%"
144+
/>
145+
<g v-if="FINAL_CONFIG.useGradient" :filter="`url(#blur_${uid})`">
146+
<circle
147+
:cx="40"
148+
:cy="40"
149+
:r="35"
150+
:stroke="FINAL_CONFIG.gradientColor"
151+
:stroke-width="1"
152+
fill="none"
153+
:stroke-dasharray="gaugeBody.dasharray"
154+
:stroke-dashoffset="gaugeBody.dashoffset"
155+
style="transform:rotate(-90deg);transform-origin: 50% 50%"
156+
/>
157+
</g>
158+
<text
159+
v-if="FINAL_CONFIG.showPercentage"
160+
:x="40"
161+
:y="47"
162+
text-anchor="middle"
163+
font-size="20"
164+
:fill="FINAL_CONFIG.textColor"
165+
>
166+
{{ Math.round(props.dataset) }}%
167+
</text>
168+
</template>
169+
</svg>
170+
</template>

0 commit comments

Comments
 (0)