@kanaries/graphic-walker 0.3.10 → 0.3.12
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/dist/components/appRoot.d.ts +5 -4
- package/dist/graphic-walker.es.js +16100 -15941
- package/dist/graphic-walker.es.js.map +1 -1
- package/dist/graphic-walker.umd.js +120 -120
- package/dist/graphic-walker.umd.js.map +1 -1
- package/dist/interfaces.d.ts +78 -1
- package/dist/renderer/pureRenderer.d.ts +4 -12
- package/dist/utils/chartIndexControl.d.ts +7 -0
- package/dist/utils/vegaApiExport.d.ts +3 -9
- package/package.json +1 -2
- package/src/components/appRoot.tsx +65 -7
- package/src/index.tsx +3 -3
- package/src/interfaces.ts +83 -1
- package/src/renderer/hooks.ts +6 -0
- package/src/renderer/index.tsx +7 -0
- package/src/renderer/pureRenderer.tsx +16 -18
- package/src/utils/chartIndexControl.ts +39 -0
- package/src/utils/vegaApiExport.ts +127 -10
- package/src/vis/react-vega.tsx +31 -11
package/dist/interfaces.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Config as VgConfig } from 'vega';
|
|
1
|
+
import { Config as VgConfig, View } from 'vega';
|
|
2
2
|
import { Config as VlConfig } from 'vega-lite';
|
|
3
3
|
export type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
4
4
|
readonly [K in keyof T]: T[K] extends Record<keyof any, any> ? DeepReadonly<T[K]> : T[K];
|
|
@@ -191,6 +191,16 @@ export declare enum ISegmentKey {
|
|
|
191
191
|
export type IThemeKey = 'vega' | 'g2';
|
|
192
192
|
export type IDarkMode = 'media' | 'light' | 'dark';
|
|
193
193
|
export type VegaGlobalConfig = VgConfig | VlConfig;
|
|
194
|
+
export interface IVegaChartRef {
|
|
195
|
+
x: number;
|
|
196
|
+
y: number;
|
|
197
|
+
w: number;
|
|
198
|
+
h: number;
|
|
199
|
+
innerWidth: number;
|
|
200
|
+
innerHeight: number;
|
|
201
|
+
view: View;
|
|
202
|
+
canvas: HTMLCanvasElement | null;
|
|
203
|
+
}
|
|
194
204
|
export interface IChartExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data-url'> {
|
|
195
205
|
mode: T;
|
|
196
206
|
title: string;
|
|
@@ -201,14 +211,81 @@ export interface IChartExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data
|
|
|
201
211
|
rowIndex: number;
|
|
202
212
|
width: number;
|
|
203
213
|
height: number;
|
|
214
|
+
canvasWidth: number;
|
|
215
|
+
canvasHeight: number;
|
|
204
216
|
data: string;
|
|
217
|
+
canvas(): HTMLCanvasElement | null;
|
|
205
218
|
}[];
|
|
219
|
+
container(): HTMLDivElement | null;
|
|
206
220
|
}
|
|
207
221
|
interface IExportChart {
|
|
208
222
|
<T extends Extract<IChartExportResult['mode'], 'svg'>>(mode?: T): Promise<IChartExportResult<T>>;
|
|
209
223
|
<T extends IChartExportResult['mode']>(mode: T): Promise<IChartExportResult<T>>;
|
|
210
224
|
}
|
|
225
|
+
export interface IChartListExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data-url'> {
|
|
226
|
+
mode: T;
|
|
227
|
+
total: number;
|
|
228
|
+
index: number;
|
|
229
|
+
data: IChartExportResult<T>;
|
|
230
|
+
hasNext: boolean;
|
|
231
|
+
}
|
|
232
|
+
interface IExportChartList {
|
|
233
|
+
<T extends Extract<IChartExportResult['mode'], 'svg'>>(mode?: T): AsyncGenerator<IChartListExportResult<T>, void, unknown>;
|
|
234
|
+
<T extends IChartExportResult['mode']>(mode: T): AsyncGenerator<IChartListExportResult<T>, void, unknown>;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* The status of the current chart.
|
|
238
|
+
* * `computing`: _GraphicWalker_ is computing the data view.
|
|
239
|
+
* * `rendering`: _GraphicWalker_ is rendering the chart.
|
|
240
|
+
* * `idle`: rendering is finished.
|
|
241
|
+
* * `error`: an error occurs during the process above.
|
|
242
|
+
*/
|
|
243
|
+
export type IRenderStatus = 'computing' | 'rendering' | 'idle' | 'error';
|
|
211
244
|
export interface IGWHandler {
|
|
245
|
+
/** length of the "chart" tab list */
|
|
246
|
+
chartCount: number;
|
|
247
|
+
/** current selected chart index */
|
|
248
|
+
chartIndex: number;
|
|
249
|
+
/** Switches to the specified chart */
|
|
250
|
+
openChart: (index: number) => void;
|
|
251
|
+
/**
|
|
252
|
+
* Returns the status of the current chart.
|
|
253
|
+
*
|
|
254
|
+
* It is computed by the following rules:
|
|
255
|
+
* - If _GraphicWalker_ is computing the data view, it returns `computing`.
|
|
256
|
+
* - If _GraphicWalker_ is rendering the chart, it returns `rendering`.
|
|
257
|
+
* - If rendering is finished, it returns `idle`.
|
|
258
|
+
* - If an error occurs during the process above, it returns `error`.
|
|
259
|
+
*/
|
|
260
|
+
get renderStatus(): IRenderStatus;
|
|
261
|
+
/**
|
|
262
|
+
* Registers a callback function to listen to the status change of the current chart.
|
|
263
|
+
*
|
|
264
|
+
* @param {(renderStatus: IRenderStatus) => void} cb - the callback function
|
|
265
|
+
* @returns {() => void} a dispose function to remove this callback
|
|
266
|
+
*/
|
|
267
|
+
onRenderStatusChange: (cb: (renderStatus: IRenderStatus) => void) => (() => void);
|
|
268
|
+
/**
|
|
269
|
+
* Exports the current chart.
|
|
270
|
+
*
|
|
271
|
+
* @param {IChartExportResult['mode']} [mode='svg'] - the export mode, either `svg` or `data-url`
|
|
272
|
+
*/
|
|
212
273
|
exportChart: IExportChart;
|
|
274
|
+
/**
|
|
275
|
+
* Exports all charts.
|
|
276
|
+
*
|
|
277
|
+
* @param {IChartExportResult['mode']} [mode='svg'] - the export mode, either `svg` or `data-url`
|
|
278
|
+
* @returns {AsyncGenerator<IChartListExportResult, void, unknown>} an async generator to iterate over all charts
|
|
279
|
+
* @example
|
|
280
|
+
* ```ts
|
|
281
|
+
* for await (const chart of gwRef.current.exportChartList()) {
|
|
282
|
+
* console.log(chart);
|
|
283
|
+
* }
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
exportChartList: IExportChartList;
|
|
287
|
+
}
|
|
288
|
+
export interface IGWHandlerInsider extends IGWHandler {
|
|
289
|
+
updateRenderStatus: (renderStatus: IRenderStatus) => void;
|
|
213
290
|
}
|
|
214
291
|
export {};
|
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
name?: string;
|
|
6
|
-
themeKey?: IThemeKey;
|
|
7
|
-
dark?: IDarkMode;
|
|
8
|
-
rawData?: IRow[];
|
|
9
|
-
visualState: DraggableFieldState;
|
|
10
|
-
visualConfig: IVisualConfig;
|
|
11
|
-
}
|
|
12
|
-
declare const _default: React.MemoExoticComponent<React.ForwardRefExoticComponent<Pick<IPureRendererProps & React.RefAttributes<IReactVegaHandler>, "key" | keyof IPureRendererProps> & React.RefAttributes<IReactVegaHandler>>>;
|
|
1
|
+
/// <reference types="react" />
|
|
2
|
+
declare const _default: ((props: object) => JSX.Element) & {
|
|
3
|
+
displayName: string;
|
|
4
|
+
};
|
|
13
5
|
export default _default;
|
|
@@ -1,10 +1,4 @@
|
|
|
1
|
-
import { type ForwardedRef, type MutableRefObject } from "react";
|
|
2
|
-
import type { View } from "vega";
|
|
1
|
+
import { type ForwardedRef, type MutableRefObject, RefObject } from "react";
|
|
3
2
|
import type { IReactVegaHandler } from "../vis/react-vega";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
y: number;
|
|
7
|
-
w: number;
|
|
8
|
-
h: number;
|
|
9
|
-
view: View;
|
|
10
|
-
}[]>, ref: ForwardedRef<IReactVegaHandler>) => void;
|
|
3
|
+
import type { IVegaChartRef } from "../interfaces";
|
|
4
|
+
export declare const useVegaExportApi: (name: string | undefined, viewsRef: MutableRefObject<IVegaChartRef[]>, ref: ForwardedRef<IReactVegaHandler>, renderTaskRefs: MutableRefObject<Promise<unknown>[]>, containerRef: RefObject<HTMLDivElement>) => void;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanaries/graphic-walker",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.12",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev:front_end": "vite --host",
|
|
6
6
|
"dev": "npm run dev:front_end",
|
|
@@ -36,7 +36,6 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@headlessui/react": "^1.7.12",
|
|
38
38
|
"@heroicons/react": "^2.0.8",
|
|
39
|
-
"@kanaries/graphic-walker": "0.3.9",
|
|
40
39
|
"@kanaries/react-beautiful-dnd": "0.0.2",
|
|
41
40
|
"@kanaries/web-data-loader": "^0.1.7",
|
|
42
41
|
"autoprefixer": "^10.3.5",
|
|
@@ -1,24 +1,72 @@
|
|
|
1
|
-
import React, { createContext, forwardRef, useImperativeHandle, type ForwardedRef, useContext } from "react";
|
|
2
|
-
import type { IGWHandler } from "../interfaces";
|
|
1
|
+
import React, { createContext, forwardRef, useImperativeHandle, type ForwardedRef, useContext, type ComponentType, type RefObject } from "react";
|
|
2
|
+
import type { IChartExportResult, IGWHandler, IGWHandlerInsider, IRenderStatus } from "../interfaces";
|
|
3
3
|
|
|
4
|
-
const AppRootContext = createContext<ForwardedRef<
|
|
4
|
+
const AppRootContext = createContext<ForwardedRef<IGWHandlerInsider>>(null);
|
|
5
5
|
|
|
6
|
-
export const useAppRootContext = () => {
|
|
7
|
-
|
|
6
|
+
export const useAppRootContext = (): RefObject<IGWHandlerInsider> => {
|
|
7
|
+
const context = useContext(AppRootContext);
|
|
8
|
+
if (context && 'current' in context) {
|
|
9
|
+
return context;
|
|
10
|
+
}
|
|
11
|
+
return {
|
|
12
|
+
current: null,
|
|
13
|
+
};
|
|
8
14
|
};
|
|
9
15
|
|
|
10
|
-
const AppRoot = forwardRef<
|
|
16
|
+
const AppRoot = forwardRef<IGWHandlerInsider, { children: any }>(({ children }, ref) => {
|
|
11
17
|
useImperativeHandle(ref, () => {
|
|
18
|
+
let renderStatus: IRenderStatus = 'idle';
|
|
19
|
+
let onRenderStatusChangeHandlers: ((status: IRenderStatus) => void)[] = [];
|
|
20
|
+
const addRenderStatusChangeListener = (cb: typeof onRenderStatusChangeHandlers[number]): (() => void) => {
|
|
21
|
+
onRenderStatusChangeHandlers.push(cb);
|
|
22
|
+
const dispose = () => {
|
|
23
|
+
onRenderStatusChangeHandlers = onRenderStatusChangeHandlers.filter(which => which !== cb);
|
|
24
|
+
};
|
|
25
|
+
return dispose;
|
|
26
|
+
};
|
|
27
|
+
const updateRenderStatus = (status: IRenderStatus) => {
|
|
28
|
+
if (renderStatus === status) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
renderStatus = status;
|
|
32
|
+
onRenderStatusChangeHandlers.forEach(cb => cb(renderStatus));
|
|
33
|
+
};
|
|
12
34
|
return {
|
|
13
|
-
|
|
35
|
+
get renderStatus() {
|
|
36
|
+
return renderStatus;
|
|
37
|
+
},
|
|
38
|
+
onRenderStatusChange: addRenderStatusChangeListener,
|
|
39
|
+
updateRenderStatus,
|
|
40
|
+
chartCount: 1,
|
|
41
|
+
chartIndex: 0,
|
|
42
|
+
openChart() {},
|
|
43
|
+
exportChart: (async (mode: IChartExportResult['mode'] = 'svg') => {
|
|
14
44
|
return {
|
|
15
45
|
mode,
|
|
16
46
|
title: '',
|
|
17
47
|
nCols: 0,
|
|
18
48
|
nRows: 0,
|
|
19
49
|
charts: [],
|
|
50
|
+
container: () => null,
|
|
20
51
|
};
|
|
21
52
|
}) as IGWHandler['exportChart'],
|
|
53
|
+
exportChartList: (async function * exportChartList (mode: IChartExportResult['mode'] = 'svg') {
|
|
54
|
+
yield {
|
|
55
|
+
mode,
|
|
56
|
+
total: 1,
|
|
57
|
+
completed: 0,
|
|
58
|
+
index: 0,
|
|
59
|
+
data: {
|
|
60
|
+
mode,
|
|
61
|
+
title: '',
|
|
62
|
+
nCols: 0,
|
|
63
|
+
nRows: 0,
|
|
64
|
+
charts: [],
|
|
65
|
+
container: () => null,
|
|
66
|
+
},
|
|
67
|
+
hasNext: false,
|
|
68
|
+
};
|
|
69
|
+
}) as IGWHandler['exportChartList'],
|
|
22
70
|
};
|
|
23
71
|
}, []);
|
|
24
72
|
|
|
@@ -29,4 +77,14 @@ const AppRoot = forwardRef<IGWHandler, { children: any }>(({ children }, ref) =>
|
|
|
29
77
|
);
|
|
30
78
|
});
|
|
31
79
|
|
|
80
|
+
export const withAppRoot = <P extends object>(Component: ComponentType<any>) => {
|
|
81
|
+
return (props: P) => {
|
|
82
|
+
return (
|
|
83
|
+
<AppRoot>
|
|
84
|
+
<Component {...props} />
|
|
85
|
+
</AppRoot>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
32
90
|
export default AppRoot;
|
package/src/index.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { forwardRef } from "react";
|
|
1
|
+
import React, { type ForwardedRef, forwardRef } from "react";
|
|
2
2
|
import { DOM } from "@kanaries/react-beautiful-dnd";
|
|
3
3
|
import { observer } from "mobx-react-lite";
|
|
4
4
|
import App, { IGWProps } from "./App";
|
|
@@ -6,7 +6,7 @@ import { StoreWrapper } from "./store/index";
|
|
|
6
6
|
import { FieldsContextWrapper } from "./fields/fieldsContext";
|
|
7
7
|
import { ShadowDom } from "./shadow-dom";
|
|
8
8
|
import AppRoot from "./components/appRoot";
|
|
9
|
-
import type { IGWHandler } from "./interfaces";
|
|
9
|
+
import type { IGWHandler, IGWHandlerInsider } from "./interfaces";
|
|
10
10
|
|
|
11
11
|
import "./empty_sheet.css";
|
|
12
12
|
|
|
@@ -24,7 +24,7 @@ export const GraphicWalker = observer(forwardRef<IGWHandler, IGWProps>((props, r
|
|
|
24
24
|
|
|
25
25
|
return (
|
|
26
26
|
<StoreWrapper keepAlive={props.keepAlive} storeRef={storeRef}>
|
|
27
|
-
<AppRoot ref={ref}>
|
|
27
|
+
<AppRoot ref={ref as ForwardedRef<IGWHandlerInsider>}>
|
|
28
28
|
<ShadowDom onMount={handleMount} onUnmount={handleUnmount}>
|
|
29
29
|
<FieldsContextWrapper>
|
|
30
30
|
<App {...props} />
|
package/src/interfaces.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {Config as VgConfig} from 'vega';
|
|
1
|
+
import {Config as VgConfig, View} from 'vega';
|
|
2
2
|
import {Config as VlConfig} from 'vega-lite';
|
|
3
3
|
|
|
4
4
|
export type DeepReadonly<T extends Record<keyof any, any>> = {
|
|
@@ -225,6 +225,17 @@ export type IDarkMode = 'media' | 'light' | 'dark';
|
|
|
225
225
|
|
|
226
226
|
export type VegaGlobalConfig = VgConfig | VlConfig;
|
|
227
227
|
|
|
228
|
+
export interface IVegaChartRef {
|
|
229
|
+
x: number;
|
|
230
|
+
y: number;
|
|
231
|
+
w: number;
|
|
232
|
+
h: number;
|
|
233
|
+
innerWidth: number;
|
|
234
|
+
innerHeight: number;
|
|
235
|
+
view: View;
|
|
236
|
+
canvas: HTMLCanvasElement | null;
|
|
237
|
+
}
|
|
238
|
+
|
|
228
239
|
export interface IChartExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data-url'> {
|
|
229
240
|
mode: T;
|
|
230
241
|
title: string;
|
|
@@ -235,8 +246,12 @@ export interface IChartExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data
|
|
|
235
246
|
rowIndex: number;
|
|
236
247
|
width: number;
|
|
237
248
|
height: number;
|
|
249
|
+
canvasWidth: number;
|
|
250
|
+
canvasHeight: number;
|
|
238
251
|
data: string;
|
|
252
|
+
canvas(): HTMLCanvasElement | null;
|
|
239
253
|
}[];
|
|
254
|
+
container(): HTMLDivElement | null;
|
|
240
255
|
}
|
|
241
256
|
|
|
242
257
|
interface IExportChart {
|
|
@@ -244,6 +259,73 @@ interface IExportChart {
|
|
|
244
259
|
<T extends IChartExportResult['mode']>(mode: T): Promise<IChartExportResult<T>>;
|
|
245
260
|
}
|
|
246
261
|
|
|
262
|
+
export interface IChartListExportResult<T extends 'svg' | 'data-url' = 'svg' | 'data-url'> {
|
|
263
|
+
mode: T;
|
|
264
|
+
total: number;
|
|
265
|
+
index: number;
|
|
266
|
+
data: IChartExportResult<T>;
|
|
267
|
+
hasNext: boolean;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
interface IExportChartList {
|
|
271
|
+
<T extends Extract<IChartExportResult['mode'], 'svg'>>(mode?: T): AsyncGenerator<IChartListExportResult<T>, void, unknown>;
|
|
272
|
+
<T extends IChartExportResult['mode']>(mode: T): AsyncGenerator<IChartListExportResult<T>, void, unknown>;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* The status of the current chart.
|
|
277
|
+
* * `computing`: _GraphicWalker_ is computing the data view.
|
|
278
|
+
* * `rendering`: _GraphicWalker_ is rendering the chart.
|
|
279
|
+
* * `idle`: rendering is finished.
|
|
280
|
+
* * `error`: an error occurs during the process above.
|
|
281
|
+
*/
|
|
282
|
+
export type IRenderStatus = 'computing' | 'rendering' | 'idle' | 'error';
|
|
283
|
+
|
|
247
284
|
export interface IGWHandler {
|
|
285
|
+
/** length of the "chart" tab list */
|
|
286
|
+
chartCount: number;
|
|
287
|
+
/** current selected chart index */
|
|
288
|
+
chartIndex: number;
|
|
289
|
+
/** Switches to the specified chart */
|
|
290
|
+
openChart: (index: number) => void;
|
|
291
|
+
/**
|
|
292
|
+
* Returns the status of the current chart.
|
|
293
|
+
*
|
|
294
|
+
* It is computed by the following rules:
|
|
295
|
+
* - If _GraphicWalker_ is computing the data view, it returns `computing`.
|
|
296
|
+
* - If _GraphicWalker_ is rendering the chart, it returns `rendering`.
|
|
297
|
+
* - If rendering is finished, it returns `idle`.
|
|
298
|
+
* - If an error occurs during the process above, it returns `error`.
|
|
299
|
+
*/
|
|
300
|
+
get renderStatus(): IRenderStatus;
|
|
301
|
+
/**
|
|
302
|
+
* Registers a callback function to listen to the status change of the current chart.
|
|
303
|
+
*
|
|
304
|
+
* @param {(renderStatus: IRenderStatus) => void} cb - the callback function
|
|
305
|
+
* @returns {() => void} a dispose function to remove this callback
|
|
306
|
+
*/
|
|
307
|
+
onRenderStatusChange: (cb: (renderStatus: IRenderStatus) => void) => (() => void);
|
|
308
|
+
/**
|
|
309
|
+
* Exports the current chart.
|
|
310
|
+
*
|
|
311
|
+
* @param {IChartExportResult['mode']} [mode='svg'] - the export mode, either `svg` or `data-url`
|
|
312
|
+
*/
|
|
248
313
|
exportChart: IExportChart;
|
|
314
|
+
/**
|
|
315
|
+
* Exports all charts.
|
|
316
|
+
*
|
|
317
|
+
* @param {IChartExportResult['mode']} [mode='svg'] - the export mode, either `svg` or `data-url`
|
|
318
|
+
* @returns {AsyncGenerator<IChartListExportResult, void, unknown>} an async generator to iterate over all charts
|
|
319
|
+
* @example
|
|
320
|
+
* ```ts
|
|
321
|
+
* for await (const chart of gwRef.current.exportChartList()) {
|
|
322
|
+
* console.log(chart);
|
|
323
|
+
* }
|
|
324
|
+
* ```
|
|
325
|
+
*/
|
|
326
|
+
exportChartList: IExportChartList;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export interface IGWHandlerInsider extends IGWHandler {
|
|
330
|
+
updateRenderStatus: (renderStatus: IRenderStatus) => void;
|
|
249
331
|
}
|
package/src/renderer/hooks.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { unstable_batchedUpdates } from 'react-dom';
|
|
|
3
3
|
import type { DeepReadonly, IFilterField, IRow, IViewField } from '../interfaces';
|
|
4
4
|
import { applyFilter, applyViewQuery, transformDataService } from '../services';
|
|
5
5
|
import { getMeaAggKey } from '../utils';
|
|
6
|
+
import { useAppRootContext } from '../components/appRoot';
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
interface UseRendererProps {
|
|
@@ -26,8 +27,11 @@ export const useRenderer = (props: UseRendererProps): UseRendererResult => {
|
|
|
26
27
|
|
|
27
28
|
const [viewData, setViewData] = useState<IRow[]>([]);
|
|
28
29
|
|
|
30
|
+
const appRef = useAppRootContext();
|
|
31
|
+
|
|
29
32
|
useEffect(() => {
|
|
30
33
|
const taskId = ++taskIdRef.current;
|
|
34
|
+
appRef.current?.updateRenderStatus('computing');
|
|
31
35
|
setComputing(true);
|
|
32
36
|
applyFilter(data, filters)
|
|
33
37
|
.then((data) => {
|
|
@@ -53,6 +57,7 @@ export const useRenderer = (props: UseRendererProps): UseRendererResult => {
|
|
|
53
57
|
if (taskId !== taskIdRef.current) {
|
|
54
58
|
return;
|
|
55
59
|
}
|
|
60
|
+
appRef.current?.updateRenderStatus('rendering');
|
|
56
61
|
unstable_batchedUpdates(() => {
|
|
57
62
|
setComputing(false);
|
|
58
63
|
setViewData(data);
|
|
@@ -61,6 +66,7 @@ export const useRenderer = (props: UseRendererProps): UseRendererResult => {
|
|
|
61
66
|
if (taskId !== taskIdRef.current) {
|
|
62
67
|
return;
|
|
63
68
|
}
|
|
69
|
+
appRef.current?.updateRenderStatus('error');
|
|
64
70
|
console.error(err);
|
|
65
71
|
unstable_batchedUpdates(() => {
|
|
66
72
|
setComputing(false);
|
package/src/renderer/index.tsx
CHANGED
|
@@ -8,6 +8,7 @@ import { IReactVegaHandler } from '../vis/react-vega';
|
|
|
8
8
|
import { unstable_batchedUpdates } from 'react-dom';
|
|
9
9
|
import { useRenderer } from './hooks';
|
|
10
10
|
import { initEncoding, initVisualConfig } from '../store/visualSpecStore';
|
|
11
|
+
import { useChartIndexControl } from '../utils/chartIndexControl';
|
|
11
12
|
|
|
12
13
|
interface RendererProps {
|
|
13
14
|
themeKey?: IThemeKey;
|
|
@@ -60,6 +61,12 @@ const Renderer = forwardRef<IReactVegaHandler, RendererProps>(function (props, r
|
|
|
60
61
|
}
|
|
61
62
|
}, [waiting, vizStore]);
|
|
62
63
|
|
|
64
|
+
useChartIndexControl({
|
|
65
|
+
count: visList.length,
|
|
66
|
+
index: visIndex,
|
|
67
|
+
onChange: idx => vizStore.selectVisualization(idx),
|
|
68
|
+
});
|
|
69
|
+
|
|
63
70
|
const handleGeomClick = useCallback(
|
|
64
71
|
(values: any, e: any) => {
|
|
65
72
|
e.stopPropagation();
|
|
@@ -3,7 +3,7 @@ import { unstable_batchedUpdates } from 'react-dom';
|
|
|
3
3
|
import { toJS } from 'mobx';
|
|
4
4
|
import { observer } from 'mobx-react-lite';
|
|
5
5
|
import { ShadowDom } from '../shadow-dom';
|
|
6
|
-
import
|
|
6
|
+
import { withAppRoot } from '../components/appRoot';
|
|
7
7
|
import type { IDarkMode, IViewField, IRow, IThemeKey, DraggableFieldState, IVisualConfig } from '../interfaces';
|
|
8
8
|
import type { IReactVegaHandler } from '../vis/react-vega';
|
|
9
9
|
import SpecRenderer from './specRenderer';
|
|
@@ -79,23 +79,21 @@ const PureRenderer = forwardRef<IReactVegaHandler, IPureRendererProps>(function
|
|
|
79
79
|
}, [waiting]);
|
|
80
80
|
|
|
81
81
|
return (
|
|
82
|
-
<
|
|
83
|
-
<
|
|
84
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
</ShadowDom>
|
|
97
|
-
</AppRoot>
|
|
82
|
+
<ShadowDom>
|
|
83
|
+
<div className="relative">
|
|
84
|
+
<SpecRenderer
|
|
85
|
+
name={name}
|
|
86
|
+
loading={waiting}
|
|
87
|
+
data={viewData}
|
|
88
|
+
ref={ref}
|
|
89
|
+
themeKey={themeKey}
|
|
90
|
+
dark={dark}
|
|
91
|
+
draggableFieldState={visualState}
|
|
92
|
+
visualConfig={visualConfig}
|
|
93
|
+
/>
|
|
94
|
+
</div>
|
|
95
|
+
</ShadowDom>
|
|
98
96
|
);
|
|
99
97
|
});
|
|
100
98
|
|
|
101
|
-
export default observer(PureRenderer);
|
|
99
|
+
export default observer(withAppRoot(PureRenderer));
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { useEffect } from "react";
|
|
2
|
+
import { useAppRootContext } from "../components/appRoot";
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
interface IUseChartIndexControlOptions {
|
|
6
|
+
count: number;
|
|
7
|
+
index: number;
|
|
8
|
+
onChange: (index: number) => void;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const useChartIndexControl = (options: IUseChartIndexControlOptions): void => {
|
|
12
|
+
const appRef = useAppRootContext();
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (appRef.current) {
|
|
16
|
+
appRef.current.chartCount = options.count;
|
|
17
|
+
appRef.current.chartIndex = options.index;
|
|
18
|
+
appRef.current.openChart = function (index: number) {
|
|
19
|
+
if (index === this.chartIndex) {
|
|
20
|
+
return;
|
|
21
|
+
} else if (Number.isInteger(index) && index >= 0 && index < this.chartCount) {
|
|
22
|
+
options.onChange(index);
|
|
23
|
+
} else {
|
|
24
|
+
console.warn(`Invalid chart index: ${index}`);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
return () => {
|
|
32
|
+
if (appRef.current) {
|
|
33
|
+
appRef.current.chartCount = 1;
|
|
34
|
+
appRef.current.chartIndex = 0;
|
|
35
|
+
appRef.current.openChart = () => {};
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}, []);
|
|
39
|
+
};
|