before claude
This commit is contained in:
87
webui/src/components/MiniSparkline.vue
Normal file
87
webui/src/components/MiniSparkline.vue
Normal file
@@ -0,0 +1,87 @@
|
||||
<script setup lang="ts">
|
||||
import { computed, PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
points: {
|
||||
type: Array as PropType<number[]>,
|
||||
default: () => [],
|
||||
},
|
||||
width: {
|
||||
type: Number,
|
||||
default: 280,
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 14,
|
||||
},
|
||||
padding: {
|
||||
type: Number,
|
||||
default: 4,
|
||||
},
|
||||
});
|
||||
|
||||
const validPoints = computed(() =>
|
||||
(props.points || [])
|
||||
.map((value) => (Number.isFinite(value) ? Number(value) : null))
|
||||
.filter((value): value is number => value !== null)
|
||||
);
|
||||
|
||||
const pointRange = computed(() => {
|
||||
const points = validPoints.value;
|
||||
if (points.length === 0) {
|
||||
return { min: 0, max: 1 };
|
||||
}
|
||||
const min = Math.min(...points);
|
||||
const max = Math.max(...points);
|
||||
return { min, max };
|
||||
});
|
||||
|
||||
const svgPoints = computed(() => {
|
||||
const points = validPoints.value;
|
||||
const { min, max } = pointRange.value;
|
||||
if (points.length === 0) {
|
||||
return "";
|
||||
}
|
||||
const delta = max - min || 1;
|
||||
const availableWidth = props.width - props.padding * 2;
|
||||
const availableHeight = props.height - props.padding * 2;
|
||||
const step = points.length > 1 ? availableWidth / (points.length - 1) : 0;
|
||||
return points
|
||||
.map((value, index) => {
|
||||
const x = props.padding + step * index;
|
||||
const normalized = (value - min) / delta;
|
||||
const y = props.padding + availableHeight * (1 - normalized);
|
||||
return `${x},${y}`;
|
||||
})
|
||||
.join(" ");
|
||||
});
|
||||
|
||||
const hasPoints = computed(() => validPoints.value.length > 1);
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="mini-sparkline">
|
||||
<svg
|
||||
:width="width"
|
||||
:height="height"
|
||||
:viewBox="`0 0 ${width} ${height}`"
|
||||
role="presentation"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<polyline
|
||||
v-if="hasPoints"
|
||||
:points="svgPoints"
|
||||
class="sparkline-polyline"
|
||||
fill="none"
|
||||
/>
|
||||
<line
|
||||
v-else
|
||||
:x1="padding"
|
||||
:y1="height / 2"
|
||||
:x2="width - padding"
|
||||
:y2="height / 2"
|
||||
class="sparkline-polyline"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user