diff --git a/app.js b/app.js index 90be9a2..13e2021 100644 --- a/app.js +++ b/app.js @@ -726,10 +726,13 @@ function renderChart(data) { if (params.data.children && params.data.children.length > 0) { // Case 1: Node has children (category or subcategory) const sortedChildren = sortBySubcategoryOrder(params.data.children, params.name); - - // Process each child + const predefinedOrder = subcategoryOrder[params.name] || []; + + // Process each child, tracking unknown item count for color assignment + let unknownCount = 0; sortedChildren.forEach((child, i) => { - const color = getSubcategoryColor(params.name, child.name, i); + const isUnknown = !predefinedOrder.includes(child.name); + const color = getSubcategoryColor(params.name, child.name, i, isUnknown ? unknownCount++ : null); const newCategory = { name: child.name, value: child.value, @@ -1078,11 +1081,16 @@ for (const category in subcategoryColors) { } // Get color for a subcategory, using fixed mapping or fallback to index-based -function getSubcategoryColor(category, subcategory, index) { +// unknownIndex: for unknown subcategories, pass the count of unknown items before this one +function getSubcategoryColor(category, subcategory, index, unknownIndex = null) { if (subcategoryColors[category] && subcategoryColors[category][subcategory]) { return subcategoryColors[category][subcategory]; } - return defaultColorPalette[index % defaultColorPalette.length]; + // For unknown subcategories, use colors starting after the predefined ones + const predefinedCount = subcategoryOrder[category] ? subcategoryOrder[category].length : 0; + // Use unknownIndex if provided, otherwise calculate from index minus predefined items that might be before + const colorIndex = unknownIndex !== null ? unknownIndex : index; + return defaultColorPalette[(predefinedCount + colorIndex) % defaultColorPalette.length]; } // Sort items by fixed subcategory order, with unknown items at the end sorted by value @@ -1273,14 +1281,20 @@ function generateDrilledDownGradient(monthData, path) { const gradientStops = []; let currentAngle = 0; + const predefinedOrder = parentCategory ? (subcategoryOrder[parentCategory] || []) : []; + let unknownCount = 0; sortedKeys.forEach((key, index) => { const percentage = totals[key] / total; const angle = percentage * 360; // Use fixed subcategory colors for first level, fallback to palette for deeper levels - const color = (level === 'subcategory' && parentCategory) - ? getSubcategoryColor(parentCategory, key, index) - : defaultColorPalette[index % defaultColorPalette.length]; + let color; + if (level === 'subcategory' && parentCategory) { + const isUnknown = !predefinedOrder.includes(key); + color = getSubcategoryColor(parentCategory, key, index, isUnknown ? unknownCount++ : null); + } else { + color = defaultColorPalette[index % defaultColorPalette.length]; + } gradientStops.push(`${color} ${currentAngle}deg ${currentAngle + angle}deg`); currentAngle += angle; @@ -1395,9 +1409,12 @@ async function loadAvailableMonths() { function transformDrillDownData(parentNode, parentCategoryName) { const newData = []; const sortedChildren = sortBySubcategoryOrder(parentNode.children, parentCategoryName); + const predefinedOrder = subcategoryOrder[parentCategoryName] || []; + let unknownCount = 0; sortedChildren.forEach((child, i) => { - const color = getSubcategoryColor(parentCategoryName, child.name, i); + const isUnknown = !predefinedOrder.includes(child.name); + const color = getSubcategoryColor(parentCategoryName, child.name, i, isUnknown ? unknownCount++ : null); const newCategory = { name: child.name, value: child.value, @@ -1618,20 +1635,26 @@ async function selectMonth(index) { if (navigatedState) { // Successfully navigated to (part of) the path + // First save the root state so we can go back to it + saveToHistory(sunburstData.data, sunburstData.total, null, true, []); + targetData = navigatedState.data; targetTotal = navigatedState.total; targetName = navigatedState.contextName; targetPath = navigatedState.path; + + // Save the drilled-down state + saveToHistory(targetData, targetTotal, targetName, false, targetPath); } else { // Stay at root level targetData = sunburstData.data; targetTotal = sunburstData.total; targetName = null; targetPath = []; - } - // Save initial state with the path - saveToHistory(targetData, targetTotal, targetName, true, targetPath); + // Save initial state + saveToHistory(targetData, targetTotal, targetName, true, targetPath); + } // Update the data option.series.data = targetData;