From c441d5979fe564fe62536e4802486a947e2f089c Mon Sep 17 00:00:00 2001 From: Anton Volnuhin Date: Sun, 1 Feb 2026 15:02:31 +0300 Subject: [PATCH] Improve center label and details box styling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Move center label from ECharts canvas to HTML overlay for better font rendering - Style ₽ symbol separately with lighter color (#888) and slightly smaller size (20px) - Use tighter line height (1.0) for center label - Remove "Детали" heading from details box, use total as header - Remove top border from details header - Increase header font sizes to 20px - Add more whitespace above "Top Items:" Co-Authored-By: Claude Opus 4.5 --- app.js | 61 +++++++++++++++++++++--------------------------------- index.html | 6 +++++- styles.css | 52 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 77 insertions(+), 42 deletions(-) diff --git a/app.js b/app.js index ce8f01b..dc1c7ce 100644 --- a/app.js +++ b/app.js @@ -1,10 +1,21 @@ -// Format RUB amount: no decimals, thin space (U+2009) as thousands separator +// Format RUB amount: no decimals, narrow no-break space as thousands separator function formatRUB(amount) { return Math.round(amount) .toLocaleString('ru-RU') .replace(/\u00a0/g, '\u202F'); } +// Update HTML center label (month in gray, category optional, amount in black) +function updateCenterLabel(month, amount, category = null) { + const labelEl = document.getElementById('center-label'); + if (!labelEl) return; + + labelEl.querySelector('.center-month').textContent = month; + labelEl.querySelector('.center-category').textContent = category || ''; + labelEl.querySelector('.center-amount-num').textContent = formatRUB(amount); + labelEl.querySelector('.center-rub').textContent = '\u202F₽'; +} + // Initialize the chart const chartDom = document.getElementById('chart-container'); const myChart = echarts.init(chartDom); @@ -50,13 +61,8 @@ function navigateToHistoryState(state) { const russianMonth = getRussianMonthName(document.getElementById('month-select').value); option.series.data = state.data; - if (state.contextName) { - option.graphic.elements[0].style.text = `${russianMonth}\n${state.contextName}\n${formatRUB(state.total)}\u202F₽`; - } else { - option.graphic.elements[0].style.text = russianMonth + '\n' + formatRUB(state.total) + '\u202F₽'; - } - myChart.setOption(option, { replaceMerge: ['series'] }); + updateCenterLabel(russianMonth, state.total, state.contextName); setupHoverEvents({ total: state.total, data: state.data }, state.contextName); // Restore drill path and update mini-charts @@ -705,22 +711,7 @@ function renderChart(data) { } }, graphic: { - elements: [ - { - type: 'text', - left: 'center', - top: 'middle', - z: 100, - style: { - text: russianMonth + '\n' + formatRUB(sunburstData.total) + '\u202F₽', - fontFamily: '-apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif', - fontWeight: 'bold', - fontSize: 18, - textAlign: 'left', - fill: '#000' - } - } - ] + elements: [] // Center label is now HTML overlay } }; @@ -914,9 +905,8 @@ function renderChart(data) { // Update the center text to show the drilled-down category const russianMonth = getRussianMonthName(document.getElementById('month-select').value); - option.graphic.elements[0].style.text = `${russianMonth}\n${params.name}\n${formatRUB(params.value)}\u202F₽`; - myChart.setOption(option, { replaceMerge: ['series'] }); + updateCenterLabel(russianMonth, params.value, params.name); // Update hover events with the new data structure, passing the drilled-down name setupHoverEvents({ total: params.value, data: newData }, params.name); @@ -927,7 +917,10 @@ function renderChart(data) { }); myChart.setOption(option); - + + // Update HTML center label + updateCenterLabel(russianMonth, sunburstData.total); + // Add click handler for the center to go back in history const zr = myChart.getZr(); zr.on('click', function(params) { @@ -1685,11 +1678,6 @@ async function selectMonth(index) { // Update the total amount in the center text const russianMonth = getRussianMonthName(month); - if (targetName) { - option.graphic.elements[0].style.text = `${russianMonth}\n${targetName}\n${formatRUB(targetTotal)}\u202F₽`; - } else { - option.graphic.elements[0].style.text = russianMonth + '\n' + formatRUB(targetTotal) + '\u202F₽'; - } myChart.setOption({ series: [{ @@ -1698,13 +1686,14 @@ async function selectMonth(index) { layoutAnimation: true, animationDuration: 500, animationEasing: 'cubicInOut' - }], - graphic: option.graphic + }] }, { lazyUpdate: false, silent: false }); + updateCenterLabel(russianMonth, targetTotal, targetName); + // Update hover events setupHoverEvents({ total: targetTotal, data: targetData }, targetName); @@ -1745,7 +1734,7 @@ function updateMonthNavigator() { // Initialize the visualization async function initVisualization() { await loadAvailableMonths(); - + // Ensure the chart is properly sized on initial load myChart.resize(); } @@ -1780,9 +1769,7 @@ function adjustChartSize() { // Update chart center position option.series.center = [`${centerPosition}%`, '50%']; - option.graphic.elements[0].left = 'center'; - option.graphic.elements[0].top = 'middle'; - + myChart.setOption(option); } diff --git a/index.html b/index.html index 469047e..86fe9f6 100644 --- a/index.html +++ b/index.html @@ -21,6 +21,11 @@
+
+
+
+
+
-

Детали

Hover over a segment to see details diff --git a/styles.css b/styles.css index e43a85c..4444010 100644 --- a/styles.css +++ b/styles.css @@ -140,6 +140,51 @@ body { box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); } +/* Center label overlay */ +.center-label { + position: absolute; + left: 35%; /* Half of chart-container width (70% / 2) */ + top: 50%; + transform: translate(-50%, -50%); + text-align: left; + pointer-events: none; + font-family: -apple-system, BlinkMacSystemFont, "SF Pro", "Segoe UI", system-ui, sans-serif; + z-index: 10; +} + +.center-month { + font-size: 18px; + font-weight: 400; + color: #666; + line-height: 1.0; +} + +.center-category { + font-size: 18px; + font-weight: 600; + color: #333; + line-height: 1.0; +} + +.center-category:empty { + display: none; +} + +.center-amount { + font-size: 22px; + font-weight: 700; + line-height: 1.0; +} + +.center-amount-num { + color: #000; +} + +.center-rub { + color: #888; + font-size: 20px; +} + /* Override ECharts default pointer cursor - only eye button should have pointer */ #chart-container canvas { cursor: default !important; @@ -174,7 +219,7 @@ body { } #details-box h4 { - margin: 10px 0 5px; + margin: 18px 0 5px; color: #555; font-size: 14px; } @@ -186,7 +231,6 @@ body { margin-bottom: 20px; padding: 10px 0; border-bottom: 1px solid #eee; - border-top: 1px solid #eee; } .hover-name { @@ -196,11 +240,11 @@ body { flex: 1; display: flex; align-items: center; - font-size: 16px; + font-size: 20px; } .hover-amount { - font-size: 18px; + font-size: 20px; color: #0066cc; font-weight: bold; margin-left: 10px;