Correct wordwrapping

This commit is contained in:
Anton Volnuhin 2025-03-19 21:23:47 +03:00
parent cfb07ce1c0
commit b7791e4612

137
app.js
View File

@ -119,6 +119,9 @@ function transformToSunburst(data) {
}
});
// Sort categories by value (largest to smallest)
categories.sort((a, b) => b.value - a.value);
// Convert the map to an array structure for ECharts
const result = [];
@ -134,11 +137,14 @@ function transformToSunburst(data) {
}
};
// Get subcategories and sort by value
const subcategories = [];
for (const subcatKey in category.children) {
subcategories.push(category.children[subcatKey]);
}
subcategories.sort((a, b) => b.value - a.value);
// Process each subcategory
subcategories.forEach(subcategory => {
const subcategoryNode = {
name: subcategory.name,
@ -149,11 +155,14 @@ function transformToSunburst(data) {
}
};
// Get microcategories and sort by value
const microcategories = [];
for (const microKey in subcategory.children) {
microcategories.push(subcategory.children[microKey]);
}
microcategories.sort((a, b) => b.value - a.value);
// Add microcategories to subcategory
microcategories.forEach(micro => {
subcategoryNode.children.push({
name: micro.name,
@ -202,14 +211,12 @@ function renderChart(data) {
center: ['40%', '50%'], // Move chart to the left
nodeClick: 'rootToNode', // To enable drill down on click
data: sunburstData.data,
sort: null, // Use 'null' to maintain the sorting we did in the data transformation
label: {
show: true,
formatter: function(param) {
if (param.depth === 0) {
// Add line breaks for long category names
if (param.name.length > 10) {
return param.name.replace(/(.{1,10})(?: |$)/g, "$1\n").trim();
}
// No word wrapping for top-level categories
return param.name;
} else {
return '';
@ -237,11 +244,14 @@ function renderChart(data) {
lineHeight: 15,
verticalAlign: 'center',
position: 'inside',
formatter: function(param) {
// No special formatting for level 1
return param.name;
}
},
itemStyle: {
borderWidth: 2
}
},
{
// Second level - Subcategories
@ -253,7 +263,61 @@ function renderChart(data) {
align: 'left',
position: 'inside',
distance: 5,
formatter: function(param) {
// If there's only one word, never wrap it
if (!param.name.includes(' ')) {
return param.name;
}
// If the text contains spaces, consider word wrapping for better visibility
const words = param.name.split(' ');
// Skip wrapping for single words or very small sectors
// Estimate sector size from value percentage
if (words.length === 1 || param.percent < 0.03) {
return param.name;
}
// Process words to keep short prepositions (< 4 chars) with the next word
const processedWords = [];
let i = 0;
while (i < words.length) {
if (i < words.length - 1 && words[i].length < 4) {
// Combine short word with the next word
processedWords.push(words[i] + ' ' + words[i+1]);
i += 2;
} else {
processedWords.push(words[i]);
i++;
}
}
// Skip wrapping if we're down to just one processed word
if (processedWords.length === 1) {
return processedWords[0];
}
// If only 2 processed words, put one on each line
if (processedWords.length == 2) {
return processedWords[0] + '\n' + processedWords[1];
}
// If 3 processed words, put each word on its own line
else if (processedWords.length == 3) {
return processedWords[0] + '\n' + processedWords[1] + '\n' + processedWords[2];
}
// For more words, split more aggressively
else if (processedWords.length > 3) {
// Try to create 3 relatively even lines
const part1 = Math.floor(processedWords.length / 3);
const part2 = Math.floor(processedWords.length * 2 / 3);
return processedWords.slice(0, part1).join(' ') + '\n' +
processedWords.slice(part1, part2).join(' ') + '\n' +
processedWords.slice(part2).join(' ');
}
return param.name;
}
},
itemStyle: {
borderWidth: 1
@ -276,9 +340,58 @@ function renderChart(data) {
silent: false,
fontSize: 10,
formatter: function(param) {
if (param.name.length > 10) {
return param.name.slice(0, 8) + '...';
// If there's only one word, never wrap it
if (!param.name.includes(' ')) {
return param.name;
}
// If the text contains spaces, consider word wrapping for better visibility
const words = param.name.split(' ');
// Skip wrapping for single words or very small sectors
// Estimate sector size from value percentage
if (words.length === 1 || param.percent < 0.02) {
return param.name;
}
// Process words to keep short prepositions (< 4 chars) with the next word
const processedWords = [];
let i = 0;
while (i < words.length) {
if (i < words.length - 1 && words[i].length < 4) {
// Combine short word with the next word
processedWords.push(words[i] + ' ' + words[i+1]);
i += 2;
} else {
processedWords.push(words[i]);
i++;
}
}
// Skip wrapping if we're down to just one processed word
if (processedWords.length === 1) {
return processedWords[0];
}
// If only 2 processed words, put one on each line
if (processedWords.length == 2) {
return processedWords[0] + '\n' + processedWords[1];
}
// If 3 processed words, put each word on its own line
else if (processedWords.length == 3) {
return processedWords[0] + '\n' + processedWords[1] + '\n' + processedWords[2];
}
// For more words, split more aggressively
else if (processedWords.length > 3) {
// Try to create 3 relatively even lines
const part1 = Math.floor(processedWords.length / 3);
const part2 = Math.floor(processedWords.length * 2 / 3);
return processedWords.slice(0, part1).join(' ') + '\n' +
processedWords.slice(part1, part2).join(' ') + '\n' +
processedWords.slice(part2).join(' ');
}
return param.name;
}
},
@ -292,8 +405,6 @@ function renderChart(data) {
},
// Add more space between wedges
gap: 2,
// Allow the chart to sort segments by value
sort: null,
tooltip: {
trigger: 'item',
formatter: function(info) {
@ -365,6 +476,9 @@ function renderChart(data) {
}
if (targetData && targetData.children && targetData.children.length > 0) {
// Sort children by value before recoloring
targetData.children.sort((a, b) => b.value - a.value);
// Recolor children with unique colors
targetData.children.forEach((child, i) => {
const color = colorPalette[i % colorPalette.length];
@ -374,6 +488,9 @@ function renderChart(data) {
// If the child has children (microcategories), color them too
if (child.children && child.children.length > 0) {
// Sort microcategories by value
child.children.sort((a, b) => b.value - a.value);
const microColors = generateColorGradient(color, child.children.length);
child.children.forEach((micro, j) => {
micro.itemStyle = {