before claude
This commit is contained in:
90
webui/src/components/PriceHistoryChart.vue
Normal file
90
webui/src/components/PriceHistoryChart.vue
Normal file
@@ -0,0 +1,90 @@
|
||||
<template>
|
||||
<div class="price-history-chart panel p-3">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<div class="section-title text-sm">Historique</div>
|
||||
<div class="label text-xs">{{ deltaLabel }}</div>
|
||||
</div>
|
||||
<svg class="w-full h-20 mb-2" viewBox="0 0 120 50" preserveAspectRatio="none">
|
||||
<polyline :points="polyPoints" class="sparkline" fill="none" />
|
||||
<circle
|
||||
v-for="(point, index) in svgPoints"
|
||||
:key="`history-detail-point-${index}`"
|
||||
:cx="point.cx"
|
||||
:cy="point.cy"
|
||||
r="1.3"
|
||||
stroke="currentColor"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
<div class="grid grid-cols-2 gap-3 text-xs">
|
||||
<div>Actuel<br /><strong>{{ formatPrice(currentPrice) }}</strong></div>
|
||||
<div>Min<br /><strong>{{ formatPrice(minPrice) }}</strong></div>
|
||||
<div>Max<br /><strong>{{ formatPrice(maxPrice) }}</strong></div>
|
||||
<div>Delta<br /><strong>{{ deltaLabel }}</strong></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
history: {
|
||||
type: Array as () => number[],
|
||||
default: () => [],
|
||||
},
|
||||
currentPrice: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
minPrice: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
maxPrice: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
deltaLabel: {
|
||||
type: String,
|
||||
default: "—",
|
||||
},
|
||||
});
|
||||
|
||||
const polyPoints = computed(() => {
|
||||
if (!props.history.length) {
|
||||
return "0,40 30,30 60,35 90,25 120,28";
|
||||
}
|
||||
const max = Math.max(...props.history);
|
||||
const min = Math.min(...props.history);
|
||||
const range = max - min || 1;
|
||||
return props.history
|
||||
.map((value, index) => {
|
||||
const x = (index / (props.history.length - 1 || 1)) * 120;
|
||||
const y = 50 - ((value - min) / range) * 50;
|
||||
return `${x.toFixed(1)},${y.toFixed(1)}`;
|
||||
})
|
||||
.join(" ");
|
||||
});
|
||||
|
||||
const svgPoints = computed(() => {
|
||||
if (!props.history.length) {
|
||||
return [];
|
||||
}
|
||||
const max = Math.max(...props.history);
|
||||
const min = Math.min(...props.history);
|
||||
const range = max - min || 1;
|
||||
return props.history.map((value, index) => {
|
||||
const x = (index / (props.history.length - 1 || 1)) * 120;
|
||||
const y = 50 - ((value - min) / range) * 50;
|
||||
return { cx: x.toFixed(1), cy: y.toFixed(1) };
|
||||
});
|
||||
});
|
||||
|
||||
const formatPrice = (value: number) => {
|
||||
if (!Number.isFinite(value)) {
|
||||
return "n/a";
|
||||
}
|
||||
return `${value.toFixed(2)} €`;
|
||||
};
|
||||
</script>
|
||||
Reference in New Issue
Block a user