88 lines
1.9 KiB
Vue
88 lines
1.9 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue'
|
|
|
|
const props = withDefaults(defineProps<{
|
|
data: { date: string; value: number }[]
|
|
color?: string
|
|
height?: number
|
|
maxPoints?: number
|
|
}>(), {
|
|
color: 'var(--accent-cyan)',
|
|
height: 60,
|
|
maxPoints: 30
|
|
})
|
|
|
|
const displayData = computed(() => {
|
|
if (props.data.length <= props.maxPoints) return props.data
|
|
// 采样:均匀抽取
|
|
const step = Math.ceil(props.data.length / props.maxPoints)
|
|
return props.data.filter((_, i) => i % step === 0)
|
|
})
|
|
|
|
const maxValue = computed(() => Math.max(...displayData.value.map(d => d.value), 1))
|
|
|
|
const points = computed(() => {
|
|
return displayData.value.map((d, i) => {
|
|
const x = (i / (displayData.value.length - 1)) * 100
|
|
const y = 100 - (d.value / maxValue.value * 100)
|
|
return `${x},${y}`
|
|
}).join(' ')
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="mini-line-chart" :style="{ '--chart-height': height + 'px', '--chart-color': color }">
|
|
<svg :viewBox="`0 0 100 100`" preserveAspectRatio="none" class="chart-svg">
|
|
<!-- 背景网格 -->
|
|
<line x1="0" y1="50" x2="100" y2="50" class="grid-line" />
|
|
<!-- 折线 -->
|
|
<polyline :points="points" class="line" />
|
|
<!-- 数据点 -->
|
|
<circle
|
|
v-for="(d, i) in displayData"
|
|
:key="i"
|
|
:cx="(i / (displayData.length - 1)) * 100"
|
|
:cy="100 - (d.value / maxValue * 100)"
|
|
r="2"
|
|
class="dot"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.mini-line-chart {
|
|
width: 100%;
|
|
height: var(--chart-height);
|
|
}
|
|
|
|
.chart-svg {
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
|
|
.grid-line {
|
|
stroke: var(--border-dim);
|
|
stroke-width: 0.5;
|
|
}
|
|
|
|
.line {
|
|
fill: none;
|
|
stroke: var(--chart-color);
|
|
stroke-width: 1.5;
|
|
stroke-linecap: round;
|
|
stroke-linejoin: round;
|
|
opacity: 0.8;
|
|
}
|
|
|
|
.dot {
|
|
fill: var(--chart-color);
|
|
opacity: 0;
|
|
transition: opacity var(--transition-fast);
|
|
}
|
|
|
|
.mini-line-chart:hover .dot {
|
|
opacity: 1;
|
|
}
|
|
</style>
|