Parcourir la source

add market distribution chart

Daniel Bohry il y a 9 mois
Parent
commit
b8d8f7ada1
2 fichiers modifiés avec 119 ajouts et 0 suppressions
  1. 116 0
      src/components/MarketDistributionChart.svelte
  2. 3 0
      src/routes/insights/+page.svelte

+ 116 - 0
src/components/MarketDistributionChart.svelte

@@ -0,0 +1,116 @@
+<script>
+	import { ArcElement, Chart, DoughnutController, Legend, Title, Tooltip } from 'chart.js';
+	import { onDestroy } from 'svelte';
+
+	export let data = {};
+	export let currency = 'USD';
+
+	let chartContainer;
+	let chartInstance;
+
+	function formatCurrency(value, fmtCurrency) {
+		return value.toLocaleString('en-US', {
+			style: 'currency',
+			currency: fmtCurrency
+		});
+	}
+
+	Chart.register(DoughnutController, ArcElement, Tooltip, Legend, Title);
+
+	const groupByMarket = (stocks) => {
+		const groups = {
+			Brazil: 0,
+			Germany: 0,
+			USA: 0,
+			Others: 0
+		};
+
+		stocks.forEach(stock => {
+			const code = stock.code;
+
+			if (code.startsWith('BVMF:')) {
+				groups.Brazil += stock.total;
+			} else if (code.startsWith('FRA:')) {
+				groups.Germany += stock.total;
+			} else if (code.startsWith('ETR:')) {
+				groups.Others += stock.total;
+			} else {
+				groups.USA += stock.total;
+			}
+		});
+
+		return groups;
+	};
+
+	function updateChart() {
+		if (chartInstance) {
+			chartInstance.destroy();
+		}
+
+		if (!data || !data.stocks || data.stocks.length === 0) {
+			chartInstance = null;
+			return;
+		}
+
+		const grouped = groupByMarket(data.stocks);
+		const labels = Object.keys(grouped);
+		const values = Object.values(grouped);
+
+		const chartData = {
+			labels,
+			datasets: [{
+				data: values,
+				backgroundColor: ['#3498db', '#2ecc71', '#f39c12', '#9b59b6'],
+				borderColor: '#fff',
+				borderWidth: 1
+			}]
+		};
+
+		const chartOptions = {
+			responsive: true,
+			maintainAspectRatio: false,
+			plugins: {
+				legend: {
+					display: false
+				},
+				tooltip: {
+					callbacks: {
+						label: function(tooltipItem) {
+							const value = tooltipItem.raw;
+							const label = tooltipItem.label;
+							return `${label}: ${formatCurrency(value, currency)}`;
+						}
+					}
+				}
+			}
+		};
+
+		chartInstance = new Chart(chartContainer, {
+			type: 'doughnut',
+			data: chartData,
+			options: chartOptions
+		});
+	}
+
+	$: if (chartContainer && data?.stocks?.length) {
+		updateChart();
+	}
+
+	onDestroy(() => {
+		if (chartInstance) {
+			chartInstance.destroy();
+		}
+	});
+</script>
+
+<!-- Chart container -->
+<div class="max-w-md mx-auto relative" style="height: 400px;">
+	{#if data?.stocks?.length}
+		<p class="text-center font-semibold text-gray-700 dark:text-gray-300 mb-2 text-base">
+			Market Distribution
+		</p>
+		<canvas bind:this={chartContainer} class="w-full h-full"></canvas>
+	{:else}
+		<p class="text-center text-gray-500 dark:text-gray-400">No data available.</p>
+	{/if}
+</div>

+ 3 - 0
src/routes/insights/+page.svelte

@@ -5,6 +5,7 @@
 	import { fade } from 'svelte/transition';
 	import { goto } from '$app/navigation';
 	import { getRequest } from '../../utils/api.js';
+	import MarketDistributionChart from '../../components/MarketDistributionChart.svelte';
 
 	let authToken;
 	let data = {};
@@ -94,5 +95,7 @@
 		</div>
 
 		<CurrentPositionChart {data} {currency} {total} />
+		<br />
+		<MarketDistributionChart {data} {currency} />
 	</div>
 {/if}