@carto/ps-react-ui 4.3.6 → 4.3.7
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.js +123 -123
- package/dist/components.js.map +1 -1
- package/dist/error-CEkRPccv.js +39 -0
- package/dist/error-CEkRPccv.js.map +1 -0
- package/dist/{lasso-tool-BctzdzBu.js → lasso-tool-jl4YK02H.js} +19 -19
- package/dist/lasso-tool-jl4YK02H.js.map +1 -0
- package/dist/no-data-hR3KcJ-_.js +60 -0
- package/dist/no-data-hR3KcJ-_.js.map +1 -0
- package/dist/{row-D3uVFImu.js → row-BKmVAUN5.js} +2 -2
- package/dist/{row-D3uVFImu.js.map → row-BKmVAUN5.js.map} +1 -1
- package/dist/{series-BAImrSBo.js → series-D1pynfeh.js} +3 -3
- package/dist/{series-BAImrSBo.js.map → series-D1pynfeh.js.map} +1 -1
- package/dist/{styles-CCZnY17y.js → styles-DrPyd0y5.js} +28 -22
- package/dist/styles-DrPyd0y5.js.map +1 -0
- package/dist/types/components/lasso-tool/types.d.ts +1 -1
- package/dist/types/widgets/_shared/chart-config/index.d.ts +1 -1
- package/dist/types/widgets/_shared/chart-config/option-builders.d.ts +7 -0
- package/dist/types/widgets/_shared/chart-config/option-builders.test.d.ts +1 -0
- package/dist/types/widgets/actions/index.d.ts +2 -2
- package/dist/types/widgets/actions/lock-selection/types.d.ts +0 -13
- package/dist/types/widgets/actions/relative-data/types.d.ts +0 -4
- package/dist/types/widgets/actions/searcher/types.d.ts +0 -2
- package/dist/types/widgets/actions/stack-toggle/types.d.ts +0 -4
- package/dist/types/widgets/echart/types.d.ts +0 -4
- package/dist/types/widgets/echart/utils.d.ts +2 -1
- package/dist/types/widgets/error/error.d.ts +1 -1
- package/dist/types/widgets/error/types.d.ts +8 -0
- package/dist/types/widgets/loader/loader.d.ts +1 -1
- package/dist/types/widgets/loader/types.d.ts +1 -1
- package/dist/types/widgets/stores/types.d.ts +1 -1
- package/dist/{use-widget-ref-B8x4sHIj.js → use-widget-ref-P-2i0MJG.js} +2 -2
- package/dist/{use-widget-ref-B8x4sHIj.js.map → use-widget-ref-P-2i0MJG.js.map} +1 -1
- package/dist/{utils-D3-eQyDR.js → utils-idmvq0Oa.js} +17 -16
- package/dist/utils-idmvq0Oa.js.map +1 -0
- package/dist/{widget-store-Dn0Bnc4h.js → widget-store-CzDt8oSK.js} +31 -46
- package/dist/widget-store-CzDt8oSK.js.map +1 -0
- package/dist/widgets/actions.js +690 -716
- package/dist/widgets/actions.js.map +1 -1
- package/dist/widgets/bar.js +67 -63
- package/dist/widgets/bar.js.map +1 -1
- package/dist/widgets/category.js +250 -241
- package/dist/widgets/category.js.map +1 -1
- package/dist/widgets/echart.js +93 -100
- package/dist/widgets/echart.js.map +1 -1
- package/dist/widgets/error.js +1 -1
- package/dist/widgets/formula.js +64 -72
- package/dist/widgets/formula.js.map +1 -1
- package/dist/widgets/histogram.js +75 -73
- package/dist/widgets/histogram.js.map +1 -1
- package/dist/widgets/loader.js +1 -1
- package/dist/widgets/loader.js.map +1 -1
- package/dist/widgets/markdown.js +2 -2
- package/dist/widgets/no-data.js +1 -1
- package/dist/widgets/pie.js +4 -4
- package/dist/widgets/range.js +97 -105
- package/dist/widgets/range.js.map +1 -1
- package/dist/widgets/scatterplot.js +8 -8
- package/dist/widgets/skeleton-loader.js +1 -1
- package/dist/widgets/spread.js +84 -100
- package/dist/widgets/spread.js.map +1 -1
- package/dist/widgets/stores.js +1 -1
- package/dist/widgets/table.js +493 -485
- package/dist/widgets/table.js.map +1 -1
- package/dist/widgets/timeseries.js +4 -4
- package/dist/widgets/wrapper.js +156 -156
- package/dist/widgets/wrapper.js.map +1 -1
- package/dist/widgets.js +4 -4
- package/package.json +3 -3
- package/src/components/lasso-tool/lasso-tool-inline.tsx +19 -17
- package/src/components/lasso-tool/lasso-tool.tsx +22 -20
- package/src/components/lasso-tool/types.ts +4 -3
- package/src/widgets/_shared/chart-config/index.ts +1 -0
- package/src/widgets/_shared/chart-config/option-builders.test.ts +40 -0
- package/src/widgets/_shared/chart-config/option-builders.ts +12 -0
- package/src/widgets/actions/fullscreen/fullscreen.tsx +5 -8
- package/src/widgets/actions/index.ts +2 -5
- package/src/widgets/actions/lock-selection/lock-selection.test.tsx +28 -30
- package/src/widgets/actions/lock-selection/lock-selection.tsx +25 -26
- package/src/widgets/actions/lock-selection/types.ts +0 -17
- package/src/widgets/actions/relative-data/relative-data.test.tsx +13 -13
- package/src/widgets/actions/relative-data/relative-data.tsx +18 -21
- package/src/widgets/actions/relative-data/types.ts +0 -7
- package/src/widgets/actions/searcher/searcher.tsx +40 -22
- package/src/widgets/actions/searcher/types.ts +0 -2
- package/src/widgets/actions/stack-toggle/stack-toggle.test.tsx +19 -9
- package/src/widgets/actions/stack-toggle/stack-toggle.tsx +32 -22
- package/src/widgets/actions/stack-toggle/types.ts +0 -8
- package/src/widgets/actions/zoom-toggle/zoom-toggle.tsx +113 -95
- package/src/widgets/bar/config.ts +37 -28
- package/src/widgets/category/category-ui.tsx +25 -22
- package/src/widgets/echart/echart-ui.test.tsx +3 -18
- package/src/widgets/echart/echart-ui.tsx +4 -22
- package/src/widgets/echart/echart.test.tsx +9 -25
- package/src/widgets/echart/echart.tsx +36 -29
- package/src/widgets/echart/types.ts +0 -4
- package/src/widgets/echart/utils.ts +3 -1
- package/src/widgets/error/error.tsx +17 -14
- package/src/widgets/error/types.ts +10 -0
- package/src/widgets/formula/components/value.tsx +13 -13
- package/src/widgets/histogram/config.ts +36 -29
- package/src/widgets/loader/loader.tsx +3 -1
- package/src/widgets/loader/types.ts +3 -1
- package/src/widgets/no-data/no-data.tsx +8 -11
- package/src/widgets/range/components/range-item.tsx +9 -13
- package/src/widgets/spread/components/max-value.tsx +13 -13
- package/src/widgets/spread/components/min-value.tsx +13 -13
- package/src/widgets/stores/types.ts +1 -4
- package/src/widgets/stores/widget-store.ts +1 -27
- package/src/widgets/table/hooks/use-pagination.ts +44 -35
- package/src/widgets/table/hooks/use-sort.ts +25 -23
- package/src/widgets/wrapper/wrapper-ui.tsx +16 -17
- package/dist/error-piB8FwYO.js +0 -38
- package/dist/error-piB8FwYO.js.map +0 -1
- package/dist/lasso-tool-BctzdzBu.js.map +0 -1
- package/dist/no-data-jdlbMef0.js +0 -61
- package/dist/no-data-jdlbMef0.js.map +0 -1
- package/dist/styles-CCZnY17y.js.map +0 -1
- package/dist/utils-D3-eQyDR.js.map +0 -1
- package/dist/widget-store-Dn0Bnc4h.js.map +0 -1
|
@@ -39,14 +39,17 @@ describe('StackToggle', () => {
|
|
|
39
39
|
expect(button).toBeTruthy()
|
|
40
40
|
})
|
|
41
41
|
|
|
42
|
-
test('toggles to stacked mode and updates
|
|
42
|
+
test('toggles to stacked mode and updates tool config', () => {
|
|
43
43
|
render(<StackToggle id={widgetId} />)
|
|
44
44
|
|
|
45
45
|
const button = screen.getByRole('button')
|
|
46
46
|
fireEvent.click(button)
|
|
47
47
|
|
|
48
48
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
49
|
-
|
|
49
|
+
const tool = widget?.registeredTools?.find(
|
|
50
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
51
|
+
)
|
|
52
|
+
expect(tool?.config?.stacked).toBe(true)
|
|
50
53
|
})
|
|
51
54
|
|
|
52
55
|
test('toggles back to unstacked mode', () => {
|
|
@@ -61,7 +64,10 @@ describe('StackToggle', () => {
|
|
|
61
64
|
fireEvent.click(button)
|
|
62
65
|
|
|
63
66
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
64
|
-
|
|
67
|
+
const tool = widget?.registeredTools?.find(
|
|
68
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
69
|
+
)
|
|
70
|
+
expect(tool?.config?.stacked).toBe(false)
|
|
65
71
|
})
|
|
66
72
|
|
|
67
73
|
test('has active state when in stacked mode', () => {
|
|
@@ -99,18 +105,24 @@ describe('StackToggle', () => {
|
|
|
99
105
|
expect(button).toBeTruthy()
|
|
100
106
|
})
|
|
101
107
|
|
|
102
|
-
test('initializes
|
|
108
|
+
test('initializes tool config with default values on mount', () => {
|
|
103
109
|
render(<StackToggle id={widgetId} />)
|
|
104
110
|
|
|
105
111
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
106
|
-
|
|
112
|
+
const tool = widget?.registeredTools?.find(
|
|
113
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
114
|
+
)
|
|
115
|
+
expect(tool?.config?.stacked).toBe(false)
|
|
107
116
|
})
|
|
108
117
|
|
|
109
|
-
test('initializes
|
|
118
|
+
test('initializes tool config with stacked values when defaultIsStacked is true', () => {
|
|
110
119
|
render(<StackToggle id={widgetId} defaultIsStacked />)
|
|
111
120
|
|
|
112
121
|
const widget = useWidgetStore.getState().getWidget(widgetId)
|
|
113
|
-
|
|
122
|
+
const tool = widget?.registeredTools?.find(
|
|
123
|
+
(t) => t.id === STACK_TOGGLE_TOOL_ID,
|
|
124
|
+
)
|
|
125
|
+
expect(tool?.config?.stacked).toBe(true)
|
|
114
126
|
})
|
|
115
127
|
|
|
116
128
|
test('applies stack to EChart series via config pipeline when toggling to stacked', async () => {
|
|
@@ -279,7 +291,6 @@ describe('StackToggle', () => {
|
|
|
279
291
|
test('config tool re-applies stack when config pipeline re-runs', async () => {
|
|
280
292
|
// Start with stacked widget
|
|
281
293
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
282
|
-
isStacked: true,
|
|
283
294
|
option: {
|
|
284
295
|
series: [
|
|
285
296
|
{ name: 'Series 1', type: 'bar', stack: DEFAULT_STACK_GROUP },
|
|
@@ -313,7 +324,6 @@ describe('StackToggle', () => {
|
|
|
313
324
|
test('config tool does not apply stack when unstacked and pipeline re-runs', async () => {
|
|
314
325
|
// Start with unstacked widget
|
|
315
326
|
useWidgetStore.getState().setWidget(widgetId, {
|
|
316
|
-
isStacked: false,
|
|
317
327
|
option: {
|
|
318
328
|
series: [
|
|
319
329
|
{ name: 'Series 1', type: 'bar' },
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IconButton } from '@mui/material'
|
|
2
2
|
import { useCallback, useEffect, useMemo } from 'react'
|
|
3
3
|
import { useWidgetStore } from '../../stores/widget-store'
|
|
4
|
-
import type { StackToggleProps
|
|
4
|
+
import type { StackToggleProps } from './types'
|
|
5
5
|
import { actionButtonStyles } from '../shared/styles'
|
|
6
6
|
import { Tooltip } from '../../../components'
|
|
7
7
|
import { GroupedBarChartIcon } from './grouped-bar-chart-icon'
|
|
@@ -34,14 +34,17 @@ export function StackToggle({
|
|
|
34
34
|
Icon,
|
|
35
35
|
IconButtonProps,
|
|
36
36
|
}: StackToggleProps) {
|
|
37
|
-
const
|
|
37
|
+
const getWidget = useWidgetStore((state) => state.getWidget)
|
|
38
38
|
const registerTool = useWidgetStore((state) => state.registerTool)
|
|
39
39
|
const unregisterTool = useWidgetStore((state) => state.unregisterTool)
|
|
40
40
|
const setToolEnabled = useWidgetStore((state) => state.setToolEnabled)
|
|
41
41
|
const updateToolConfig = useWidgetStore((state) => state.updateToolConfig)
|
|
42
42
|
|
|
43
|
-
const
|
|
44
|
-
useShallow((state) =>
|
|
43
|
+
const stackTool = useWidgetStore(
|
|
44
|
+
useShallow((state) => {
|
|
45
|
+
const tools = state.getWidget(id)?.registeredTools ?? []
|
|
46
|
+
return tools.find((tool) => tool.id === STACK_TOGGLE_TOOL_ID)
|
|
47
|
+
}),
|
|
45
48
|
)
|
|
46
49
|
|
|
47
50
|
const option = useWidgetStore(
|
|
@@ -61,15 +64,25 @@ export function StackToggle({
|
|
|
61
64
|
|
|
62
65
|
// If series already has stack defined, default to stacked=true
|
|
63
66
|
const effectiveDefaultIsStacked = hasStackInSeries || defaultIsStacked
|
|
64
|
-
const isStacked =
|
|
67
|
+
const isStacked =
|
|
68
|
+
(stackTool?.config?.stacked as boolean | undefined) ??
|
|
69
|
+
effectiveDefaultIsStacked
|
|
65
70
|
|
|
66
71
|
// Register config tool on mount
|
|
67
72
|
useEffect(() => {
|
|
73
|
+
const existingTool = getWidget(id)?.registeredTools?.find(
|
|
74
|
+
(tool) => tool.id === STACK_TOGGLE_TOOL_ID,
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
const initialStacked =
|
|
78
|
+
(existingTool?.config?.stacked as boolean | undefined) ??
|
|
79
|
+
effectiveDefaultIsStacked
|
|
80
|
+
|
|
68
81
|
registerTool(id, {
|
|
69
82
|
id: STACK_TOGGLE_TOOL_ID,
|
|
70
83
|
type: 'config',
|
|
71
84
|
order: 10,
|
|
72
|
-
enabled:
|
|
85
|
+
enabled: initialStacked && hasMultiSeries,
|
|
73
86
|
fn: (currentConfig, toolConfig) => {
|
|
74
87
|
const config = currentConfig as Record<string, unknown>
|
|
75
88
|
const option = config.option as EchartOptionsProps | undefined
|
|
@@ -90,26 +103,23 @@ export function StackToggle({
|
|
|
90
103
|
|
|
91
104
|
return { ...config, option: { ...option, series: updatedSeries } }
|
|
92
105
|
},
|
|
93
|
-
config: { stacked:
|
|
106
|
+
config: { stacked: initialStacked },
|
|
94
107
|
})
|
|
95
108
|
return () => unregisterTool(id, STACK_TOGGLE_TOOL_ID)
|
|
96
|
-
}, [
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
// Initialize store with default value only if not already configured
|
|
105
|
-
useEffect(() => {
|
|
106
|
-
if (storeIsStacked !== undefined) return
|
|
107
|
-
setWidget(id, { isStacked: effectiveDefaultIsStacked })
|
|
108
|
-
}, [effectiveDefaultIsStacked, id, setWidget, storeIsStacked])
|
|
109
|
+
}, [
|
|
110
|
+
id,
|
|
111
|
+
registerTool,
|
|
112
|
+
unregisterTool,
|
|
113
|
+
effectiveDefaultIsStacked,
|
|
114
|
+
hasMultiSeries,
|
|
115
|
+
getWidget,
|
|
116
|
+
])
|
|
109
117
|
|
|
110
118
|
const handleToggle = useCallback(() => {
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
const newStacked = !isStacked
|
|
120
|
+
setToolEnabled(id, STACK_TOGGLE_TOOL_ID, newStacked && hasMultiSeries)
|
|
121
|
+
updateToolConfig(id, STACK_TOGGLE_TOOL_ID, { stacked: newStacked })
|
|
122
|
+
}, [isStacked, hasMultiSeries, id, setToolEnabled, updateToolConfig])
|
|
113
123
|
|
|
114
124
|
const tooltipLabel = isStacked
|
|
115
125
|
? (labels?.unstacked ?? 'Disable stacking')
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { IconButtonProps } from '@mui/material'
|
|
2
2
|
import type { ReactNode } from 'react'
|
|
3
|
-
import type { BaseWidgetState } from '../../stores/types'
|
|
4
|
-
|
|
5
3
|
export interface StackToggleProps {
|
|
6
4
|
/** Widget ID to update stack configuration in the widget store */
|
|
7
5
|
id: string
|
|
@@ -21,9 +19,3 @@ export interface StackToggleProps {
|
|
|
21
19
|
/** Custom icon to display */
|
|
22
20
|
Icon?: ReactNode
|
|
23
21
|
}
|
|
24
|
-
|
|
25
|
-
export type StackToggleState<T = unknown> = BaseWidgetState<
|
|
26
|
-
T & {
|
|
27
|
-
isStacked?: boolean
|
|
28
|
-
}
|
|
29
|
-
>
|
|
@@ -5,11 +5,10 @@ import {
|
|
|
5
5
|
} from '@mui/icons-material'
|
|
6
6
|
import { useEffect, useCallback } from 'react'
|
|
7
7
|
import { useWidgetStore } from '../../stores/widget-store'
|
|
8
|
-
import type { ZoomToggleProps
|
|
8
|
+
import type { ZoomToggleProps } from './types'
|
|
9
9
|
import { styles } from './style'
|
|
10
10
|
import { Tooltip } from '../../../components'
|
|
11
11
|
import { getEChartZoomConfig } from '../../echart/utils'
|
|
12
|
-
import type { EchartWidgetState } from '../../echart/types'
|
|
13
12
|
import type { EchartOptionsProps } from '../../echart/types'
|
|
14
13
|
import { useShallow } from 'zustand/shallow'
|
|
15
14
|
|
|
@@ -45,143 +44,162 @@ export function ZoomToggle({
|
|
|
45
44
|
IconButtonProps,
|
|
46
45
|
}: ZoomToggleProps) {
|
|
47
46
|
const theme = useTheme()
|
|
48
|
-
const setWidget = useWidgetStore((state) => state.setWidget)
|
|
49
47
|
const getWidget = useWidgetStore((state) => state.getWidget)
|
|
50
48
|
const registerTool = useWidgetStore((state) => state.registerTool)
|
|
51
49
|
const unregisterTool = useWidgetStore((state) => state.unregisterTool)
|
|
52
50
|
const setToolEnabled = useWidgetStore((state) => state.setToolEnabled)
|
|
53
51
|
const updateToolConfig = useWidgetStore((state) => state.updateToolConfig)
|
|
54
52
|
|
|
55
|
-
const
|
|
53
|
+
const zoomTool = useWidgetStore(
|
|
56
54
|
useShallow((state) => {
|
|
57
|
-
const
|
|
58
|
-
return
|
|
55
|
+
const tools = state.getWidget(id)?.registeredTools ?? []
|
|
56
|
+
return tools.find((tool) => tool.id === ZOOM_TOGGLE_TOOL_ID)
|
|
59
57
|
}),
|
|
60
58
|
)
|
|
61
59
|
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
)
|
|
60
|
+
const zoom = zoomTool?.enabled ?? defaultZoom
|
|
61
|
+
const zoomStart =
|
|
62
|
+
(zoomTool?.config?.start as number | undefined) ?? defaultZoomStart
|
|
63
|
+
const zoomEnd =
|
|
64
|
+
(zoomTool?.config?.end as number | undefined) ?? defaultZoomEnd
|
|
68
65
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
// Handle dataZoom event to update zoom range in tool config
|
|
67
|
+
const handleDataZoom = useCallback(
|
|
68
|
+
(event: unknown) => {
|
|
69
|
+
const zoomEvent = event as {
|
|
70
|
+
start?: number
|
|
71
|
+
end?: number
|
|
72
|
+
batch?: {
|
|
73
|
+
start?: number
|
|
74
|
+
end?: number
|
|
75
|
+
}[]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const start = zoomEvent.start ?? zoomEvent.batch?.[0]?.start
|
|
79
|
+
const end = zoomEvent.end ?? zoomEvent.batch?.[0]?.end
|
|
80
|
+
|
|
81
|
+
if (start !== undefined && end !== undefined) {
|
|
82
|
+
setToolEnabled(id, ZOOM_TOGGLE_TOOL_ID, true)
|
|
83
|
+
updateToolConfig(id, ZOOM_TOGGLE_TOOL_ID, {
|
|
84
|
+
enabled: true,
|
|
85
|
+
start,
|
|
86
|
+
end,
|
|
87
|
+
})
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
[id, setToolEnabled, updateToolConfig],
|
|
74
91
|
)
|
|
75
92
|
|
|
76
93
|
// Register config tool on mount
|
|
77
94
|
useEffect(() => {
|
|
95
|
+
const existingTool = getWidget(id)?.registeredTools?.find(
|
|
96
|
+
(tool) => tool.id === ZOOM_TOGGLE_TOOL_ID,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
const initialEnabled = existingTool?.enabled ?? defaultZoom
|
|
100
|
+
const initialStart =
|
|
101
|
+
(existingTool?.config?.start as number | undefined) ?? defaultZoomStart
|
|
102
|
+
const initialEnd =
|
|
103
|
+
(existingTool?.config?.end as number | undefined) ?? defaultZoomEnd
|
|
104
|
+
|
|
78
105
|
registerTool(id, {
|
|
79
106
|
id: ZOOM_TOGGLE_TOOL_ID,
|
|
80
107
|
type: 'config',
|
|
81
108
|
order: 20,
|
|
82
|
-
enabled:
|
|
109
|
+
enabled: initialEnabled,
|
|
83
110
|
fn: (currentConfig, toolConfig) => {
|
|
84
111
|
const config = currentConfig as Record<string, unknown>
|
|
85
112
|
const option = config.option as EchartOptionsProps | undefined
|
|
113
|
+
const currentOnEvents =
|
|
114
|
+
(config.onEvents as Record<string, unknown> | undefined) ?? {}
|
|
115
|
+
|
|
86
116
|
const enabled = (toolConfig?.enabled as boolean) ?? false
|
|
87
117
|
const start = (toolConfig?.start as number) ?? 0
|
|
88
118
|
const end = (toolConfig?.end as number) ?? 100
|
|
89
119
|
|
|
120
|
+
const legend = option?.legend as { show?: boolean } | undefined
|
|
121
|
+
const hasLegend = legend?.show !== false && legend !== undefined
|
|
122
|
+
|
|
123
|
+
const sliderHeight = parseInt(theme?.spacing?.(4) ?? '32')
|
|
124
|
+
const sliderGap = 8
|
|
125
|
+
const legendBottomOffset = hasLegend ? 28 : 0
|
|
126
|
+
|
|
90
127
|
const zoomConfig = getEChartZoomConfig(
|
|
91
128
|
enabled,
|
|
92
129
|
{ start, end },
|
|
93
|
-
{
|
|
130
|
+
{
|
|
131
|
+
inside: true,
|
|
132
|
+
xSlider: true,
|
|
133
|
+
ySlider: false,
|
|
134
|
+
bottomOffset: legendBottomOffset,
|
|
135
|
+
},
|
|
94
136
|
theme,
|
|
95
137
|
)
|
|
96
|
-
|
|
138
|
+
|
|
139
|
+
const grid = option?.grid as { bottom?: number | string } | undefined
|
|
140
|
+
const currentGridBottom =
|
|
141
|
+
typeof grid?.bottom === 'number'
|
|
142
|
+
? grid.bottom
|
|
143
|
+
: parseInt(grid?.bottom ?? '24')
|
|
144
|
+
|
|
145
|
+
const gridBottom = enabled
|
|
146
|
+
? currentGridBottom + sliderHeight + sliderGap
|
|
147
|
+
: currentGridBottom
|
|
148
|
+
|
|
149
|
+
const onEventsWithoutDataZoom = { ...currentOnEvents }
|
|
150
|
+
delete onEventsWithoutDataZoom.dataZoom
|
|
151
|
+
const onEvents = enabled
|
|
152
|
+
? { ...currentOnEvents, dataZoom: handleDataZoom }
|
|
153
|
+
: onEventsWithoutDataZoom
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
...config,
|
|
157
|
+
option: {
|
|
158
|
+
...option,
|
|
159
|
+
...zoomConfig,
|
|
160
|
+
grid: { ...grid, bottom: gridBottom },
|
|
161
|
+
},
|
|
162
|
+
onEvents,
|
|
163
|
+
}
|
|
164
|
+
},
|
|
165
|
+
config: {
|
|
166
|
+
enabled: initialEnabled,
|
|
167
|
+
start: initialStart,
|
|
168
|
+
end: initialEnd,
|
|
97
169
|
},
|
|
98
|
-
config: { enabled: zoom, start: zoomStart, end: zoomEnd },
|
|
99
170
|
})
|
|
100
171
|
return () => unregisterTool(id, ZOOM_TOGGLE_TOOL_ID)
|
|
101
|
-
}, [
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
// Initialize zoom state from defaults only if not already set
|
|
114
|
-
useEffect(() => {
|
|
115
|
-
const existingState = getWidget<ZoomState>(id)
|
|
116
|
-
|
|
117
|
-
if (existingState?.zoom) return
|
|
118
|
-
|
|
119
|
-
setWidget<ZoomState>(id, {
|
|
120
|
-
zoom: existingState?.zoom ?? defaultZoom,
|
|
121
|
-
zoomStart: existingState?.zoomStart ?? defaultZoomStart,
|
|
122
|
-
zoomEnd: existingState?.zoomEnd ?? defaultZoomEnd,
|
|
123
|
-
})
|
|
124
|
-
}, [defaultZoom, defaultZoomEnd, defaultZoomStart, getWidget, id, setWidget])
|
|
125
|
-
|
|
126
|
-
// Cleanup: disable zoom when component unmounts
|
|
127
|
-
useEffect(() => {
|
|
128
|
-
return () => {
|
|
129
|
-
setWidget<ZoomState>(id, { zoom: false })
|
|
130
|
-
}
|
|
131
|
-
}, [id, setWidget])
|
|
172
|
+
}, [
|
|
173
|
+
defaultZoom,
|
|
174
|
+
defaultZoomEnd,
|
|
175
|
+
defaultZoomStart,
|
|
176
|
+
getWidget,
|
|
177
|
+
handleDataZoom,
|
|
178
|
+
id,
|
|
179
|
+
registerTool,
|
|
180
|
+
theme,
|
|
181
|
+
unregisterTool,
|
|
182
|
+
])
|
|
132
183
|
|
|
133
184
|
const handleToggle = () => {
|
|
134
185
|
const newZoom = !zoom
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
zoomEnd: newZoom ? (existingState?.zoomEnd ?? defaultZoomEnd) : 100,
|
|
186
|
+
setToolEnabled(id, ZOOM_TOGGLE_TOOL_ID, newZoom)
|
|
187
|
+
updateToolConfig(id, ZOOM_TOGGLE_TOOL_ID, {
|
|
188
|
+
enabled: newZoom,
|
|
189
|
+
start: newZoom ? zoomStart : 0,
|
|
190
|
+
end: newZoom ? zoomEnd : 100,
|
|
141
191
|
})
|
|
142
192
|
}
|
|
143
193
|
|
|
144
194
|
const handleReset = () => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
195
|
+
setToolEnabled(id, ZOOM_TOGGLE_TOOL_ID, true)
|
|
196
|
+
updateToolConfig(id, ZOOM_TOGGLE_TOOL_ID, {
|
|
197
|
+
enabled: true,
|
|
198
|
+
start: defaultZoomStart,
|
|
199
|
+
end: defaultZoomEnd,
|
|
149
200
|
})
|
|
150
201
|
}
|
|
151
202
|
|
|
152
|
-
// Handle dataZoom event to update zoom range in store
|
|
153
|
-
const handleDataZoom = useCallback(
|
|
154
|
-
(event: unknown) => {
|
|
155
|
-
const zoomEvent = event as {
|
|
156
|
-
start: number
|
|
157
|
-
end: number
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const start = zoomEvent.start
|
|
161
|
-
const end = zoomEvent.end
|
|
162
|
-
|
|
163
|
-
if (start !== undefined && end !== undefined) {
|
|
164
|
-
setWidget<ZoomState>(id, {
|
|
165
|
-
zoom: true,
|
|
166
|
-
zoomStart: start,
|
|
167
|
-
zoomEnd: end,
|
|
168
|
-
})
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
[id, setWidget],
|
|
172
|
-
)
|
|
173
|
-
|
|
174
|
-
// Register dataZoom event handler when zoom is enabled
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
if (zoom) {
|
|
177
|
-
setWidget<EchartWidgetState>(id, {
|
|
178
|
-
onEvents: {
|
|
179
|
-
dataZoom: handleDataZoom,
|
|
180
|
-
},
|
|
181
|
-
})
|
|
182
|
-
}
|
|
183
|
-
}, [id, zoom, handleDataZoom, setWidget])
|
|
184
|
-
|
|
185
203
|
const enableLabel = labels?.enable ?? 'Enable zoom'
|
|
186
204
|
const disableLabel = labels?.disable ?? 'Disable zoom'
|
|
187
205
|
const resetLabel = labels?.reset ?? 'Reset zoom'
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
buildGridConfig,
|
|
11
11
|
createTooltipPositioner,
|
|
12
12
|
createTooltipFormatter,
|
|
13
|
-
|
|
13
|
+
niceNum,
|
|
14
14
|
} from '../_shared/chart-config'
|
|
15
15
|
import { downloadToCSV, downloadToPNG, type DownloadItem } from '../actions'
|
|
16
16
|
import type { ConfigProps } from '../loader/types'
|
|
@@ -47,32 +47,7 @@ function getOption({
|
|
|
47
47
|
}: BarConfig): EchartOptionsProps {
|
|
48
48
|
const hasLegend = (data?.length ?? 0) > 1
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
type: 'value' as const,
|
|
52
|
-
splitNumber: 1,
|
|
53
|
-
axisLabel: {
|
|
54
|
-
fontSize: theme.typography.overlineDelicate.fontSize,
|
|
55
|
-
fontFamily: theme.typography.overlineDelicate.fontFamily,
|
|
56
|
-
margin: parseInt(theme.spacing(1)),
|
|
57
|
-
show: true,
|
|
58
|
-
showMaxLabel: true,
|
|
59
|
-
showMinLabel: false,
|
|
60
|
-
verticalAlign: 'bottom' as const,
|
|
61
|
-
inside: true,
|
|
62
|
-
},
|
|
63
|
-
axisLine: {
|
|
64
|
-
show: false,
|
|
65
|
-
},
|
|
66
|
-
axisTick: {
|
|
67
|
-
show: false,
|
|
68
|
-
},
|
|
69
|
-
splitLine: {
|
|
70
|
-
show: true,
|
|
71
|
-
lineStyle: {
|
|
72
|
-
color: theme.palette.black[4],
|
|
73
|
-
},
|
|
74
|
-
},
|
|
75
|
-
}
|
|
50
|
+
let niceMax = 1
|
|
76
51
|
|
|
77
52
|
return {
|
|
78
53
|
legend: buildLegendConfig(hasLegend),
|
|
@@ -90,7 +65,41 @@ function getOption({
|
|
|
90
65
|
margin: 0,
|
|
91
66
|
},
|
|
92
67
|
},
|
|
93
|
-
yAxis:
|
|
68
|
+
yAxis: {
|
|
69
|
+
type: 'value' as const,
|
|
70
|
+
min: 0,
|
|
71
|
+
max: (extent: { min: number; max: number }) => {
|
|
72
|
+
niceMax = extent.max <= 0 ? 1 : niceNum(extent.max)
|
|
73
|
+
return niceMax
|
|
74
|
+
},
|
|
75
|
+
splitNumber: 1,
|
|
76
|
+
axisLabel: {
|
|
77
|
+
fontSize: theme.typography.overlineDelicate.fontSize,
|
|
78
|
+
fontFamily: theme.typography.overlineDelicate.fontFamily,
|
|
79
|
+
margin: parseInt(theme.spacing(1)),
|
|
80
|
+
show: true,
|
|
81
|
+
showMaxLabel: true,
|
|
82
|
+
showMinLabel: false,
|
|
83
|
+
verticalAlign: 'bottom' as const,
|
|
84
|
+
inside: true,
|
|
85
|
+
formatter: (value: number) => {
|
|
86
|
+
if (value !== niceMax) return ''
|
|
87
|
+
return formatter ? formatter(value) : String(value)
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
axisLine: {
|
|
91
|
+
show: false,
|
|
92
|
+
},
|
|
93
|
+
axisTick: {
|
|
94
|
+
show: false,
|
|
95
|
+
},
|
|
96
|
+
splitLine: {
|
|
97
|
+
show: true,
|
|
98
|
+
lineStyle: {
|
|
99
|
+
color: theme.palette.black[4],
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
},
|
|
94
103
|
tooltip: {
|
|
95
104
|
position: createTooltipPositioner(theme),
|
|
96
105
|
formatter: createTooltipFormatter((item) => {
|
|
@@ -15,30 +15,33 @@ const defaultFormatter = (value: number) => value.toString()
|
|
|
15
15
|
|
|
16
16
|
export function CategoryUI({ id }: CategoryUIProps) {
|
|
17
17
|
const theme = useTheme()
|
|
18
|
-
const
|
|
19
|
-
useShallow((state) =>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
18
|
+
const _formatter = useWidgetStore(
|
|
19
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.formatter),
|
|
20
|
+
)
|
|
21
|
+
const _series = useWidgetStore(
|
|
22
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.series),
|
|
23
|
+
)
|
|
24
|
+
const data = useWidgetStore(
|
|
25
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.data),
|
|
26
|
+
)
|
|
27
|
+
const maxItems = useWidgetStore(
|
|
28
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.maxItems),
|
|
29
|
+
)
|
|
30
|
+
const labels = useWidgetStore(
|
|
31
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.labels),
|
|
32
|
+
)
|
|
33
|
+
const onRowClick = useWidgetStore(
|
|
34
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.onRowClick),
|
|
35
|
+
)
|
|
36
|
+
const selected = useWidgetStore(
|
|
37
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.selected),
|
|
38
|
+
)
|
|
39
|
+
const max = useWidgetStore(
|
|
40
|
+
useShallow((state) => state.getWidget<CategoryWidgetState>(id)?.max),
|
|
32
41
|
)
|
|
33
42
|
|
|
34
|
-
const formatter =
|
|
35
|
-
const series =
|
|
36
|
-
const data = widget?.data
|
|
37
|
-
const maxItems = widget?.maxItems
|
|
38
|
-
const labels = widget?.labels
|
|
39
|
-
const onRowClick = widget?.onRowClick
|
|
40
|
-
const selected = widget?.selected
|
|
41
|
-
const max = widget?.max
|
|
43
|
+
const formatter = _formatter ?? defaultFormatter
|
|
44
|
+
const series = _series ?? []
|
|
42
45
|
|
|
43
46
|
const [maxHeight] = useState<string | number | undefined>(
|
|
44
47
|
maxItems ? 40 * (series.length || 1) * maxItems : undefined,
|
|
@@ -175,7 +175,7 @@ describe('EchartUI', () => {
|
|
|
175
175
|
|
|
176
176
|
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
177
177
|
lazyUpdate: true,
|
|
178
|
-
|
|
178
|
+
notMerge: true,
|
|
179
179
|
})
|
|
180
180
|
})
|
|
181
181
|
|
|
@@ -200,22 +200,7 @@ describe('EchartUI', () => {
|
|
|
200
200
|
|
|
201
201
|
expect(mockChart.setOption).toHaveBeenCalledWith(newOption, {
|
|
202
202
|
lazyUpdate: true,
|
|
203
|
-
|
|
204
|
-
})
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
test('uses provided replaceMerge values', () => {
|
|
208
|
-
render(
|
|
209
|
-
<EchartUI
|
|
210
|
-
{...defaultProps}
|
|
211
|
-
option={basicOption}
|
|
212
|
-
replaceMerge={['series']}
|
|
213
|
-
/>,
|
|
214
|
-
)
|
|
215
|
-
|
|
216
|
-
expect(mockChart.setOption).toHaveBeenCalledWith(basicOption, {
|
|
217
|
-
lazyUpdate: true,
|
|
218
|
-
replaceMerge: ['series'],
|
|
203
|
+
notMerge: true,
|
|
219
204
|
})
|
|
220
205
|
})
|
|
221
206
|
|
|
@@ -496,7 +481,7 @@ describe('EchartUI', () => {
|
|
|
496
481
|
|
|
497
482
|
expect(mockChart.setOption).toHaveBeenCalledWith(complexOption, {
|
|
498
483
|
lazyUpdate: true,
|
|
499
|
-
|
|
484
|
+
notMerge: true,
|
|
500
485
|
})
|
|
501
486
|
})
|
|
502
487
|
|