Skip to content

Commit ca00eaa

Browse files
committed
chart item ordering
fixes https://github.com/sqlpage/SQLPage/discussions/930Preserve original category order for bar charts Single-series bar charts now retain their original data point order. For multi-series bar charts, categories are aligned and ordered by their first appearance in the data, instead of alphabetically.
1 parent d0e493f commit ca00eaa

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

sqlpage/apexcharts.js

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -39,36 +39,48 @@ sqlpage_chart = (() => {
3939

4040
/**
4141
* Aligns series data points by their x-axis categories, ensuring all series have data points
42-
* for each unique category. Missing values are filled with zeros. Categories are sorted.
42+
* for each unique category. Missing values are filled with zeros.
43+
* Categories are ordered by their first appearance across all series.
4344
*
4445
* @example
4546
* // Input series:
4647
* const series = [
47-
* { name: "A", data: [{x: "Jan", y: 10}, {x: "Mar", y: 30}] },
48-
* { name: "B", data: [{x: "Jan", y: 20}, {x: "Feb", y: 25}] }
48+
* { name: "A", data: [{x: "X2", y: 10}, {x: "X3", y: 30}] },
49+
* { name: "B", data: [{x: "X1", y: 25}, {x: "X2", y: 20}] }
4950
* ];
5051
*
51-
* // Output after align_categories:
52+
* // Output after align_categories (orderedCategories will be ["X2", "X3", "X1"]):
5253
* // [
53-
* // { name: "A", data: [{x: "Feb", y: 0}, {x: "Jan", y: 10}, {x: "Mar", y: 30}] },
54-
* // { name: "B", data: [{x: "Feb", y: 25}, {x: "Jan", y: 20}, {x: "Mar", y: 0}] }
54+
* // { name: "A", data: [{x: "X2", y: 10}, {x: "X3", y: 30}, {x: "X1", y: 0}] },
55+
* // { name: "B", data: [{x: "X2", y: 20}, {x: "X3", y: 0}, {x: "X1", y: 25}] }
5556
* // ]
5657
*
57-
* @param {Series[string][]} series - Array of series objects, each containing name and data points
58+
* @param {(Series[string])[]} series - Array of series objects, each containing name and data points
5859
* @returns {Series[string][]} Aligned series with consistent categories across all series
5960
*/
6061
function align_categories(series) {
61-
// Collect all unique categories
62-
const categories = new Set(series.flatMap((s) => s.data.map((p) => p.x)));
63-
const sortedCategories = Array.from(categories).sort();
64-
65-
// Create a map of category -> value for each series
62+
const categoriesSet = new Set();
63+
const pointers = series.map((_) => 0);
64+
while (true) {
65+
const series_idxs = series.flatMap((series, i) =>
66+
pointers[i] < series.data.length ? [i] : [],
67+
);
68+
if (series_idxs.length === 0) break;
69+
const min_ptr = Math.min(...series_idxs.map((i) => pointers[i]));
70+
const min_series_idx =
71+
series_idxs.find((i) => pointers[i] === min_ptr) | 0;
72+
const min_series = series[min_series_idx];
73+
const min_point = min_series.data[min_ptr];
74+
const new_category = min_point.x;
75+
if (!categoriesSet.has(new_category)) categoriesSet.add(new_category);
76+
pointers[min_series_idx]++;
77+
}
78+
// Create a map of category -> value for each series and rebuild
6679
return series.map((s) => {
6780
const valueMap = new Map(s.data.map((point) => [point.x, point.y]));
68-
6981
return {
7082
name: s.name,
71-
data: sortedCategories.map((category) => ({
83+
data: Array.from(categoriesSet, (category) => ({
7284
x: category,
7385
y: valueMap.get(category) || 0,
7486
})),
@@ -116,7 +128,7 @@ sqlpage_chart = (() => {
116128
if (data.type === "pie") {
117129
labels = data.points.map(([name, x, y]) => x || name);
118130
series = data.points.map(([name, x, y]) => y);
119-
} else if (categories && data.type === "bar")
131+
} else if (categories && data.type === "bar" && series.length > 1)
120132
series = align_categories(series);
121133

122134
const chart_type = data.type || "line";

0 commit comments

Comments
 (0)