lowcoder-comps 0.0.29 → 0.0.31

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.
Files changed (86) hide show
  1. package/README.md +120 -0
  2. package/index.html +26 -0
  3. package/index.tsx +21 -0
  4. package/jest.config.js +6 -0
  5. package/package.json +3 -4
  6. package/src/__test__/allComp.test.tsx +61 -0
  7. package/src/app-env.d.ts +3 -0
  8. package/src/comps/calendarComp/calendarComp.tsx +633 -0
  9. package/src/comps/calendarComp/calendarConstants.tsx +1048 -0
  10. package/src/comps/calendarComp/errorBoundary.tsx +30 -0
  11. package/src/comps/chartComp/chartComp.tsx +442 -0
  12. package/src/comps/chartComp/chartConfigs/barChartConfig.tsx +51 -0
  13. package/src/comps/chartComp/chartConfigs/cartesianAxisConfig.tsx +307 -0
  14. package/src/comps/chartComp/chartConfigs/chartUrls.tsx +9 -0
  15. package/src/comps/chartComp/chartConfigs/legendConfig.tsx +55 -0
  16. package/src/comps/chartComp/chartConfigs/lineChartConfig.tsx +96 -0
  17. package/src/comps/chartComp/chartConfigs/pieChartConfig.tsx +83 -0
  18. package/src/comps/chartComp/chartConfigs/scatterChartConfig.tsx +62 -0
  19. package/src/comps/chartComp/chartConstants.tsx +299 -0
  20. package/src/comps/chartComp/chartPropertyView.tsx +235 -0
  21. package/src/comps/chartComp/chartUtils.ts +291 -0
  22. package/src/comps/chartComp/reactEcharts/core.tsx +194 -0
  23. package/src/comps/chartComp/reactEcharts/index.ts +21 -0
  24. package/src/comps/chartComp/reactEcharts/types.ts +76 -0
  25. package/src/comps/chartComp/seriesComp.tsx +119 -0
  26. package/src/comps/imageEditorComp/imageEditorClass.tsx +52 -0
  27. package/src/comps/imageEditorComp/imageEditorConstants.tsx +109 -0
  28. package/src/comps/imageEditorComp/index.tsx +184 -0
  29. package/src/comps/mermaidComp/index.tsx +44 -0
  30. package/src/comps/mermaidComp/mermaid.tsx +29 -0
  31. package/src/global.ts +1 -0
  32. package/src/i18n/comps/index.tsx +29 -0
  33. package/src/i18n/comps/locales/en.ts +163 -0
  34. package/src/i18n/comps/locales/enObj.tsx +198 -0
  35. package/src/i18n/comps/locales/index.ts +7 -0
  36. package/src/i18n/comps/locales/types.tsx +10 -0
  37. package/src/i18n/comps/locales/zh.ts +156 -0
  38. package/src/i18n/comps/locales/zhObj.tsx +4 -0
  39. package/src/index.ts +11 -0
  40. package/tsconfig.json +22 -0
  41. package/vite.config.js +10 -0
  42. package/2085da13.js +0 -960
  43. package/250691b5.js +0 -5
  44. package/256b619e.js +0 -92
  45. package/274f545c.js +0 -881
  46. package/289305a1.js +0 -208
  47. package/2eae45c2.js +0 -34
  48. package/2ff2c7a6.js +0 -6
  49. package/2ff7471d.js +0 -9
  50. package/335b22a2.js +0 -220
  51. package/38c826fe.js +0 -1127
  52. package/44011c1d.js +0 -818
  53. package/4fc06812.js +0 -64
  54. package/56a787cf.js +0 -915
  55. package/590941ff.js +0 -86
  56. package/6341867f.js +0 -804
  57. package/657fd065.js +0 -8
  58. package/78a5e50d.js +0 -1579
  59. package/820c3641.js +0 -25
  60. package/88b4e75a.js +0 -2967
  61. package/8d999722.js +0 -1102
  62. package/92e85b65.js +0 -65
  63. package/989caea2.js +0 -505
  64. package/99b984d1.js +0 -237
  65. package/9e5f02d6.js +0 -19104
  66. package/a40faea7.js +0 -11624
  67. package/abac9104.js +0 -1536
  68. package/af2f19b3.js +0 -819
  69. package/af5ee3de.js +0 -268
  70. package/b24707c2.js +0 -48428
  71. package/b68f8b69.js +0 -1276
  72. package/ba68ba65.js +0 -391
  73. package/bafb8599.js +0 -319
  74. package/bba60c35.js +0 -2501
  75. package/bd7c2a8e.js +0 -1089
  76. package/c71dadea.js +0 -455
  77. package/d05c1762.js +0 -933
  78. package/d073ab24.js +0 -134353
  79. package/d838cd10.js +0 -769
  80. package/dc36a6eb.js +0 -796
  81. package/ed143450.js +0 -1284
  82. package/ee8ec8f2.js +0 -2284
  83. package/f6755210.js +0 -1269
  84. package/f9637058.js +0 -16
  85. package/fba4c8e4.js +0 -447
  86. package/index.js +0 -5
@@ -0,0 +1,291 @@
1
+ import {
2
+ CharOptionCompType,
3
+ ChartCompPropsType,
4
+ ChartSize,
5
+ noDataAxisConfig,
6
+ noDataPieChartConfig,
7
+ } from "comps/chartComp/chartConstants";
8
+ import { getPieRadiusAndCenter } from "comps/chartComp/chartConfigs/pieChartConfig";
9
+ import { EChartsOptionWithMap } from "./reactEcharts/types";
10
+ import _ from "lodash";
11
+ import { chartColorPalette, isNumeric, JSONObject, loadScript } from "lowcoder-sdk";
12
+ import { calcXYConfig } from "comps/chartComp/chartConfigs/cartesianAxisConfig";
13
+ import Big from "big.js";
14
+ import { googleMapsApiUrl } from "./chartConfigs/chartUrls";
15
+
16
+ export function transformData(
17
+ originData: JSONObject[],
18
+ xAxis: string,
19
+ seriesColumnNames: string[]
20
+ ) {
21
+ // aggregate data by x-axis
22
+ const transformedData: JSONObject[] = [];
23
+ originData.reduce((prev, cur) => {
24
+ if (cur === null || cur === undefined) {
25
+ return prev;
26
+ }
27
+ const groupValue = cur[xAxis] as string;
28
+ if (!prev[groupValue]) {
29
+ // init as 0
30
+ const initValue: any = {};
31
+ seriesColumnNames.forEach((name) => {
32
+ initValue[name] = 0;
33
+ });
34
+ prev[groupValue] = initValue;
35
+ transformedData.push(prev[groupValue]);
36
+ }
37
+ // remain the x-axis data
38
+ prev[groupValue][xAxis] = groupValue;
39
+ seriesColumnNames.forEach((key) => {
40
+ if (key === xAxis) {
41
+ return;
42
+ } else if (isNumeric(cur[key])) {
43
+ const bigNum = Big(cur[key]);
44
+ prev[groupValue][key] = bigNum.add(prev[groupValue][key]).toNumber();
45
+ } else {
46
+ prev[groupValue][key] += 1;
47
+ }
48
+ });
49
+ return prev;
50
+ }, {} as any);
51
+ return transformedData;
52
+ }
53
+
54
+ const notAxisChartSet: Set<CharOptionCompType> = new Set(["pie"] as const);
55
+ export const echartsConfigOmitChildren = [
56
+ "hidden",
57
+ "selectedPoints",
58
+ "onUIEvent",
59
+ "mapInstance"
60
+ ] as const;
61
+ type EchartsConfigProps = Omit<ChartCompPropsType, typeof echartsConfigOmitChildren[number]>;
62
+
63
+ export function isAxisChart(type: CharOptionCompType) {
64
+ return !notAxisChartSet.has(type);
65
+ }
66
+
67
+ export function getSeriesConfig(props: EchartsConfigProps) {
68
+ const visibleSeries = props.series.filter((s) => !s.getView().hide);
69
+ const seriesLength = visibleSeries.length;
70
+ return visibleSeries.map((s, index) => {
71
+ if (isAxisChart(props.chartConfig.type)) {
72
+ let encodeX: string, encodeY: string;
73
+ const horizontalX = props.xAxisDirection === "horizontal";
74
+ let itemStyle = props.chartConfig.itemStyle;
75
+ // FIXME: need refactor... chartConfig returns a function with paramters
76
+ if (props.chartConfig.type === "bar") {
77
+ // barChart's border radius, depend on x-axis direction and stack state
78
+ const borderRadius = horizontalX ? [2, 2, 0, 0] : [0, 2, 2, 0];
79
+ if (props.chartConfig.stack && index === visibleSeries.length - 1) {
80
+ itemStyle = { ...itemStyle, borderRadius: borderRadius };
81
+ } else if (!props.chartConfig.stack) {
82
+ itemStyle = { ...itemStyle, borderRadius: borderRadius };
83
+ }
84
+ }
85
+ if (horizontalX) {
86
+ encodeX = props.xAxisKey;
87
+ encodeY = s.getView().columnName;
88
+ } else {
89
+ encodeX = s.getView().columnName;
90
+ encodeY = props.xAxisKey;
91
+ }
92
+ return {
93
+ name: s.getView().seriesName,
94
+ selectedMode: "single",
95
+ select: {
96
+ itemStyle: {
97
+ borderColor: "#000",
98
+ },
99
+ },
100
+ encode: {
101
+ x: encodeX,
102
+ y: encodeY,
103
+ },
104
+ // each type of chart's config
105
+ ...props.chartConfig,
106
+ itemStyle: itemStyle,
107
+ label: {
108
+ ...props.chartConfig.label,
109
+ ...(!horizontalX && { position: "outside" }),
110
+ },
111
+ };
112
+ } else {
113
+ // pie
114
+ const radiusAndCenter = getPieRadiusAndCenter(seriesLength, index, props.chartConfig);
115
+ return {
116
+ ...props.chartConfig,
117
+ radius: radiusAndCenter.radius,
118
+ center: radiusAndCenter.center,
119
+ name: s.getView().seriesName,
120
+ selectedMode: "single",
121
+ encode: {
122
+ itemName: props.xAxisKey,
123
+ value: s.getView().columnName,
124
+ },
125
+ };
126
+ }
127
+ });
128
+ }
129
+
130
+ // https://echarts.apache.org/en/option.html
131
+ export function getEchartsConfig(props: EchartsConfigProps, chartSize?: ChartSize): EChartsOptionWithMap {
132
+ if (props.mode === "json") {
133
+ return props.echartsOption ? props.echartsOption : {};
134
+ }
135
+ if(props.mode === "map") {
136
+ const {
137
+ mapZoomLevel,
138
+ mapCenterLat,
139
+ mapCenterLng,
140
+ mapOptions,
141
+ showCharts,
142
+ } = props;
143
+
144
+ const echartsOption = mapOptions && showCharts ? mapOptions : {};
145
+ return {
146
+ gmap: {
147
+ center: [mapCenterLng, mapCenterLat],
148
+ zoom: mapZoomLevel,
149
+ renderOnMoving: true,
150
+ echartsLayerZIndex: showCharts ? 2019 : 0,
151
+ roam: true
152
+ },
153
+ ...echartsOption,
154
+ }
155
+ }
156
+ // axisChart
157
+ const axisChart = isAxisChart(props.chartConfig.type);
158
+ const gridPos = {
159
+ left: 20,
160
+ right: props.legendConfig.left === "right" ? "10%" : 20,
161
+ top: 50,
162
+ bottom: 35,
163
+ };
164
+ let config: EChartsOptionWithMap = {
165
+ title: { text: props.title, left: "center" },
166
+ tooltip: {
167
+ confine: true,
168
+ trigger: axisChart ? "axis" : "item",
169
+ },
170
+ legend: props.legendConfig,
171
+ grid: {
172
+ ...gridPos,
173
+ containLabel: true,
174
+ },
175
+ };
176
+ if (props.data.length <= 0) {
177
+ // no data
178
+ return {
179
+ ...config,
180
+ ...(axisChart ? noDataAxisConfig : noDataPieChartConfig),
181
+ };
182
+ }
183
+ const yAxisConfig = props.yConfig();
184
+ const seriesColumnNames = props.series
185
+ .filter((s) => !s.getView().hide)
186
+ .map((s) => s.getView().columnName);
187
+ // y-axis is category and time, data doesn't need to aggregate
188
+ const transformedData =
189
+ yAxisConfig.type === "category" || yAxisConfig.type === "time"
190
+ ? props.data
191
+ : transformData(props.data, props.xAxisKey, seriesColumnNames);
192
+ config = {
193
+ ...config,
194
+ dataset: [
195
+ {
196
+ source: transformedData,
197
+ sourceHeader: false,
198
+ },
199
+ ],
200
+ series: getSeriesConfig(props),
201
+ };
202
+ if (axisChart) {
203
+ // pure chart's size except the margin around
204
+ let chartRealSize;
205
+ if (chartSize) {
206
+ const rightSize =
207
+ typeof gridPos.right === "number"
208
+ ? gridPos.right
209
+ : (chartSize.w * parseFloat(gridPos.right)) / 100.0;
210
+ chartRealSize = {
211
+ // actually it's self-adaptive with the x-axis label on the left, not that accurate but work
212
+ w: chartSize.w - gridPos.left - rightSize,
213
+ // also self-adaptive on the bottom
214
+ h: chartSize.h - gridPos.top - gridPos.bottom,
215
+ right: rightSize,
216
+ };
217
+ }
218
+ const finalXyConfig = calcXYConfig(
219
+ props.xConfig,
220
+ yAxisConfig,
221
+ props.xAxisDirection,
222
+ transformedData.map((d) => d[props.xAxisKey]),
223
+ chartRealSize
224
+ );
225
+ config = {
226
+ ...config,
227
+ // @ts-ignore
228
+ xAxis: finalXyConfig.xConfig,
229
+ // @ts-ignore
230
+ yAxis: finalXyConfig.yConfig,
231
+ };
232
+ }
233
+ // log.log("Echarts transformedData and config", transformedData, config);
234
+ return config;
235
+ }
236
+
237
+ export function getSelectedPoints(param: any, option: any) {
238
+ const series = option.series;
239
+ const dataSource = _.isArray(option.dataset) && option.dataset[0]?.source;
240
+ if (series && dataSource) {
241
+ return param.selected.flatMap((selectInfo: any) => {
242
+ const seriesInfo = series[selectInfo.seriesIndex];
243
+ if (!seriesInfo || !seriesInfo.encode) {
244
+ return [];
245
+ }
246
+ return selectInfo.dataIndex.map((index: any) => {
247
+ const commonResult = {
248
+ seriesName: seriesInfo.name,
249
+ };
250
+ if (seriesInfo.encode.itemName && seriesInfo.encode.value) {
251
+ return {
252
+ ...commonResult,
253
+ itemName: dataSource[index][seriesInfo.encode.itemName],
254
+ value: dataSource[index][seriesInfo.encode.value],
255
+ };
256
+ } else {
257
+ return {
258
+ ...commonResult,
259
+ x: dataSource[index][seriesInfo.encode.x],
260
+ y: dataSource[index][seriesInfo.encode.y],
261
+ };
262
+ }
263
+ });
264
+ });
265
+ }
266
+ return [];
267
+ }
268
+
269
+ export function loadGoogleMapsScript(apiKey: string) {
270
+ const mapsUrl = `${googleMapsApiUrl}?key=${apiKey}`;
271
+ const scripts = document.getElementsByTagName('script');
272
+ // is script already loaded
273
+ let scriptIndex = _.findIndex(scripts, (script) => script.src.endsWith(mapsUrl));
274
+ if(scriptIndex > -1) {
275
+ return scripts[scriptIndex];
276
+ }
277
+ // is script loaded with diff api_key, remove the script and load again
278
+ scriptIndex = _.findIndex(scripts, (script) => script.src.startsWith(googleMapsApiUrl));
279
+ if(scriptIndex > -1) {
280
+ scripts[scriptIndex].remove();
281
+ }
282
+
283
+ const script = document.createElement("script");
284
+ script.type = "text/javascript";
285
+ script.src = mapsUrl;
286
+ script.async = true;
287
+ script.defer = true;
288
+ window.document.body.appendChild(script);
289
+
290
+ return script;
291
+ }
@@ -0,0 +1,194 @@
1
+ import type { ECharts } from "echarts";
2
+ import { PureComponent } from "react";
3
+ import isEqual from "fast-deep-equal";
4
+ import { EChartsReactProps, EChartsInstance } from "./types";
5
+ import _ from "lodash";
6
+ import log from "loglevel";
7
+
8
+ function isString(v: any): boolean {
9
+ return typeof v === "string";
10
+ }
11
+
12
+ function isFunction(v: any): boolean {
13
+ return typeof v === "function";
14
+ }
15
+
16
+ /**
17
+ * core component for echarts binding
18
+ */
19
+ export default class EChartsReactCore extends PureComponent<EChartsReactProps> {
20
+ /**
21
+ * echarts render container
22
+ */
23
+ public ele: HTMLElement | null;
24
+
25
+ /**
26
+ * echarts library entry
27
+ */
28
+ protected echarts: any;
29
+
30
+ constructor(props: EChartsReactProps) {
31
+ super(props);
32
+
33
+ this.echarts = props.echarts;
34
+ this.ele = null;
35
+ }
36
+
37
+ componentDidMount() {
38
+ this.renderNewEcharts();
39
+ }
40
+
41
+ // update
42
+ componentDidUpdate(prevProps: EChartsReactProps) {
43
+ /**
44
+ * if shouldSetOption return false, then return, not update echarts options
45
+ * default is true
46
+ */
47
+ const { shouldSetOption } = this.props;
48
+ if (shouldSetOption && isFunction(shouldSetOption) && !shouldSetOption(prevProps, this.props)) {
49
+ return;
50
+ }
51
+
52
+ /**
53
+ * the props below need to dispose before re-render
54
+ * 1. when switching theme
55
+ * 2. when modifying opts
56
+ * 3. when modifying onEvents, thus the binded event issue #151 can be cancel
57
+ */
58
+ if (
59
+ !isEqual(prevProps.theme, this.props.theme) ||
60
+ !isEqual(prevProps.opts, this.props.opts) ||
61
+ !isEqual(prevProps.onEvents, this.props.onEvents) ||
62
+ !isEqual(prevProps.mode, this.props.mode)
63
+ // this.props.option.gmap
64
+ ) {
65
+ this.dispose();
66
+
67
+ this.renderNewEcharts(); // re-render
68
+ return;
69
+ }
70
+
71
+ if(this.props.mode === "json") {
72
+ this.updateEChartsOption();
73
+ return;
74
+ }
75
+
76
+ // when these props are not isEqual, update echarts
77
+ const pickKeys = ["option", "notMerge", "lazyUpdate", "showLoading", "loadingOption"];
78
+ if (!isEqual(_.pick(this.props, pickKeys), _.pick(prevProps, pickKeys))) {
79
+ this.updateEChartsOption();
80
+ }
81
+ }
82
+
83
+ componentWillUnmount() {
84
+ this.dispose();
85
+ }
86
+
87
+ /**
88
+ * return the echart object
89
+ * 1. if exist, return the existed instance
90
+ * 2. or new one instance
91
+ */
92
+ public getEchartsInstance(): ECharts {
93
+ return (
94
+ this.echarts.getInstanceByDom(this.ele) ||
95
+ this.echarts.init(this.ele, this.props.theme, this.props.opts)
96
+ );
97
+ }
98
+
99
+ /**
100
+ * dispose echarts and clear size-sensor
101
+ */
102
+ private dispose() {
103
+ if (this.ele) {
104
+ // dispose echarts instance
105
+ this.echarts.dispose(this.ele);
106
+ }
107
+ }
108
+
109
+ /**
110
+ * render a new echarts instance
111
+ */
112
+ private renderNewEcharts() {
113
+ const { onEvents, onChartReady } = this.props;
114
+
115
+ // 1. new echarts instance
116
+ const echartsInstance = this.updateEChartsOption();
117
+
118
+ // 2. bind events
119
+ this.bindEvents(echartsInstance, onEvents || {});
120
+
121
+ // 3. on chart ready
122
+ if (onChartReady && isFunction(onChartReady)) onChartReady(echartsInstance);
123
+ }
124
+
125
+ // bind the events
126
+ private bindEvents(instance: any, events: EChartsReactProps["onEvents"]) {
127
+ function _bindEvent(eventName: string, func: Function) {
128
+ // ignore the event config which not satisfy
129
+ if (isString(eventName) && isFunction(func)) {
130
+ // binding event
131
+ instance.on(eventName, (param: any) => {
132
+ func(param, instance);
133
+ });
134
+ }
135
+ }
136
+
137
+ // loop and bind
138
+ for (const eventName in events) {
139
+ if (Object.prototype.hasOwnProperty.call(events, eventName)) {
140
+ _bindEvent(eventName, events[eventName]);
141
+ }
142
+ }
143
+ }
144
+
145
+ /**
146
+ * render the echarts
147
+ */
148
+ private updateEChartsOption(): EChartsInstance {
149
+ const {
150
+ option,
151
+ notMerge = false,
152
+ lazyUpdate = false,
153
+ showLoading,
154
+ loadingOption = null,
155
+ } = this.props;
156
+ // 1. get or initial the echarts object
157
+ const echartInstance = this.getEchartsInstance();
158
+ // 2. set the echarts option
159
+ try {
160
+ // set option catch exception
161
+ echartInstance.setOption(option, {
162
+ notMerge: notMerge,
163
+ lazyUpdate: lazyUpdate,
164
+ silent: true,
165
+ });
166
+ } catch (e) {
167
+ // FIXME: if don't dispose, setOption again will call cause bugs
168
+ // https://github.com/apache/echarts/issues/16608
169
+ this.dispose();
170
+ log.warn("invalid echarts option:", e);
171
+ }
172
+ // 3. set loading mask
173
+ if (showLoading) echartInstance.showLoading(loadingOption);
174
+ else echartInstance.hideLoading();
175
+
176
+ return echartInstance;
177
+ }
178
+
179
+ render(): JSX.Element {
180
+ const { style, className = "" } = this.props;
181
+ // default height = 300
182
+ const newStyle = { height: 300, ...style };
183
+
184
+ return (
185
+ <div
186
+ ref={(e: HTMLElement | null) => {
187
+ this.ele = e;
188
+ }}
189
+ style={newStyle}
190
+ className={`echarts-for-react ${className}`}
191
+ />
192
+ );
193
+ }
194
+ }
@@ -0,0 +1,21 @@
1
+ import * as echarts from "echarts";
2
+ import "echarts-wordcloud";
3
+ import { EChartsReactProps, EChartsInstance, EChartsOptionWithMap } from "./types";
4
+ import EChartsReactCore from "./core";
5
+
6
+ /**
7
+ * reference: https://github.com/hustcc/echarts-for-react
8
+ * add exception-catch for setOption
9
+ * if query isn't successfully loaded, chart will fail to load and can't reload
10
+ */
11
+ export type { EChartsReactProps, EChartsOptionWithMap, EChartsInstance };
12
+
13
+ // export the Component the echarts Object.
14
+ export default class EChartsReact extends EChartsReactCore {
15
+ constructor(props: EChartsReactProps) {
16
+ super(props);
17
+
18
+ // initialize as echarts package
19
+ this.echarts = echarts;
20
+ }
21
+ }
@@ -0,0 +1,76 @@
1
+ import { CSSProperties } from "react";
2
+ import { EChartsOption } from "echarts";
3
+ import { GoogleMapComponentOption } from "echarts-extension-gmap";
4
+
5
+ export type EChartsOptionWithMap = EChartsOption & GoogleMapComponentOption<any>;
6
+
7
+ export type EChartsInstance = any;
8
+
9
+ export type Opts = {
10
+ readonly devicePixelRatio?: number;
11
+ readonly renderer?: "canvas" | "svg";
12
+ readonly width?: number | null | undefined | "auto";
13
+ readonly height?: number | null | undefined | "auto";
14
+ readonly locale?: string;
15
+ };
16
+
17
+ export type EChartsReactProps = {
18
+ /**
19
+ * echarts library entry, use it for import necessary.
20
+ */
21
+ readonly echarts?: any;
22
+ /**
23
+ * `className` for container
24
+ */
25
+ readonly className?: string;
26
+ /**
27
+ * `style` for container
28
+ */
29
+ readonly style?: CSSProperties;
30
+ /**
31
+ * echarts option
32
+ */
33
+ readonly option: EChartsOptionWithMap;
34
+ /**
35
+ * echarts theme config, can be:
36
+ * 1. theme name string
37
+ * 2. theme object
38
+ */
39
+ readonly theme?: string | Record<string, any>;
40
+ /**
41
+ * notMerge config for echarts, default is `false`
42
+ */
43
+ readonly notMerge?: boolean;
44
+ /**
45
+ * lazyUpdate config for echarts, default is `false`
46
+ */
47
+ readonly lazyUpdate?: boolean;
48
+ /**
49
+ * showLoading config for echarts, default is `false`
50
+ */
51
+ readonly showLoading?: boolean;
52
+ /**
53
+ * loadingOption config for echarts, default is `null`
54
+ */
55
+ readonly loadingOption?: any;
56
+ /**
57
+ * echarts opts config, default is `{}`
58
+ */
59
+ readonly opts?: Opts;
60
+ /**
61
+ * when after chart reander, do the callback widht echarts instance
62
+ */
63
+ readonly onChartReady?: (instance: EChartsInstance) => void;
64
+ /**
65
+ * bind events, default is `{}`
66
+ */
67
+ readonly onEvents?: Record<string, Function>;
68
+ /**
69
+ * should update echarts options
70
+ */
71
+ readonly shouldSetOption?: (prevProps: EChartsReactProps, props: EChartsReactProps) => boolean;
72
+ /**
73
+ * echarts mode: ui | json | map
74
+ */
75
+ readonly mode?: 'ui' | 'json' | 'map'
76
+ };
@@ -0,0 +1,119 @@
1
+ import {
2
+ BoolControl,
3
+ StringControl,
4
+ list,
5
+ JSONObject,
6
+ isNumeric,
7
+ genRandomKey,
8
+ Dropdown,
9
+ OptionsType,
10
+ MultiCompBuilder,
11
+ valueComp,
12
+ } from "lowcoder-sdk";
13
+ import { trans } from "i18n/comps";
14
+
15
+ import { ConstructorToComp, ConstructorToDataType, ConstructorToView } from "lowcoder-core";
16
+ import { CompAction, CustomAction, customAction, isMyCustomAction } from "lowcoder-core";
17
+
18
+ export type SeriesCompType = ConstructorToComp<typeof SeriesComp>;
19
+ export type RawSeriesCompType = ConstructorToView<typeof SeriesComp>;
20
+ type SeriesDataType = ConstructorToDataType<typeof SeriesComp>;
21
+
22
+ type ActionDataType = {
23
+ type: "chartDataChanged";
24
+ chartData: Array<JSONObject>;
25
+ };
26
+
27
+ export function newSeries(name: string, columnName: string): SeriesDataType {
28
+ return {
29
+ seriesName: name,
30
+ columnName: columnName,
31
+ dataIndex: genRandomKey(),
32
+ };
33
+ }
34
+
35
+ const seriesChildrenMap = {
36
+ columnName: StringControl,
37
+ seriesName: StringControl,
38
+ hide: BoolControl,
39
+ // unique key, for sort
40
+ dataIndex: valueComp<string>(""),
41
+ };
42
+
43
+ const SeriesTmpComp = new MultiCompBuilder(seriesChildrenMap, (props) => {
44
+ return props;
45
+ })
46
+ .setPropertyViewFn(() => {
47
+ return <></>;
48
+ })
49
+ .build();
50
+
51
+ class SeriesComp extends SeriesTmpComp {
52
+ getPropertyViewWithData(columnOptions: OptionsType): React.ReactNode {
53
+ return (
54
+ <>
55
+ {this.children.seriesName.propertyView({
56
+ label: trans("chart.seriesName"),
57
+ })}
58
+ <Dropdown
59
+ value={this.children.columnName.getView()}
60
+ options={columnOptions}
61
+ label={trans("chart.dataColumns")}
62
+ onChange={(value) => {
63
+ this.children.columnName.dispatchChangeValueAction(value);
64
+ }}
65
+ />
66
+ </>
67
+ );
68
+ }
69
+ }
70
+
71
+ const SeriesListTmpComp = list(SeriesComp);
72
+
73
+ export class SeriesListComp extends SeriesListTmpComp {
74
+ override reduce(action: CompAction): this {
75
+ if (isMyCustomAction<ActionDataType>(action, "chartDataChanged")) {
76
+ // auto generate series
77
+ const actions = this.genExampleSeriesActions(action.value.chartData);
78
+ return this.reduce(this.multiAction(actions));
79
+ }
80
+ return super.reduce(action);
81
+ }
82
+
83
+ private genExampleSeriesActions(chartData: Array<JSONObject>) {
84
+ const actions: CustomAction[] = [];
85
+ if (!chartData || chartData.length <= 0 || !chartData[0]) {
86
+ return actions;
87
+ }
88
+ let delCnt = 0;
89
+ const existColumns = this.getView().map((s) => s.getView().columnName);
90
+ // delete series not in data
91
+ existColumns.forEach((columnName) => {
92
+ if (chartData[0]?.[columnName] === undefined) {
93
+ actions.push(this.deleteAction(0));
94
+ delCnt++;
95
+ }
96
+ });
97
+ if (existColumns.length > delCnt) {
98
+ // don't generate example if exists
99
+ return actions;
100
+ }
101
+ // generate example series
102
+ const exampleKeys = Object.keys(chartData[0])
103
+ .filter((key) => {
104
+ return !existColumns.includes(key) && isNumeric(chartData[0][key]);
105
+ })
106
+ .slice(0, 3);
107
+ exampleKeys.forEach((key) => actions.push(this.pushAction(newSeries(key, key))));
108
+ return actions;
109
+ }
110
+
111
+ dispatchDataChanged(chartData: Array<JSONObject>): void {
112
+ this.dispatch(
113
+ customAction<ActionDataType>({
114
+ type: "chartDataChanged",
115
+ chartData: chartData,
116
+ })
117
+ );
118
+ }
119
+ }