@easy-editor/materials-dashboard-bar-chart 0.0.4 → 0.0.5

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/src/component.tsx CHANGED
@@ -1,311 +1,313 @@
1
- /**
2
- * Bar Chart Component
3
- * 柱状图组件 - 支持数据源绑定和事件交互
4
- */
5
-
6
- import { useEffect, useMemo, useRef, type CSSProperties } from 'react'
7
- import * as echarts from 'echarts/core'
8
- import { BarChart as EChartsBarChart } from 'echarts/charts'
9
- import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
10
- import { CanvasRenderer } from 'echarts/renderers'
11
- import type { SeriesOption } from 'echarts'
12
- import { type MaterialComponet, useDataSource } from '@easy-editor/materials-shared'
13
- import { DEFAULT_COLORS, type DataPoint } from './constants'
14
- import styles from './component.module.css'
15
-
16
- // 按需注册 ECharts 组件
17
- echarts.use([EChartsBarChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer])
18
-
19
- export interface BarChartProps extends MaterialComponet {
20
- /** X轴字段 */
21
- xField?: string
22
- /** Y轴字段列表 */
23
- yFields?: string[]
24
- /** 颜色列表 */
25
- colors?: string[]
26
- /** 布局方向 */
27
- layout?: 'vertical' | 'horizontal'
28
- /** 堆叠模式 */
29
- stacked?: boolean
30
- /** 渐变填充 */
31
- gradient?: boolean
32
- /** 圆角 */
33
- borderRadius?: number
34
- /** 柱间距 */
35
- barGap?: string
36
- /** 显示网格 */
37
- showGrid?: boolean
38
- /** 显示图例 */
39
- showLegend?: boolean
40
- /** 显示提示 */
41
- showTooltip?: boolean
42
- /** 发光效果 */
43
- glowEffect?: boolean
44
- /** 点击事件 */
45
- onClick?: (e: React.MouseEvent) => void
46
- /** 双击事件 */
47
- onDoubleClick?: (e: React.MouseEvent) => void
48
- /** 鼠标进入 */
49
- onMouseEnter?: (e: React.MouseEvent) => void
50
- /** 鼠标离开 */
51
- onMouseLeave?: (e: React.MouseEvent) => void
52
- }
53
-
54
- interface SeriesOptions {
55
- stacked: boolean
56
- gradient: boolean
57
- borderRadius: number
58
- glowEffect: boolean
59
- layout: string
60
- barGap?: string
61
- }
62
-
63
- // 获取渐变色
64
- const getGradientColor = (color: string, isVertical: boolean) =>
65
- new echarts.graphic.LinearGradient(isVertical ? 0 : 1, isVertical ? 1 : 0, isVertical ? 0 : 0, isVertical ? 0 : 1, [
66
- { offset: 0, color: `${color}99` },
67
- { offset: 1, color },
68
- ])
69
-
70
- // 构建单个 series 配置
71
- const createBarSeries = (field: string, data: DataPoint[], color: string, options: SeriesOptions): SeriesOption => {
72
- const { stacked, gradient, borderRadius, glowEffect, layout } = options
73
- const isVertical = layout === 'vertical'
74
-
75
- return {
76
- name: field,
77
- type: 'bar' as const,
78
- data: data.map(item => item[field] as number),
79
- stack: stacked ? 'total' : undefined,
80
- barGap: options.barGap,
81
- itemStyle: {
82
- color: gradient ? getGradientColor(color, isVertical) : color,
83
- borderRadius,
84
- shadowColor: glowEffect ? color : 'transparent',
85
- shadowBlur: glowEffect ? 10 : 0,
86
- },
87
- }
88
- }
89
-
90
- // 构建 series 配置
91
- const buildSeries = (yFields: string[], data: DataPoint[], colors: string[], options: SeriesOptions): SeriesOption[] =>
92
- yFields.map((field, index) => {
93
- const color = colors[index % colors.length]
94
- return createBarSeries(field, data, color, options)
95
- })
96
-
97
- // 构建图表配置
98
- const buildOption = (
99
- data: DataPoint[],
100
- xField: string,
101
- series: SeriesOption[],
102
- options: {
103
- layout: string
104
- showGrid: boolean
105
- showLegend: boolean
106
- showTooltip: boolean
107
- glowEffect: boolean
108
- },
109
- ) => {
110
- const { layout, showGrid, showLegend, showTooltip } = options
111
- const isHorizontal = layout === 'horizontal'
112
-
113
- return {
114
- backgroundColor: 'transparent',
115
- grid: {
116
- top: showLegend ? 40 : 20,
117
- right: 20,
118
- bottom: 30,
119
- left: isHorizontal ? 80 : 50,
120
- containLabel: false,
121
- },
122
- xAxis: {
123
- type: isHorizontal ? 'value' : 'category',
124
- data: isHorizontal ? undefined : data.map(item => item[xField]),
125
- axisLine: {
126
- lineStyle: {
127
- color: '#8899aa',
128
- opacity: 0.3,
129
- },
130
- },
131
- axisTick: { show: false },
132
- axisLabel: {
133
- color: '#8899aa',
134
- fontSize: isHorizontal ? 11 : 12,
135
- },
136
- splitLine: {
137
- show: showGrid,
138
- lineStyle: {
139
- color: '#00d4ff',
140
- opacity: 0.1,
141
- type: 'dashed',
142
- },
143
- },
144
- },
145
- yAxis: {
146
- type: isHorizontal ? 'category' : 'value',
147
- data: isHorizontal ? data.map(item => item[xField]) : undefined,
148
- axisLine: {
149
- lineStyle: {
150
- color: '#8899aa',
151
- opacity: 0.3,
152
- },
153
- },
154
- axisTick: { show: false },
155
- axisLabel: {
156
- color: '#8899aa',
157
- fontSize: isHorizontal ? 12 : 11,
158
- },
159
- splitLine: {
160
- show: showGrid && !isHorizontal,
161
- lineStyle: {
162
- color: '#00d4ff',
163
- opacity: 0.1,
164
- type: 'dashed',
165
- },
166
- },
167
- },
168
- tooltip: showTooltip
169
- ? {
170
- trigger: 'axis',
171
- axisPointer: {
172
- type: 'shadow',
173
- },
174
- backgroundColor: 'rgba(0, 20, 40, 0.9)',
175
- borderColor: '#00d4ff',
176
- borderWidth: 1,
177
- textStyle: {
178
- color: '#fff',
179
- },
180
- }
181
- : undefined,
182
- legend: showLegend
183
- ? {
184
- show: true,
185
- top: 10,
186
- textStyle: {
187
- color: '#8899aa',
188
- fontSize: 11,
189
- },
190
- }
191
- : undefined,
192
- series,
193
- }
194
- }
195
-
196
- export const BarChart: React.FC<BarChartProps> = ({
197
- ref,
198
- $data,
199
- __dataSource,
200
- xField = 'name',
201
- yFields = ['value1', 'value2'],
202
- colors = DEFAULT_COLORS,
203
- layout = 'vertical',
204
- stacked = false,
205
- gradient = true,
206
- borderRadius = 4,
207
- barGap = '20%',
208
- showGrid = true,
209
- showLegend = true,
210
- showTooltip = true,
211
- glowEffect = true,
212
- rotation = 0,
213
- opacity = 100,
214
- background = 'transparent',
215
- style: externalStyle,
216
- onClick,
217
- onDoubleClick,
218
- onMouseEnter,
219
- onMouseLeave,
220
- }) => {
221
- const chartRef = useRef<HTMLDivElement>(null)
222
- const chartInstance = useRef<echarts.ECharts | null>(null)
223
-
224
- // 解析数据源
225
- const dataSource = useDataSource($data, __dataSource)
226
- const data = useMemo<DataPoint[]>(() => {
227
- if (dataSource.length > 0 && dataSource[0]?.name && dataSource[0]?.value1 && dataSource[0]?.value2) {
228
- return dataSource.map(item => ({
229
- name: String(item.name),
230
- value1: Number(item.value1),
231
- value2: Number(item.value2),
232
- }))
233
- }
234
- return []
235
- }, [dataSource])
236
-
237
- useEffect(() => {
238
- if (!chartRef.current) {
239
- return
240
- }
241
-
242
- chartInstance.current = echarts.init(chartRef.current)
243
-
244
- // 构建 series
245
- const series = buildSeries(yFields, data, colors, {
246
- stacked,
247
- gradient,
248
- borderRadius,
249
- glowEffect,
250
- layout,
251
- barGap,
252
- })
253
-
254
- const option = buildOption(data, xField, series, {
255
- layout,
256
- showGrid,
257
- showLegend,
258
- showTooltip,
259
- glowEffect,
260
- })
261
-
262
- chartInstance.current.setOption(option)
263
-
264
- const resizeObserver = new ResizeObserver(() => {
265
- chartInstance.current?.resize()
266
- })
267
- resizeObserver.observe(chartRef.current)
268
-
269
- return () => {
270
- resizeObserver.disconnect()
271
- chartInstance.current?.dispose()
272
- }
273
- }, [
274
- data,
275
- xField,
276
- yFields,
277
- colors,
278
- layout,
279
- stacked,
280
- gradient,
281
- borderRadius,
282
- barGap,
283
- showGrid,
284
- showLegend,
285
- showTooltip,
286
- glowEffect,
287
- ])
288
-
289
- const containerStyle: CSSProperties = {
290
- width: '100%',
291
- height: '100%',
292
- transform: rotation !== 0 ? `rotate(${rotation}deg)` : undefined,
293
- opacity: opacity / 100,
294
- backgroundColor: background,
295
- ...externalStyle,
296
- }
297
-
298
- return (
299
- <div
300
- className={styles.container}
301
- onClick={onClick}
302
- onDoubleClick={onDoubleClick}
303
- onMouseEnter={onMouseEnter}
304
- onMouseLeave={onMouseLeave}
305
- ref={ref}
306
- style={containerStyle}
307
- >
308
- <div className={styles.chart} ref={chartRef} />
309
- </div>
310
- )
311
- }
1
+ /**
2
+ * Bar Chart Component
3
+ * 柱状图组件 - 支持数据源绑定和事件交互
4
+ */
5
+
6
+ import { useEffect, useMemo, useRef, type CSSProperties } from 'react'
7
+ import * as echarts from 'echarts/core'
8
+ import { BarChart as EChartsBarChart } from 'echarts/charts'
9
+ import { GridComponent, TooltipComponent, LegendComponent } from 'echarts/components'
10
+ import { CanvasRenderer } from 'echarts/renderers'
11
+ import type { SeriesOption } from 'echarts'
12
+ import { type MaterialComponet, useDataSource } from '@easy-editor/materials-shared'
13
+ import { DEFAULT_COLORS, type DataPoint } from './constants'
14
+ import styles from './component.module.css'
15
+
16
+ // 按需注册 ECharts 组件
17
+ echarts.use([EChartsBarChart, GridComponent, TooltipComponent, LegendComponent, CanvasRenderer])
18
+
19
+ export interface BarChartProps extends MaterialComponet {
20
+ /** X轴字段 */
21
+ xField?: string
22
+ /** Y轴字段列表 */
23
+ yFields?: string[]
24
+ /** 颜色列表 */
25
+ colors?: string[]
26
+ /** 布局方向 */
27
+ layout?: 'vertical' | 'horizontal'
28
+ /** 堆叠模式 */
29
+ stacked?: boolean
30
+ /** 渐变填充 */
31
+ gradient?: boolean
32
+ /** 圆角 */
33
+ borderRadius?: number
34
+ /** 柱间距 */
35
+ barGap?: string
36
+ /** 显示网格 */
37
+ showGrid?: boolean
38
+ /** 显示图例 */
39
+ showLegend?: boolean
40
+ /** 显示提示 */
41
+ showTooltip?: boolean
42
+ /** 发光效果 */
43
+ glowEffect?: boolean
44
+ /** 点击事件 */
45
+ onClick?: (e: React.MouseEvent) => void
46
+ /** 双击事件 */
47
+ onDoubleClick?: (e: React.MouseEvent) => void
48
+ /** 鼠标进入 */
49
+ onMouseEnter?: (e: React.MouseEvent) => void
50
+ /** 鼠标离开 */
51
+ onMouseLeave?: (e: React.MouseEvent) => void
52
+ }
53
+
54
+ interface SeriesOptions {
55
+ stacked: boolean
56
+ gradient: boolean
57
+ borderRadius: number
58
+ glowEffect: boolean
59
+ layout: string
60
+ barGap?: string
61
+ }
62
+
63
+ // 获取渐变色
64
+ const getGradientColor = (color: string, isVertical: boolean) =>
65
+ new echarts.graphic.LinearGradient(isVertical ? 0 : 1, isVertical ? 1 : 0, isVertical ? 0 : 0, isVertical ? 0 : 1, [
66
+ { offset: 0, color: `${color}99` },
67
+ { offset: 1, color },
68
+ ])
69
+
70
+ // 构建单个 series 配置
71
+ const createBarSeries = (field: string, data: DataPoint[], color: string, options: SeriesOptions): SeriesOption => {
72
+ const { stacked, gradient, borderRadius, glowEffect, layout } = options
73
+ const isVertical = layout === 'vertical'
74
+
75
+ return {
76
+ name: field,
77
+ type: 'bar' as const,
78
+ data: data.map(item => item[field] as number),
79
+ stack: stacked ? 'total' : undefined,
80
+ barGap: options.barGap,
81
+ itemStyle: {
82
+ color: gradient ? getGradientColor(color, isVertical) : color,
83
+ borderRadius,
84
+ shadowColor: glowEffect ? color : 'transparent',
85
+ shadowBlur: glowEffect ? 10 : 0,
86
+ },
87
+ }
88
+ }
89
+
90
+ // 构建 series 配置
91
+ const buildSeries = (yFields: string[], data: DataPoint[], colors: string[], options: SeriesOptions): SeriesOption[] =>
92
+ yFields.map((field, index) => {
93
+ const color = colors[index % colors.length]
94
+ return createBarSeries(field, data, color, options)
95
+ })
96
+
97
+ // 构建图表配置
98
+ const buildOption = (
99
+ data: DataPoint[],
100
+ xField: string,
101
+ series: SeriesOption[],
102
+ options: {
103
+ layout: string
104
+ showGrid: boolean
105
+ showLegend: boolean
106
+ showTooltip: boolean
107
+ glowEffect: boolean
108
+ },
109
+ ) => {
110
+ const { layout, showGrid, showLegend, showTooltip } = options
111
+ const isHorizontal = layout === 'horizontal'
112
+
113
+ return {
114
+ backgroundColor: 'transparent',
115
+ grid: {
116
+ top: showLegend ? 40 : 20,
117
+ right: 20,
118
+ bottom: 30,
119
+ left: isHorizontal ? 80 : 50,
120
+ containLabel: false,
121
+ },
122
+ xAxis: {
123
+ type: isHorizontal ? 'value' : 'category',
124
+ data: isHorizontal ? undefined : data.map(item => item[xField]),
125
+ axisLine: {
126
+ lineStyle: {
127
+ color: '#8899aa',
128
+ opacity: 0.3,
129
+ },
130
+ },
131
+ axisTick: { show: false },
132
+ axisLabel: {
133
+ color: '#8899aa',
134
+ fontSize: isHorizontal ? 11 : 12,
135
+ },
136
+ splitLine: {
137
+ show: showGrid,
138
+ lineStyle: {
139
+ color: '#00d4ff',
140
+ opacity: 0.1,
141
+ type: 'dashed',
142
+ },
143
+ },
144
+ },
145
+ yAxis: {
146
+ type: isHorizontal ? 'category' : 'value',
147
+ data: isHorizontal ? data.map(item => item[xField]) : undefined,
148
+ axisLine: {
149
+ lineStyle: {
150
+ color: '#8899aa',
151
+ opacity: 0.3,
152
+ },
153
+ },
154
+ axisTick: { show: false },
155
+ axisLabel: {
156
+ color: '#8899aa',
157
+ fontSize: isHorizontal ? 12 : 11,
158
+ },
159
+ splitLine: {
160
+ show: showGrid && !isHorizontal,
161
+ lineStyle: {
162
+ color: '#00d4ff',
163
+ opacity: 0.1,
164
+ type: 'dashed',
165
+ },
166
+ },
167
+ },
168
+ tooltip: showTooltip
169
+ ? {
170
+ trigger: 'axis',
171
+ axisPointer: {
172
+ type: 'shadow',
173
+ },
174
+ backgroundColor: 'rgba(0, 20, 40, 0.9)',
175
+ borderColor: '#00d4ff',
176
+ borderWidth: 1,
177
+ textStyle: {
178
+ color: '#fff',
179
+ },
180
+ }
181
+ : undefined,
182
+ legend: showLegend
183
+ ? {
184
+ show: true,
185
+ top: 10,
186
+ textStyle: {
187
+ color: '#8899aa',
188
+ fontSize: 11,
189
+ },
190
+ }
191
+ : undefined,
192
+ series,
193
+ }
194
+ }
195
+
196
+ export const BarChart: React.FC<BarChartProps> = ({
197
+ ref,
198
+ $data,
199
+ __dataSource,
200
+ xField = 'name',
201
+ yFields = ['value1', 'value2'],
202
+ colors = DEFAULT_COLORS,
203
+ layout = 'vertical',
204
+ stacked = false,
205
+ gradient = true,
206
+ borderRadius = 4,
207
+ barGap = '20%',
208
+ showGrid = true,
209
+ showLegend = true,
210
+ showTooltip = true,
211
+ glowEffect = true,
212
+ rotation = 0,
213
+ opacity = 100,
214
+ background = 'transparent',
215
+ style: externalStyle,
216
+ onClick,
217
+ onDoubleClick,
218
+ onMouseEnter,
219
+ onMouseLeave,
220
+ }) => {
221
+ const chartRef = useRef<HTMLDivElement>(null)
222
+ const chartInstance = useRef<echarts.ECharts | null>(null)
223
+
224
+ // 解析数据源
225
+ const dataSource = useDataSource($data, __dataSource)
226
+ const data = useMemo<DataPoint[]>(() => {
227
+ if (dataSource.length > 0 && dataSource[0]?.name && dataSource[0]?.value1 && dataSource[0]?.value2) {
228
+ return dataSource.map(item => ({
229
+ name: String(item.name),
230
+ value1: Number(item.value1),
231
+ value2: Number(item.value2),
232
+ }))
233
+ }
234
+ return []
235
+ }, [dataSource])
236
+
237
+ useEffect(() => {
238
+ if (!chartRef.current) {
239
+ return
240
+ }
241
+
242
+ chartInstance.current = echarts.init(chartRef.current)
243
+
244
+ // 构建 series
245
+ const series = buildSeries(yFields, data, colors, {
246
+ stacked,
247
+ gradient,
248
+ borderRadius,
249
+ glowEffect,
250
+ layout,
251
+ barGap,
252
+ })
253
+
254
+ const option = buildOption(data, xField, series, {
255
+ layout,
256
+ showGrid,
257
+ showLegend,
258
+ showTooltip,
259
+ glowEffect,
260
+ })
261
+
262
+ chartInstance.current.setOption(option)
263
+
264
+ const resizeObserver = new ResizeObserver(() => {
265
+ chartInstance.current?.resize()
266
+ })
267
+ resizeObserver.observe(chartRef.current)
268
+
269
+ return () => {
270
+ resizeObserver.disconnect()
271
+ chartInstance.current?.dispose()
272
+ }
273
+ }, [
274
+ data,
275
+ xField,
276
+ yFields,
277
+ colors,
278
+ layout,
279
+ stacked,
280
+ gradient,
281
+ borderRadius,
282
+ barGap,
283
+ showGrid,
284
+ showLegend,
285
+ showTooltip,
286
+ glowEffect,
287
+ ])
288
+
289
+ const containerStyle: CSSProperties = {
290
+ width: '100%',
291
+ height: '100%',
292
+ transform: rotation !== 0 ? `rotate(${rotation}deg)` : undefined,
293
+ opacity: opacity / 100,
294
+ backgroundColor: background,
295
+ ...externalStyle,
296
+ }
297
+
298
+ return (
299
+ <div
300
+ className={styles.container}
301
+ onClick={onClick}
302
+ onDoubleClick={onDoubleClick}
303
+ onMouseEnter={onMouseEnter}
304
+ onMouseLeave={onMouseLeave}
305
+ ref={ref}
306
+ style={containerStyle}
307
+ >
308
+ <div className={styles.chart} ref={chartRef} />
309
+ </div>
310
+ )
311
+ }
312
+
313
+ export default BarChart
package/src/meta.ts CHANGED
@@ -1,21 +1,23 @@
1
- import type { ComponentMetadata } from '@easy-editor/core'
2
- import { MaterialGroup } from '@easy-editor/materials-shared'
3
- import { COMPONENT_NAME, PACKAGE_NAME } from './constants'
4
- import { configure } from './configure'
5
- import { snippets } from './snippets'
6
- import pkg from '../package.json'
7
-
8
- export const meta: ComponentMetadata = {
9
- componentName: COMPONENT_NAME,
10
- title: '柱状图',
11
- group: MaterialGroup.CHART,
12
- devMode: 'proCode',
13
- npm: {
14
- package: PACKAGE_NAME,
15
- version: pkg.version,
16
- globalName: COMPONENT_NAME,
17
- componentName: COMPONENT_NAME,
18
- },
19
- snippets,
20
- configure,
21
- }
1
+ import type { ComponentMetadata } from '@easy-editor/core'
2
+ import { MaterialGroup } from '@easy-editor/materials-shared'
3
+ import { COMPONENT_NAME, PACKAGE_NAME } from './constants'
4
+ import { configure } from './configure'
5
+ import { snippets } from './snippets'
6
+ import pkg from '../package.json'
7
+
8
+ export const meta: ComponentMetadata = {
9
+ componentName: COMPONENT_NAME,
10
+ title: '柱状图',
11
+ group: MaterialGroup.CHART,
12
+ devMode: 'proCode',
13
+ npm: {
14
+ package: PACKAGE_NAME,
15
+ version: pkg.version,
16
+ globalName: COMPONENT_NAME,
17
+ componentName: COMPONENT_NAME,
18
+ },
19
+ snippets,
20
+ configure,
21
+ }
22
+
23
+ export default meta