File: /var/www/quadcode.com/src/components/blocks/investment-calculator/InvestmentAdvancedChart.svelte
<script lang="ts">
import { onMount, tick } from 'svelte';
import { t } from '$lib/translations';
import { investmentCalculator } from '../../../store';
import { chartSegments, type IInvestmentCalculator } from '$type/investmentCalculator';
let nominalValue = 0;
let realValue = 0;
let estimatedTaxes = 0;
let inflationImpact = 0;
let managementFees = 0;
let valueElements: HTMLElement[] = [];
const updateSegments = () => {
if (window.matchMedia('(max-width: 767px)').matches) {
chartSegments.set(22);
} else if (window.matchMedia('(max-width: 1439px)').matches) {
chartSegments.set(40);
} else {
chartSegments.set(30);
}
};
const syncValueWidths = async () => {
await tick();
if (!valueElements.length) return;
valueElements.forEach(el => el.style.minWidth = '');
const maxW = Math.max(...valueElements.map(el => el.getBoundingClientRect().width));
valueElements.forEach(el => el.style.minWidth = `${maxW}px`);
};
onMount(() => {
updateSegments();
syncValueWidths();
const media = [
window.matchMedia('(max-width: 767px)'),
window.matchMedia('(max-width: 1439px)')
];
media.forEach(m => m.addEventListener('change', updateSegments));
return () => {
media.forEach(m => m.removeEventListener('change', updateSegments));
};
});
investmentCalculator.subscribe((data: IInvestmentCalculator) => {
nominalValue = data.nominalValue;
realValue = data.realValue;
estimatedTaxes = data.estimatedTaxes;
inflationImpact = data.inflationImpact;
managementFees = data.managementFees;
syncValueWidths();
});
const formatCurrency = (value: number) => {
const formatted = new Intl.NumberFormat('en-US', {
style: 'currency',
currency: 'USD',
maximumFractionDigits: 0,
}).format(Math.abs(value));
return value < 0 ? `-${formatted}` : formatted;
};
const getFilledSegments = (value: number) => {
if (!nominalValue) return 0;
return Math.round((Math.abs(value) / nominalValue) * $chartSegments);
};
</script>
<div class="advancedChart">
<div class="advancedChart__row advancedChart__row--main">
<div class="advancedChart__label">{$t('IC.Real Value')}</div>
<div class="advancedChart__data">
<div class="advancedChart__value" title={formatCurrency(realValue)} bind:this={valueElements[0]}>
{formatCurrency(realValue)}
</div>
<div class="advancedChart__bar">
{#each Array($chartSegments) as _, i}
<div
class="advancedChart__segment"
class:filled={i < getFilledSegments(realValue)}
class:gray={true}
></div>
{/each}
</div>
</div>
</div>
<div class="advancedChart__group">
{#each [
{ label: $t('IC.Estimated Taxes'), value: -estimatedTaxes },
{ label: $t('IC.Inflation Impact'), value: -inflationImpact },
{ label: $t('IC.Management Fees'), value: -managementFees },
] as row, i}
<div class="advancedChart__row">
<div class="advancedChart__label">{row.label}</div>
<div class="advancedChart__data">
<div class="advancedChart__value" title={formatCurrency(row.value)} bind:this={valueElements[i + 1]}>
{formatCurrency(row.value)}
</div>
<div class="advancedChart__bar">
{#each Array($chartSegments) as _, j}
<div
class="advancedChart__segment negative"
class:filled={j < getFilledSegments(row.value)}
class:red={true}
></div>
{/each}
</div>
</div>
</div>
{/each}
</div>
</div>
<style lang="scss">
@import 'src/scss/variables';
@import 'src/scss/media';
@import 'src/scss/mixins';
.advancedChart {
width: 100%;
display: flex;
flex-direction: column;
gap: 8px;
&__group {
border: 1px solid #434446;
background-color: #262626;
border-radius: 12px;
padding: 16px;
display: flex;
flex-direction: column;
gap: 16px;
}
&__row {
display: flex;
flex-direction: column;
gap: 8px;
&--main {
margin-bottom: 12px;
}
}
&__data {
display: flex;
gap: 10px;
@include breakpoint-down('tabM') {
flex-direction: column;
}
}
&__label {
font-weight: 400;
font-size: 14px;
line-height: 18px;
color: #f5f5f5;
}
&__value {
max-width: 250px !important;
font-weight: 500;
font-size: 24px;
line-height: 32px;
color: #ffffff;
flex-shrink: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&__bar {
width: 100%;
display: flex;
gap: 4px;
align-items: center;
}
&__segment {
width: calc(100% / 30);
height: 20px;
border-radius: 2px;
background: #616161;
border: 1px solid #FFFFFF54;
&.negative {
background: transparent;
border-radius: 2px;
border: 1px solid transparent;
background: linear-gradient(#262626, #262626) padding-box, linear-gradient(305.13deg, #F96C6E 22.41%, rgba(255, 164, 165, 0.42) 80.51%) border-box;
}
&.gray.filled {
background: #FFFFFF;
}
&.red.filled {
background: #FF3737;
}
}
}
</style>