diff options
| author | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
|---|---|---|
| committer | Martial Simon <msimon_fr@hotmail.com> | 2025-09-15 01:07:58 +0200 |
| commit | 967be9e750221ab2ab783f95df79bb26d290a45e (patch) | |
| tree | 6802900a5e975f9f68b169f0f503f040056d6952 /ping/frontend/src/lib/components/dashboard/StockGraph.svelte | |
Diffstat (limited to 'ping/frontend/src/lib/components/dashboard/StockGraph.svelte')
| -rw-r--r-- | ping/frontend/src/lib/components/dashboard/StockGraph.svelte | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/ping/frontend/src/lib/components/dashboard/StockGraph.svelte b/ping/frontend/src/lib/components/dashboard/StockGraph.svelte new file mode 100644 index 0000000..beefed9 --- /dev/null +++ b/ping/frontend/src/lib/components/dashboard/StockGraph.svelte @@ -0,0 +1,136 @@ +<script lang="ts"> + import Chart from 'chart.js/auto'; + import { onMount } from 'svelte'; + import StockSelector from '../input/StockSelector.svelte'; + + async function fetchChartData(stock: string, startDate: string, endDate: string) { + const res = await fetch( + `/stocksapi/chart?query=${stock}&startDate=${startDate}&endDate=${endDate}&interval=${range}`, + { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache' + } + } + ); + return await res.json(); + } + + function updateGraph() { + fetchChartData(selectedStock, startDate, endDate).then((data) => { + if (chart) { + chart.destroy(); + chart = null; + } + + const { quotes, meta } = data; + + validRanges = meta.validRanges; + + const labels = quotes.map((item: any) => item.date.split('T')[0]); + const datasets = ['low', 'high', 'open', 'close'].map((key) => ({ + label: key.charAt(0).toUpperCase() + key.slice(1), + data: quotes.map((item: any) => item[key]), + borderColor: + key === 'low' + ? 'rgb(255, 99, 132)' + : key === 'high' + ? 'rgb(54, 162, 235)' + : key === 'open' + ? 'rgb(255, 205, 86)' + : 'rgb(75, 192, 192)', + fill: false + })); + + // @ts-ignore + chart = new Chart(document.getElementById('stockgraph'), { + type: 'line', + data: { + labels, + datasets + }, + options: { + responsive: true, + maintainAspectRatio: true, + plugins: { + title: { + display: true, + text: meta.longName + } + } + } + }); + }); + } + + let today = $state(new Date().toISOString().split('T')[0]); + + let selectedStock = $state('2223.SR'); + let startDate = $state(''); + let endDate = $state(''); + let chart = $state<Chart | null>(null); + let range = $state('1d'); + let validRanges = $state(['1d']); + + onMount(() => { + endDate = new Date().toISOString().split('T')[0]; + startDate = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString().split('T')[0]; + + updateGraph(); + }); + + $effect(() => { + if (selectedStock && startDate && endDate && range) { + updateGraph(); + } + }); + + $effect(() => { + if (startDate && endDate && startDate > endDate) { + let temp = startDate; + startDate = endDate; + endDate = temp; + } + }); +</script> + +<div> + <div class="header"> + <h2>Vue d'ensemble : {selectedStock}</h2> + <div class="controls"> + <input type="date" name="startDate" id="startDate" bind:value={startDate} max={today} /> + <input type="date" name="endDate" id="endDate" bind:value={endDate} max={today} /> + <select name="validRanges" id="validRanges" bind:value={range}> + {#each validRanges as r} + <option value={r}> + {r} + </option> + {/each} + </select> + + <StockSelector bind:selectedStock /> + </div> + </div> + <canvas id="stockgraph"></canvas> +</div> + +<style> + .header { + display: flex; + align-items: center; + justify-content: space-between; + max-height: 512px !important; + } + + h2 { + font-weight: bold; + color: var(--text-lime); + font-size: 24px; + } + + #stockgraph { + width: 100% !important; + max-height: 512px !important; + } +</style> |
