@gooddata/sdk-ui-charts 11.40.0-alpha.5 → 11.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/NOTICE +664 -360
- package/esm/highcharts/chartTypes/_chartOptions/chartDrilling.d.ts +1 -1
- package/esm/highcharts/chartTypes/_chartOptions/chartDrilling.js +3 -3
- package/esm/highcharts/chartTypes/_chartOptions/chartLimits.js +23 -3
- package/esm/highcharts/chartTypes/_chartOptions/chartOptionsBuilder.js +1 -1
- package/esm/highcharts/constants/limits.d.ts +2 -0
- package/esm/highcharts/constants/limits.js +4 -0
- package/package.json +17 -17
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type DataViewFacade, type IHeaderPredicate, type VisType } from "@gooddata/sdk-ui";
|
|
2
2
|
import { type IUnwrappedAttributeHeadersWithItems } from "../../typings/mess.js";
|
|
3
|
-
export declare function getDrillableSeries(dv: DataViewFacade, series: any[], drillableItems: IHeaderPredicate[], viewByAttributes: (IUnwrappedAttributeHeadersWithItems | undefined | null)[], stackByAttribute: IUnwrappedAttributeHeadersWithItems | undefined | null, type: VisType | undefined, forceDrillIntersection?: boolean): any;
|
|
3
|
+
export declare function getDrillableSeries(dv: DataViewFacade, series: any[], drillableItems: IHeaderPredicate[], viewByAttributes: (IUnwrappedAttributeHeadersWithItems | undefined | null)[], stackByAttribute: IUnwrappedAttributeHeadersWithItems | undefined | null, type: VisType | undefined, forceDrillIntersection?: boolean, isSingleSeriesBubble?: boolean): any;
|
|
@@ -40,7 +40,7 @@ function getStackBy(stackByAttribute, stackByIndex) {
|
|
|
40
40
|
stackByAttributeDescriptor,
|
|
41
41
|
};
|
|
42
42
|
}
|
|
43
|
-
export function getDrillableSeries(dv, series, drillableItems, viewByAttributes, stackByAttribute, type, forceDrillIntersection = false) {
|
|
43
|
+
export function getDrillableSeries(dv, series, drillableItems, viewByAttributes, stackByAttribute, type, forceDrillIntersection = false, isSingleSeriesBubble = false) {
|
|
44
44
|
const [viewByChildAttribute, viewByParentAttribute] = viewByAttributes;
|
|
45
45
|
const isMultiMeasureWithOnlyMeasures = isOneOfTypes(type, multiMeasuresAlternatingTypes) && !viewByChildAttribute;
|
|
46
46
|
const measureGroup = findMeasureGroupInDimensions(dv.meta().dimensions());
|
|
@@ -77,10 +77,10 @@ export function getDrillableSeries(dv, series, drillableItems, viewByAttributes,
|
|
|
77
77
|
measureHeaders = [measureGroup.items[measureIndex]];
|
|
78
78
|
}
|
|
79
79
|
const viewByIndex = isHeatmap(type) || isStackedTreemap ? pointData.x : pointIndex;
|
|
80
|
-
// Scatter
|
|
80
|
+
// Scatter and single-series bubble render one series, so the segment is resolved per point, not by seriesIndex (always 0).
|
|
81
81
|
const stackByIndex = isHeatmap(type) || isStackedTreemap
|
|
82
82
|
? pointData.y
|
|
83
|
-
: isScatterPlot(type)
|
|
83
|
+
: isScatterPlot(type) || isSingleSeriesBubble
|
|
84
84
|
? pointIndex
|
|
85
85
|
: seriesIndex;
|
|
86
86
|
const { stackByHeader, stackByAttributeDescriptor } = getStackBy(stackByAttribute, stackByIndex);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// (C) 2007-2026 GoodData Corporation
|
|
2
2
|
import { VisualizationTypes } from "@gooddata/sdk-ui";
|
|
3
|
-
import { DEFAULT_CATEGORIES_LIMIT, DEFAULT_DATA_POINTS_LIMIT, DEFAULT_SERIES_LIMIT, HEATMAP_DATA_POINTS_LIMIT, PIE_CHART_LIMIT, SANKEY_CHART_DATA_POINT_LIMIT, SANKEY_CHART_NODE_LIMIT, SOFT_DEFAULT_CATEGORIES_LIMIT, SOFT_DEFAULT_DATA_POINTS_LIMIT, SOFT_DEFAULT_SERIES_LIMIT, SOFT_PIE_CHART_LIMIT, SOFT_SANKEY_CHART_DATA_POINT_LIMIT, SOFT_SANKEY_CHART_NODE_LIMIT, SOFT_STACKED_COLUMN_BAR_SERIES_LIMIT, SOFT_WATERFALL_CHART_DATA_POINT_LIMIT, STACKED_COLUMN_BAR_SERIES_LIMIT, WATERFALL_CHART_DATA_POINT_LIMIT, } from "../../constants/limits.js";
|
|
3
|
+
import { COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT, DEFAULT_CATEGORIES_LIMIT, DEFAULT_DATA_POINTS_LIMIT, DEFAULT_SERIES_LIMIT, HEATMAP_DATA_POINTS_LIMIT, PIE_CHART_LIMIT, SANKEY_CHART_DATA_POINT_LIMIT, SANKEY_CHART_NODE_LIMIT, SOFT_COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT, SOFT_DEFAULT_CATEGORIES_LIMIT, SOFT_DEFAULT_DATA_POINTS_LIMIT, SOFT_DEFAULT_SERIES_LIMIT, SOFT_PIE_CHART_LIMIT, SOFT_SANKEY_CHART_DATA_POINT_LIMIT, SOFT_SANKEY_CHART_NODE_LIMIT, SOFT_STACKED_COLUMN_BAR_SERIES_LIMIT, SOFT_WATERFALL_CHART_DATA_POINT_LIMIT, STACKED_COLUMN_BAR_SERIES_LIMIT, WATERFALL_CHART_DATA_POINT_LIMIT, } from "../../constants/limits.js";
|
|
4
4
|
import { isDataOfReasonableSize } from "../_chartCreators/highChartsCreators.js";
|
|
5
5
|
import { isOneOfTypes, isTreemap } from "../_util/common.js";
|
|
6
6
|
import { unsupportedNegativeValuesTypes } from "./chartCapabilities.js";
|
|
@@ -132,6 +132,20 @@ function getTreemapDataForValidation(data) {
|
|
|
132
132
|
})),
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
function isColumnOrBar(type) {
|
|
136
|
+
return type === VisualizationTypes.COLUMN || type === VisualizationTypes.BAR;
|
|
137
|
+
}
|
|
138
|
+
function getTotalDataPoints(data) {
|
|
139
|
+
const series = data?.series;
|
|
140
|
+
if (!Array.isArray(series)) {
|
|
141
|
+
return 0;
|
|
142
|
+
}
|
|
143
|
+
return series.reduce((sum, serie) => sum + (serie.data?.length ?? 0), 0);
|
|
144
|
+
}
|
|
145
|
+
// Total rendered-points cap for column/bar, kept out of IChartLimits and checked alongside isDataOfReasonableSize.
|
|
146
|
+
function exceedsColumnBarTotalDataPoints(type, data, limit) {
|
|
147
|
+
return isColumnOrBar(type) && getTotalDataPoints(data) > limit;
|
|
148
|
+
}
|
|
135
149
|
export function validateData(limits, chartOptions) {
|
|
136
150
|
const type = chartOptions.type;
|
|
137
151
|
const { isViewByTwoAttributes } = chartOptions;
|
|
@@ -142,8 +156,9 @@ export function validateData(limits, chartOptions) {
|
|
|
142
156
|
if (isTreemap(type)) {
|
|
143
157
|
dataToValidate = getTreemapDataForValidation(chartOptions.data);
|
|
144
158
|
}
|
|
159
|
+
const totalDataTooLarge = !limits && exceedsColumnBarTotalDataPoints(type, dataToValidate, COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT);
|
|
145
160
|
return {
|
|
146
|
-
dataTooLarge: !isDataOfReasonableSize(dataToValidate, finalLimits, isViewByTwoAttributes),
|
|
161
|
+
dataTooLarge: totalDataTooLarge || !isDataOfReasonableSize(dataToValidate, finalLimits, isViewByTwoAttributes),
|
|
147
162
|
hasNegativeValue: cannotShowNegativeValues(type) && isNegativeValueIncluded(chartOptions.data?.series),
|
|
148
163
|
};
|
|
149
164
|
}
|
|
@@ -153,7 +168,8 @@ export function getIsFilteringRecommended(chartOptions) {
|
|
|
153
168
|
const dataToValidate = isTreemap(type)
|
|
154
169
|
? getTreemapDataForValidation(chartOptions.data)
|
|
155
170
|
: chartOptions.data;
|
|
156
|
-
return
|
|
171
|
+
return (exceedsColumnBarTotalDataPoints(type, dataToValidate, SOFT_COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT) ||
|
|
172
|
+
!isDataOfReasonableSize(dataToValidate, limits, isViewByTwoAttributes));
|
|
157
173
|
}
|
|
158
174
|
/**
|
|
159
175
|
* Creates a message for onDataTooLarge error, which contains the limits which were exceeded.
|
|
@@ -161,6 +177,7 @@ export function getIsFilteringRecommended(chartOptions) {
|
|
|
161
177
|
export function getDataTooLargeErrorMessage(limits, chartOptions) {
|
|
162
178
|
const { type, isViewByTwoAttributes } = chartOptions;
|
|
163
179
|
const { series: seriesLimit, categories: categoriesLimit, nodes: nodesLimit, dataPoints: dataPointsLimit, } = limits || getChartLimits(type, chartOptions);
|
|
180
|
+
const totalDataPointsLimit = !limits && isColumnOrBar(type) ? COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT : undefined;
|
|
164
181
|
const dataToValidate = isTreemap(type)
|
|
165
182
|
? getTreemapDataForValidation(chartOptions.data)
|
|
166
183
|
: chartOptions.data;
|
|
@@ -194,6 +211,9 @@ export function getDataTooLargeErrorMessage(limits, chartOptions) {
|
|
|
194
211
|
}));
|
|
195
212
|
result.push(limitLog("DataPointsMax", dataPointsLimit, dataPointsMax));
|
|
196
213
|
}
|
|
214
|
+
if (totalDataPointsLimit !== undefined) {
|
|
215
|
+
result.push(limitLog("TotalDataPoints", totalDataPointsLimit, getTotalDataPoints(dataToValidate)));
|
|
216
|
+
}
|
|
197
217
|
return result
|
|
198
218
|
.filter((el) => el !== "")
|
|
199
219
|
.join(" ")
|
|
@@ -221,7 +221,7 @@ export function getChartOptions(dataView, chartConfig, drillableItems, emptyHead
|
|
|
221
221
|
const measureGroup = findMeasureGroupInDimensions(dimensions);
|
|
222
222
|
const yAxes = getYAxes(dv, config, measureGroup, stackByAttribute);
|
|
223
223
|
const seriesWithoutDrillability = getSeries(dv, measureGroup, viewByAttribute, viewByParentAttribute, stackByAttribute, type, colorStrategy, emptyHeaderTitle, theme, config.chartFill, config);
|
|
224
|
-
const drillableSeries = getDrillableSeries(dv, seriesWithoutDrillability, drillableItems, [viewByAttribute, viewByParentAttribute], stackByAttribute, type, config.customTooltip?.enabled ?? false);
|
|
224
|
+
const drillableSeries = getDrillableSeries(dv, seriesWithoutDrillability, drillableItems, [viewByAttribute, viewByParentAttribute], stackByAttribute, type, config.customTooltip?.enabled ?? false, isBubbleChart(type) && (chartConfig?.enableSingleBubbleSeries ?? false));
|
|
225
225
|
let initialSeries = assignYAxes(drillableSeries, yAxes);
|
|
226
226
|
let categories = viewByParentAttribute
|
|
227
227
|
? getCategoriesForTwoAttributes(viewByAttribute, viewByParentAttribute, emptyHeaderTitle)
|
|
@@ -7,6 +7,7 @@ export declare const SANKEY_CHART_NODE_LIMIT = 10000;
|
|
|
7
7
|
export declare const SANKEY_CHART_DATA_POINT_LIMIT = 10000;
|
|
8
8
|
export declare const WATERFALL_CHART_DATA_POINT_LIMIT = 10000;
|
|
9
9
|
export declare const STACKED_COLUMN_BAR_SERIES_LIMIT = 1000;
|
|
10
|
+
export declare const COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT = 6000;
|
|
10
11
|
/**
|
|
11
12
|
* Soft limits are used for checking whether the chart should be recommended to be filtered out
|
|
12
13
|
* due to too many data points.
|
|
@@ -22,3 +23,4 @@ export declare const SOFT_SANKEY_CHART_NODE_LIMIT = 50;
|
|
|
22
23
|
export declare const SOFT_SANKEY_CHART_DATA_POINT_LIMIT = 500;
|
|
23
24
|
export declare const SOFT_WATERFALL_CHART_DATA_POINT_LIMIT = 400;
|
|
24
25
|
export declare const SOFT_STACKED_COLUMN_BAR_SERIES_LIMIT = 50;
|
|
26
|
+
export declare const SOFT_COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT = 2000;
|
|
@@ -10,6 +10,9 @@ export const WATERFALL_CHART_DATA_POINT_LIMIT = 10000;
|
|
|
10
10
|
// Stacked column/bar charts freeze the main thread well before the generic 10k series cap
|
|
11
11
|
// (Highcharts can't draw more than ~1500 stacks), so they need a tighter limit than other chart types.
|
|
12
12
|
export const STACKED_COLUMN_BAR_SERIES_LIMIT = 1000;
|
|
13
|
+
// Column/bar charts render one SVG element per data point, and the point count is categories x series.
|
|
14
|
+
// That total can hang the browser even when neither dimension alone hits its cap, so cap the total too.
|
|
15
|
+
export const COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT = 6000;
|
|
13
16
|
/**
|
|
14
17
|
* Soft limits are used for checking whether the chart should be recommended to be filtered out
|
|
15
18
|
* due to too many data points.
|
|
@@ -25,3 +28,4 @@ export const SOFT_SANKEY_CHART_NODE_LIMIT = 50;
|
|
|
25
28
|
export const SOFT_SANKEY_CHART_DATA_POINT_LIMIT = 500;
|
|
26
29
|
export const SOFT_WATERFALL_CHART_DATA_POINT_LIMIT = 400;
|
|
27
30
|
export const SOFT_STACKED_COLUMN_BAR_SERIES_LIMIT = 50;
|
|
31
|
+
export const SOFT_COLUMN_BAR_TOTAL_DATA_POINTS_LIMIT = 2000;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-charts",
|
|
3
|
-
"version": "11.40.0
|
|
3
|
+
"version": "11.40.0",
|
|
4
4
|
"description": "GoodData.UI SDK - Charts",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -69,13 +69,13 @@
|
|
|
69
69
|
"ts-invariant": "0.10.3",
|
|
70
70
|
"tslib": "2.8.1",
|
|
71
71
|
"uuid": "11.1.0",
|
|
72
|
-
"@gooddata/sdk-backend-spi": "11.40.0
|
|
73
|
-
"@gooddata/sdk-
|
|
74
|
-
"@gooddata/sdk-
|
|
75
|
-
"@gooddata/sdk-ui-theme-provider": "11.40.0
|
|
76
|
-
"@gooddata/sdk-ui-kit": "11.40.0
|
|
77
|
-
"@gooddata/
|
|
78
|
-
"@gooddata/
|
|
72
|
+
"@gooddata/sdk-backend-spi": "11.40.0",
|
|
73
|
+
"@gooddata/sdk-ui": "11.40.0",
|
|
74
|
+
"@gooddata/sdk-model": "11.40.0",
|
|
75
|
+
"@gooddata/sdk-ui-theme-provider": "11.40.0",
|
|
76
|
+
"@gooddata/sdk-ui-kit": "11.40.0",
|
|
77
|
+
"@gooddata/util": "11.40.0",
|
|
78
|
+
"@gooddata/sdk-ui-vis-commons": "11.40.0"
|
|
79
79
|
},
|
|
80
80
|
"devDependencies": {
|
|
81
81
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -93,7 +93,7 @@
|
|
|
93
93
|
"@typescript-eslint/eslint-plugin": "8.58.0",
|
|
94
94
|
"@typescript-eslint/parser": "8.58.0",
|
|
95
95
|
"@typescript/native-preview": "7.0.0-dev.20260202.1",
|
|
96
|
-
"@vitest/eslint-plugin": "1.6.
|
|
96
|
+
"@vitest/eslint-plugin": "1.6.19",
|
|
97
97
|
"dependency-cruiser": "17.3.10",
|
|
98
98
|
"eslint": "^9.39.2",
|
|
99
99
|
"eslint-import-resolver-typescript": "4.4.4",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
"eslint-plugin-react-hooks": "5.2.0",
|
|
108
108
|
"eslint-plugin-sonarjs": "3.0.6",
|
|
109
109
|
"full-icu": "^1.3.0",
|
|
110
|
-
"happy-dom": "
|
|
110
|
+
"happy-dom": "20.9.0",
|
|
111
111
|
"npm-run-all": "^4.1.5",
|
|
112
112
|
"oxfmt": "0.52.0",
|
|
113
113
|
"oxlint": "1.51.0",
|
|
@@ -120,11 +120,11 @@
|
|
|
120
120
|
"typescript": "5.9.3",
|
|
121
121
|
"vitest": "4.1.8",
|
|
122
122
|
"vitest-dom": "0.1.1",
|
|
123
|
-
"@gooddata/eslint-config": "11.40.0
|
|
124
|
-
"@gooddata/oxlint-config": "11.40.0
|
|
125
|
-
"@gooddata/reference-workspace": "11.40.0
|
|
126
|
-
"@gooddata/sdk-backend-mockingbird": "11.40.0
|
|
127
|
-
"@gooddata/stylelint-config": "11.40.0
|
|
123
|
+
"@gooddata/eslint-config": "11.40.0",
|
|
124
|
+
"@gooddata/oxlint-config": "11.40.0",
|
|
125
|
+
"@gooddata/reference-workspace": "11.40.0",
|
|
126
|
+
"@gooddata/sdk-backend-mockingbird": "11.40.0",
|
|
127
|
+
"@gooddata/stylelint-config": "11.40.0"
|
|
128
128
|
},
|
|
129
129
|
"peerDependencies": {
|
|
130
130
|
"react": "^18.0.0 || ^19.0.0",
|
|
@@ -142,8 +142,8 @@
|
|
|
142
142
|
"dep-cruiser": "depcruise --validate .dependency-cruiser.js --output-type err-long src/",
|
|
143
143
|
"format-check": "oxfmt --check .",
|
|
144
144
|
"format-write": "oxfmt .",
|
|
145
|
-
"lint": "oxlint . --
|
|
146
|
-
"lint-fix": "oxlint . --
|
|
145
|
+
"lint": "oxlint . --quiet && eslint .",
|
|
146
|
+
"lint-fix": "oxlint . --quiet --fix && eslint . --fix",
|
|
147
147
|
"scss": "sass --load-path=node_modules styles/scss:styles/css",
|
|
148
148
|
"stylelint": "stylelint '**/*.scss'",
|
|
149
149
|
"stylelint-fix": "stylelint '**/*.scss' --fix",
|