43 lines
2.9 KiB
JavaScript
43 lines
2.9 KiB
JavaScript
(() => {
|
||
const modal = document.querySelector('#detailModal');
|
||
const viewport = document.querySelector('#modalViewport');
|
||
const renderCharts = root => root.querySelectorAll('[data-chart]').forEach(host => {
|
||
if (host.dataset.rendered) return;
|
||
host.dataset.rendered = 'true';
|
||
const data = JSON.parse(host.dataset.chart);
|
||
const render = (title, series, color, unit = 'тыс. руб.') => {
|
||
const width = 520, height = 252, pad = {l: 42, r: 18, t: 18, b: 36};
|
||
const values = series.map(item => item.value), maximum = Math.max(...values) * 1.15, minimum = Math.min(0, ...values) * .85;
|
||
const x = index => pad.l + index * ((width - pad.l - pad.r) / Math.max(1, series.length - 1));
|
||
const y = value => pad.t + (maximum - value) / (maximum - minimum || 1) * (height - pad.t - pad.b);
|
||
const points = series.map((item, index) => `${x(index)},${y(item.value)}`).join(' ');
|
||
const area = `${pad.l},${height - pad.b} ${points} ${x(series.length - 1)},${height - pad.b}`;
|
||
const grid = [0, .25, .5, .75, 1].map(t => { const yy = pad.t + t * (height - pad.t - pad.b); return `<line class="grid-line" x1="${pad.l}" y1="${yy}" x2="${width-pad.r}" y2="${yy}"/>`; }).join('');
|
||
const labels = series.map((item, index) => `<text class="chart-label" x="${x(index)}" y="${height-12}" text-anchor="middle">${item.year}</text>`).join('');
|
||
const dots = series.map((item, index) => `<circle class="chart-point" cx="${x(index)}" cy="${y(item.value)}" r="5"><title>${item.year}: ${item.value.toLocaleString('ru-RU')} ${unit}</title></circle>`).join('');
|
||
return `<article class="line-chart" style="--chart:${color}"><h3>${title}</h3><svg viewBox="0 0 ${width} ${height}" role="img" aria-label="${title}">${grid}<polygon class="chart-area" points="${area}"/><polyline class="chart-line" points="${points}"/>${dots}${labels}</svg></article>`;
|
||
};
|
||
if (data.employees) {
|
||
host.innerHTML = render('Динамика численности', data.employees, '#BE7AB9', data.unit || 'чел.');
|
||
return;
|
||
}
|
||
const unit = data.unit || 'тыс. руб.';
|
||
host.innerHTML = render(`Выручка, ${unit}`, data.income, '#73b8e5', unit) + render(`Чистая прибыль, ${unit}`, data.profit, '#55bd79', unit);
|
||
});
|
||
document.addEventListener('click', event => {
|
||
const trigger = event.target.closest('.detail-button');
|
||
if (trigger) {
|
||
const template = document.querySelector(`#${CSS.escape(trigger.dataset.modalSource)}`);
|
||
if (!template) return;
|
||
viewport.replaceChildren(template.content.cloneNode(true));
|
||
renderCharts(viewport);
|
||
modal.showModal();
|
||
return;
|
||
}
|
||
if (event.target.closest('.modal-close')) modal.close();
|
||
if (event.target === modal) modal.close();
|
||
});
|
||
document.addEventListener('keydown', event => { if (event.key === 'Escape' && modal?.open) modal.close(); });
|
||
renderCharts(document);
|
||
})();
|