initial commit
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
<script lang="ts" setup>
|
||||
import { HumanReadable } from '@/plugins/utils';
|
||||
import { computed } from 'vue';
|
||||
|
||||
const props = defineProps({
|
||||
tilesData: <any>{},
|
||||
type: String
|
||||
})
|
||||
|
||||
const data = computed(() => {
|
||||
const d = props.tilesData
|
||||
if (!d.mem && !d.cpu) return { percent: 0, text: '-' }
|
||||
switch (props.type) {
|
||||
case 'g-cpu':
|
||||
return { percent: d.cpu, text: Math.ceil(d.cpu) + "%" }
|
||||
case 'g-mem':
|
||||
const curr = HumanReadable.sizeFormat(d.mem.current,0).split(' ')
|
||||
const total = HumanReadable.sizeFormat(d.mem.total,0).split(' ')
|
||||
if (curr[1] == total[1]) curr[1] = ''
|
||||
return {
|
||||
percent: Math.ceil(d.mem.current*100/d.mem.total),
|
||||
text: curr[0] + "<sup>" + (curr[1]?? ' ') + "</sup>/" + total[0] + "<sup>" + (total[1]?? '') + "</sup>"
|
||||
}
|
||||
}
|
||||
return { percent: 0, text: '-'}
|
||||
})
|
||||
|
||||
const cssTransformRotateValue = computed(() => {
|
||||
const percentageAsFraction = data.value.percent / 100
|
||||
const halfPercentage = percentageAsFraction / 2
|
||||
|
||||
return `${halfPercentage}turn`
|
||||
})
|
||||
|
||||
const gaugeColor = computed(() => {
|
||||
if (data.value.percent > 90) return 'error'
|
||||
if (data.value.percent > 70) return 'warning'
|
||||
return 'primary'
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="gauge__outer">
|
||||
<div class="gauge__inner">
|
||||
<div
|
||||
class="gauge__fill"
|
||||
:style="{
|
||||
transform: `rotate(${cssTransformRotateValue})`,
|
||||
background: `rgb(var(--v-theme-${gaugeColor}))`
|
||||
}">
|
||||
</div>
|
||||
<span class="gauge__cover" dir="ltr" v-html="data.text">
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.gauge__outer {
|
||||
width: 100%;
|
||||
max-width: 250px;
|
||||
}
|
||||
|
||||
.gauge__inner {
|
||||
width: 100%;
|
||||
height: 0;
|
||||
padding-bottom: 50%;
|
||||
background: rgb(var(--v-theme-surface));
|
||||
position: relative;
|
||||
border-top-left-radius: 100% 200%;
|
||||
border-top-right-radius: 100% 200%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.gauge__fill {
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 0;
|
||||
width: inherit;
|
||||
height: 100%;
|
||||
background: rgb(var(--v-theme-primary));
|
||||
transform-origin: center top;
|
||||
transform: rotate(0turn);
|
||||
transition: transform 0.2s ease-out;
|
||||
}
|
||||
|
||||
.gauge__cover {
|
||||
width: 75%;
|
||||
height: 150%;
|
||||
background: rgb(var(--v-theme-background));
|
||||
position: absolute;
|
||||
top: 25%;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
border-radius: 50%;
|
||||
|
||||
/* Text */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding-bottom: 25%;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Lexend', sans-serif;
|
||||
font-weight: bold;
|
||||
font-size: 32px;
|
||||
}
|
||||
|
||||
sup {
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -0,0 +1,200 @@
|
||||
<template>
|
||||
<Line v-if="loaded" :data="data" :options="<any>options" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { ref } from 'vue'
|
||||
import { Line } from 'vue-chartjs'
|
||||
import {
|
||||
Chart as ChartJS,
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Filler,
|
||||
} from 'chart.js'
|
||||
import { HumanReadable } from '@/plugins/utils'
|
||||
ChartJS.register(
|
||||
CategoryScale,
|
||||
LinearScale,
|
||||
PointElement,
|
||||
LineElement,
|
||||
Title,
|
||||
Filler
|
||||
)
|
||||
ChartJS.defaults.font.family = 'Vazirmatn'
|
||||
export default {
|
||||
components: {
|
||||
Line
|
||||
},
|
||||
props: ['tilesData','type'],
|
||||
data() {
|
||||
return {
|
||||
loaded: false,
|
||||
labels: new Array(20).fill(''),
|
||||
oldValues: <any>{},
|
||||
options1: {
|
||||
animation: false,
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'index',
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
min: 0,
|
||||
max: 100,
|
||||
grid: {
|
||||
color: () => { return this.$vuetify.theme.current.colors.secondary },
|
||||
},
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
beginAtZero: true,
|
||||
steps: 10,
|
||||
stepValue: 5,
|
||||
max: 100
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
optionsNet: {
|
||||
animation: false,
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
interaction: {
|
||||
intersect: false,
|
||||
mode: 'index',
|
||||
},
|
||||
plugins: {
|
||||
tooltip: {
|
||||
enabled: false
|
||||
},
|
||||
legend: {
|
||||
display: false,
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
grid: {
|
||||
color: () => { return this.$vuetify.theme.current.colors.secondary },
|
||||
},
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
callback: (label:any, index: number) => { return parseInt(label).toString() },
|
||||
count: 10
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
data: ref(<any>{})
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
options() {
|
||||
switch (this.$props.type){
|
||||
case "h-net":
|
||||
this.optionsNet.scales.y.ticks.callback = (label:any, index: number) => {
|
||||
return label == 0 ? "0" : HumanReadable.sizeFormat(label,0)
|
||||
}
|
||||
return this.optionsNet
|
||||
case "hp-net":
|
||||
this.optionsNet.scales.y.ticks.callback = (label:any, index: number) => {
|
||||
return label == 0 ? "0" : HumanReadable.packetFormat(label,0)
|
||||
}
|
||||
return this.optionsNet
|
||||
}
|
||||
return this.options1
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
updateData1(value1: number) {
|
||||
const newData = <number[]>[]
|
||||
if (this.data.datasets){
|
||||
newData.push(...this.data.datasets[0].data,value1)
|
||||
}
|
||||
if (newData.length>20) newData.shift()
|
||||
this.data = {
|
||||
labels: this.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: '',
|
||||
backgroundColor: 'rgba(255, 165, 0, 0.2)',
|
||||
borderColor: 'rgba(255, 165, 0,0.8)',
|
||||
fill: true,
|
||||
data: newData
|
||||
}
|
||||
],
|
||||
}
|
||||
this.loaded = true
|
||||
},
|
||||
updateData2(value1: number, value2:number) {
|
||||
const newData1 = <number[]>[]
|
||||
const newData2 = <number[]>[]
|
||||
if (this.data.datasets){
|
||||
newData1.push(...this.data.datasets[0].data,value1)
|
||||
newData2.push(...this.data.datasets[1].data,value2)
|
||||
}
|
||||
if (newData1.length>20) newData1.shift()
|
||||
if (newData2.length>20) newData2.shift()
|
||||
this.data = {
|
||||
labels: this.labels,
|
||||
datasets: [
|
||||
{
|
||||
label: '',
|
||||
backgroundColor: 'rgba(255, 165, 0, 0.2)',
|
||||
borderColor: 'rgba(255, 165, 0,0.8)',
|
||||
fill: true,
|
||||
data: newData1
|
||||
},
|
||||
{
|
||||
label: '',
|
||||
backgroundColor: 'rgba(0, 128, 0, 0.1)',
|
||||
borderColor: 'rgba(0, 128, 0,0.8)',
|
||||
fill: true,
|
||||
data: newData2
|
||||
}
|
||||
],
|
||||
}
|
||||
this.loaded = true
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
tilesData(v:any) {
|
||||
switch (this.$props.type) {
|
||||
case 'h-cpu':
|
||||
this.updateData1(v.cpu)
|
||||
break
|
||||
case 'h-mem':
|
||||
this.updateData1(v.mem.current*100/v.mem.total)
|
||||
break
|
||||
case 'h-net':
|
||||
if (this.oldValues.sent) {
|
||||
const downSpeed = (v.net.recv-this.oldValues.recv)/2 // Each 2 sec
|
||||
const upSpeed = (v.net.sent-this.oldValues.sent)/2 // Each 2 sec
|
||||
this.updateData2(upSpeed,downSpeed)
|
||||
}
|
||||
this.oldValues = v.net
|
||||
break
|
||||
case 'hp-net':
|
||||
if (this.oldValues.psent) {
|
||||
const downSpeed = (v.net.precv-this.oldValues.precv)/2 // Each 2 sec
|
||||
const upSpeed = (v.net.psent-this.oldValues.psent)/2 // Each 2 sec
|
||||
this.updateData2(upSpeed,downSpeed)
|
||||
}
|
||||
this.oldValues = v.net
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user