|
|
@@ -101,6 +101,38 @@
|
|
|
ChartDataLabels
|
|
|
);
|
|
|
|
|
|
+ function getFlag(code) {
|
|
|
+ const market = code.includes(':') ? code.split(':')[0].toUpperCase() : code.toUpperCase();
|
|
|
+
|
|
|
+ const country = {
|
|
|
+ BVMF: 'br',
|
|
|
+ FRA: 'de',
|
|
|
+ ETR: 'eu'
|
|
|
+ };
|
|
|
+
|
|
|
+ return country[market] || 'us';
|
|
|
+ }
|
|
|
+
|
|
|
+ function getMarketFlag(market) {
|
|
|
+ const marketFlags = {
|
|
|
+ Brazil: 'br',
|
|
|
+ Germany: 'de',
|
|
|
+ USA: 'us',
|
|
|
+ Others: 'eu'
|
|
|
+ };
|
|
|
+ return marketFlags[market] || 'us';
|
|
|
+ }
|
|
|
+
|
|
|
+ function getMarketFlagEmoji(market) {
|
|
|
+ const flagEmojis = {
|
|
|
+ Brazil: '🇧🇷',
|
|
|
+ Germany: '🇩🇪',
|
|
|
+ USA: '🇺🇸',
|
|
|
+ Others: '🇪🇺'
|
|
|
+ };
|
|
|
+ return flagEmojis[market] || '🇺🇸';
|
|
|
+ }
|
|
|
+
|
|
|
const groupByMarket = (stocks) => {
|
|
|
const groups = {
|
|
|
Brazil: 0,
|
|
|
@@ -140,8 +172,9 @@
|
|
|
}
|
|
|
|
|
|
const grouped = groupByMarket(data.stocks);
|
|
|
- const labels = Object.keys(grouped);
|
|
|
- const values = Object.values(grouped);
|
|
|
+ const filteredEntries = Object.entries(grouped).filter(([_, value]) => value > 0);
|
|
|
+ const labels = filteredEntries.map(([market, _]) => market);
|
|
|
+ const values = filteredEntries.map(([_, value]) => value);
|
|
|
const chartColors = generateColors(labels.length);
|
|
|
|
|
|
const chartData = {
|
|
|
@@ -212,11 +245,14 @@
|
|
|
const total = dataArray.reduce((sum, val) => sum + val, 0);
|
|
|
const percentage = total ? (value / total) * 100 : 0;
|
|
|
|
|
|
- // Only show labels for segments larger than 0.1%
|
|
|
if (percentage < 0.1) {
|
|
|
return null;
|
|
|
}
|
|
|
- return `${percentage.toFixed(1)}%`;
|
|
|
+
|
|
|
+ const market = context.chart.data.labels[context.dataIndex];
|
|
|
+ const flagEmoji = getMarketFlagEmoji(market);
|
|
|
+
|
|
|
+ return `${flagEmoji} ${percentage.toFixed(1)}%`;
|
|
|
},
|
|
|
anchor: 'center',
|
|
|
align: 'center',
|
|
|
@@ -228,13 +264,11 @@
|
|
|
padding: 4
|
|
|
}
|
|
|
},
|
|
|
- // Add accessibility
|
|
|
accessibility: {
|
|
|
enabled: true
|
|
|
}
|
|
|
};
|
|
|
|
|
|
- // Update existing chart if possible, otherwise create new one
|
|
|
if (chartInstance) {
|
|
|
chartInstance.data = chartData;
|
|
|
chartInstance.options = chartOptions;
|
|
|
@@ -335,9 +369,9 @@
|
|
|
</table>
|
|
|
</div>
|
|
|
|
|
|
- <!-- Legend for mobile devices (typically 4 markets or less) -->
|
|
|
+ <!-- Legend with flags (typically 4 markets or less) -->
|
|
|
{#if Object.values(groupByMarket(data.stocks)).filter(v => v > 0).length <= 4}
|
|
|
- <div class="mt-4 grid grid-cols-2 gap-2 text-xs md:hidden" aria-label="Chart legend">
|
|
|
+ <div class="mt-4 grid grid-cols-2 md:grid-cols-4 gap-2 text-xs" aria-label="Chart legend">
|
|
|
{#each Object.entries(groupByMarket(data.stocks)).filter(([_, value]) => value > 0) as [market, value], index}
|
|
|
<div class="flex items-center space-x-2">
|
|
|
<div
|
|
|
@@ -345,8 +379,13 @@
|
|
|
style="background-color: {generateColors(Object.keys(groupByMarket(data.stocks)).length)[index]}"
|
|
|
aria-hidden="true"
|
|
|
></div>
|
|
|
+ <img
|
|
|
+ src={`https://flagcdn.com/w40/${getMarketFlag(market)}.png`}
|
|
|
+ alt="{market} flag"
|
|
|
+ class="w-5 h-auto flex-shrink-0"
|
|
|
+ />
|
|
|
<span class="text-gray-700 dark:text-gray-300 truncate">
|
|
|
- {market}
|
|
|
+ {market} ({((value / total) * 100).toFixed(1)}%)
|
|
|
</span>
|
|
|
</div>
|
|
|
{/each}
|