diff --git a/sqlpage/apexcharts.js b/sqlpage/apexcharts.js index b822f9e1..8fad6e29 100644 --- a/sqlpage/apexcharts.js +++ b/sqlpage/apexcharts.js @@ -53,7 +53,7 @@ sqlpage_chart = (() => { /** @typedef {number|string|Date} XValue */ /** @typedef { {x:XValue, y:number|null, z?:number, fillColor?:string} } ChartPoint */ /** @typedef { {name:string, data:ChartPoint[]} } ChartSeries */ - /** @typedef { { [name:string]: ChartSeries } } Series */ + /** @typedef { Map } Series */ /** @param {XValue} x @returns {number|string} equal x values share a key */ const x_key = (x) => (x instanceof Date ? x.getTime() : x); @@ -199,9 +199,11 @@ sqlpage_chart = (() => { const points = data.points.filter(Array.isArray); const reference_rows = data.points.filter((row) => !Array.isArray(row)); /** @type { Series } */ - const series_map = {}; + const series_map = new Map(); for (const [name, old_x, old_y, color, z] of points) { - series_map[name] = series_map[name] || { name, data: [] }; + /** @type {ChartSeries} */ + const point_series = series_map.get(name) ?? { name, data: [] }; + series_map.set(name, point_series); let x = old_x; let y = old_y; if (is_timeseries) { @@ -210,7 +212,7 @@ sqlpage_chart = (() => { y = y.map((y) => new Date(y).getTime()); else x = new Date(x); } - series_map[name].data.push({ x, y, z, fillColor: named_color(color) }); + point_series.data.push({ x, y, z, fillColor: named_color(color) }); } if (data.xmin == null) data.xmin = undefined; if (data.xmax == null) data.xmax = undefined; @@ -224,7 +226,7 @@ sqlpage_chart = (() => { ]; let colors = palette; - let series = Object.values(series_map); + let series = [...series_map.values()]; const xaxis_type = xaxis_type_for( series, chart_type, diff --git a/tests/end-to-end/fixtures/chart/builtin-series-names.sql b/tests/end-to-end/fixtures/chart/builtin-series-names.sql new file mode 100644 index 00000000..c03347f7 --- /dev/null +++ b/tests/end-to-end/fixtures/chart/builtin-series-names.sql @@ -0,0 +1,2 @@ +SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker; +WITH points(series, x, y) AS (VALUES ('toString', 'Q1', 1), ('constructor', 'Q1', 2)) SELECT * FROM points; diff --git a/tests/end-to-end/fixtures/chart/numeric-series-names.sql b/tests/end-to-end/fixtures/chart/numeric-series-names.sql new file mode 100644 index 00000000..cd56fd8e --- /dev/null +++ b/tests/end-to-end/fixtures/chart/numeric-series-names.sql @@ -0,0 +1,2 @@ +SELECT 'chart' AS component, 'test-chart' AS id, 'Chart test fixture' AS title, 'bar' AS type, 4 AS marker; +WITH points(series, x, y) AS (VALUES (2024, 'Q1', 1), (2023, 'Q1', 2), ('total', 'Q1', 3)) SELECT * FROM points; diff --git a/tests/end-to-end/fixtures/chart/test.ts b/tests/end-to-end/fixtures/chart/test.ts index d20553a9..b2cdcba2 100644 --- a/tests/end-to-end/fixtures/chart/test.ts +++ b/tests/end-to-end/fixtures/chart/test.ts @@ -9,7 +9,7 @@ declare global { config: { chart: { type: string; stacked: boolean }; xaxis: { type?: string; tickAmount?: number }; - series: { name: string; data?: ChartPoint[] }[]; + series: { name: string | number; data?: ChartPoint[] }[]; }; globals: { labels: (string | number)[] }; }; @@ -487,6 +487,25 @@ test("keeps the color of the series when a row names a color SQLPage does not kn expect(fills(unknown)).toEqual(fills(plain)); }); +test("renders series named after built-in JavaScript properties", async ({ + page, +}) => { + const chart = await renderChart(page, "builtin-series-names"); + + expect(chart.failures).toEqual([]); + expect(chart.series.map((s) => s.name)).toEqual(["toString", "constructor"]); + expect(chart.shapes).toHaveLength(2); +}); + +test("keeps numeric series names in the order their rows came back in", async ({ + page, +}) => { + const chart = await renderChart(page, "numeric-series-names"); + + expect(chart.failures).toEqual([]); + expect(chart.series.map((s) => s.name)).toEqual([2024, 2023, "total"]); +}); + test("keeps coloring reference lines from their own row", async ({ page }) => { const chart = await renderChart(page, "colored-reference-line");