Improve responsive chart scaling and hide center label earlier
- Scale chart layers on mobile (≤500px) to fill container while keeping same hole size as desktop (20%) - Add resize handler to dynamically update proportions when crossing 500px threshold - Hide center label at 850px (stacked layout) instead of 500px to prevent overlap with chart - Center chart at 50% on mobile since details box is below Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
2b45a42b49
commit
d76e80dc02
96
app.js
96
app.js
@ -462,7 +462,7 @@ function renderChart(data) {
|
||||
// Calculate the correct center position first
|
||||
const screenWidth = window.innerWidth;
|
||||
let centerPosition;
|
||||
|
||||
|
||||
if (screenWidth >= 1000) {
|
||||
// For screens 1000px and wider, keep centered at 50%
|
||||
centerPosition = 50;
|
||||
@ -470,11 +470,25 @@ function renderChart(data) {
|
||||
// Gradual transition between 640-1000px
|
||||
const transitionProgress = (screenWidth - 640) / 360; // 0 to 1
|
||||
centerPosition = 40 + (transitionProgress * 10); // 40 to 50
|
||||
} else if (screenWidth <= 500) {
|
||||
// Mobile: center the chart since details box is below
|
||||
centerPosition = 50;
|
||||
} else {
|
||||
// For smaller screens
|
||||
// For smaller screens (500-640px)
|
||||
centerPosition = 40;
|
||||
}
|
||||
|
||||
|
||||
// Mobile: scale chart to fill container, hide outside labels
|
||||
const isMobile = screenWidth <= 500;
|
||||
|
||||
// Mobile: extend layers to fill container, keeping same hole size as desktop
|
||||
// Hole stays at 20%, layers scaled to fill remaining 80% (vs 55% on desktop)
|
||||
const level1Inner = '20%';
|
||||
const level1Outer = isMobile ? '56%' : '45%';
|
||||
const level2Outer = isMobile ? '93%' : '70%';
|
||||
const level3Outer = isMobile ? '100%' : '75%';
|
||||
const outerRadius = isMobile ? '100%' : '95%';
|
||||
|
||||
option = {
|
||||
backgroundColor: '#fff',
|
||||
grid: {
|
||||
@ -489,7 +503,7 @@ function renderChart(data) {
|
||||
//animationEasingUpdate: 'cubicInOut',
|
||||
series: {
|
||||
type: 'sunburst',
|
||||
radius: [0, '95%'],
|
||||
radius: [0, outerRadius],
|
||||
center: [`${centerPosition}%`, '50%'],
|
||||
startAngle: 0,
|
||||
nodeClick: false,
|
||||
@ -518,8 +532,8 @@ function renderChart(data) {
|
||||
{},
|
||||
{
|
||||
// First level - Categories
|
||||
r0: '20%',
|
||||
r: '45%',
|
||||
r0: level1Inner,
|
||||
r: level1Outer,
|
||||
label: {
|
||||
show: true,
|
||||
rotate: 'radial',
|
||||
@ -538,8 +552,8 @@ function renderChart(data) {
|
||||
},
|
||||
{
|
||||
// Second level - Subcategories
|
||||
r0: '45%',
|
||||
r: '70%',
|
||||
r0: level1Outer,
|
||||
r: level2Outer,
|
||||
label: {
|
||||
show: function(param) {
|
||||
// Show labels for sectors that are at least 5% of the total
|
||||
@ -617,16 +631,17 @@ function renderChart(data) {
|
||||
}
|
||||
},
|
||||
{
|
||||
// Third level - Microcategories - a bit wider than before
|
||||
r0: '70%',
|
||||
r: '75%',
|
||||
// Third level - Microcategories
|
||||
r0: level2Outer,
|
||||
r: level3Outer,
|
||||
label: {
|
||||
// Only show labels conditionally based on segment size
|
||||
show: function(param) {
|
||||
// On mobile, hide outside labels to maximize chart size
|
||||
show: isMobile ? false : function(param) {
|
||||
// Show label if segment is wide enough (>1%)
|
||||
return param.percent > 0.000;
|
||||
},
|
||||
position: 'outside',
|
||||
position: isMobile ? 'inside' : 'outside',
|
||||
padding: 3,
|
||||
minAngle: 3, // Add this - default is 5, reducing it will show more labels
|
||||
silent: false,
|
||||
@ -1754,18 +1769,53 @@ window.addEventListener('resize', function() {
|
||||
function adjustChartSize() {
|
||||
// Check if option is defined
|
||||
if (!option) return;
|
||||
|
||||
|
||||
const screenWidth = window.innerWidth;
|
||||
const detailsBox = document.getElementById('details-box');
|
||||
const detailsWidth = detailsBox.offsetWidth;
|
||||
|
||||
// Calculate center position with a smooth transition
|
||||
const isMobile = screenWidth <= 500;
|
||||
|
||||
// Mobile: extend layers to fill container, keeping same hole size as desktop
|
||||
// Hole stays at 20%, layers scaled to fill remaining 80% (vs 55% on desktop)
|
||||
const level1Inner = '20%';
|
||||
const level1Outer = isMobile ? '56%' : '45%';
|
||||
const level2Outer = isMobile ? '93%' : '70%';
|
||||
const level3Outer = isMobile ? '100%' : '75%';
|
||||
const outerRadius = isMobile ? '100%' : '95%';
|
||||
|
||||
// Update layer proportions
|
||||
option.series.levels[1].r0 = level1Inner;
|
||||
option.series.levels[1].r = level1Outer;
|
||||
option.series.levels[2].r0 = level1Outer;
|
||||
option.series.levels[2].r = level2Outer;
|
||||
option.series.levels[3].r0 = level2Outer;
|
||||
option.series.levels[3].r = level3Outer;
|
||||
option.series.radius = [0, outerRadius];
|
||||
|
||||
// Update level 3 labels: hide on mobile, show on desktop (with conditions)
|
||||
if (isMobile) {
|
||||
option.series.levels[3].label.show = false;
|
||||
option.series.levels[3].label.position = 'inside';
|
||||
} else if (screenWidth < 950) {
|
||||
option.series.levels[3].label.show = false;
|
||||
option.series.levels[3].label.position = 'outside';
|
||||
} else {
|
||||
option.series.levels[3].label.show = function(param) {
|
||||
return param.percent > 0.000;
|
||||
};
|
||||
option.series.levels[3].label.position = 'outside';
|
||||
}
|
||||
|
||||
// Calculate center position
|
||||
let centerPosition;
|
||||
|
||||
if (screenWidth < 950)
|
||||
option.series.levels[3].label.show=false;
|
||||
else option.series.levels[3].label.show=true;
|
||||
centerPosition = 50;
|
||||
if (screenWidth >= 1000) {
|
||||
centerPosition = 50;
|
||||
} else if (screenWidth >= 640) {
|
||||
const transitionProgress = (screenWidth - 640) / 360;
|
||||
centerPosition = 40 + (transitionProgress * 10);
|
||||
} else if (isMobile) {
|
||||
centerPosition = 50;
|
||||
} else {
|
||||
centerPosition = 40;
|
||||
}
|
||||
|
||||
// Update chart center position
|
||||
option.series.center = [`${centerPosition}%`, '50%'];
|
||||
|
||||
16
styles.css
16
styles.css
@ -359,6 +359,10 @@ body {
|
||||
.top-item-amount {
|
||||
min-width: 80px;
|
||||
}
|
||||
|
||||
.center-label {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
@ -394,10 +398,6 @@ body {
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.center-label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
padding: 15px 10px;
|
||||
}
|
||||
@ -405,6 +405,12 @@ body {
|
||||
.chart-wrapper {
|
||||
height: 95vw;
|
||||
}
|
||||
|
||||
#chart-container {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
border-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 400px) {
|
||||
@ -432,7 +438,7 @@ body {
|
||||
}
|
||||
|
||||
.chart-wrapper {
|
||||
height: 98vw;
|
||||
height: 100vw;
|
||||
}
|
||||
|
||||
.details-header {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user