@easyv/charts 1.8.23 → 1.8.25

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.
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * 图例
3
3
  */
4
- import React, { memo, useCallback, useState, useEffect, useRef } from 'react';
5
- import { getIcon, sortPie } from '../utils';
6
- import TextOverflow from './TextOverflow';
4
+ import React, { memo, useCallback, useState, useEffect, useRef } from "react";
5
+ import { getIcon, sortPie } from "../utils";
6
+ import TextOverflow from "./TextOverflow";
7
7
 
8
8
  const defaultFont = {
9
- fontStyle: 'normal',
10
- fontWeight: 'normal',
9
+ fontStyle: "normal",
10
+ fontWeight: "normal",
11
11
  };
12
12
 
13
13
  export default memo(
@@ -17,14 +17,14 @@ export default memo(
17
17
  config,
18
18
  config: {
19
19
  show,
20
- order = '',
20
+ order = "",
21
21
  interactive,
22
- LegendType,//类型
22
+ LegendType, //类型
23
23
  maxWidth,
24
24
  textOverflow,
25
25
  speed,
26
26
  layout: {
27
- alignment = 'right center',
27
+ alignment = "right center",
28
28
  gridTemplateColumns,
29
29
  gridGap: { gridColumnGap, gridRowGap },
30
30
  translate: { x, y },
@@ -35,7 +35,8 @@ export default memo(
35
35
  },
36
36
  filterData,
37
37
  formatter,
38
- judge
38
+ judge,
39
+ pieClick,
39
40
  }) => {
40
41
  if (!show) return null;
41
42
 
@@ -47,7 +48,8 @@ export default memo(
47
48
  // 初始化行高
48
49
  useEffect(() => {
49
50
  if (ref_container.current) {
50
- const rowHeight = ref_container.current.querySelector('li').clientHeight + gridRowGap;
51
+ const rowHeight =
52
+ ref_container.current.querySelector("li").clientHeight + gridRowGap;
51
53
  setScrollStep(rowHeight);
52
54
  }
53
55
  }, [gridRowGap]);
@@ -64,12 +66,12 @@ export default memo(
64
66
 
65
67
  // 清除定时器
66
68
  return () => clearInterval(timer);
67
- }, [scrollStep, loop.show, loop.interval])
68
-
69
+ }, [scrollStep, loop.show, loop.interval]);
70
+
69
71
  const handleAutoScroll = () => {
70
72
  const table = ref_container.current;
71
73
  if (!table) return;
72
-
74
+
73
75
  // 如果已经滚动到了底部,则返回顶部
74
76
  if (ref_scrollTop.current + table.clientHeight >= table.scrollHeight) {
75
77
  ref_scrollTop.current = 0;
@@ -78,11 +80,11 @@ export default memo(
78
80
  ref_scrollTop.current += scrollStep;
79
81
  }
80
82
 
81
- table.scrollTo({ top: ref_scrollTop.current, behavior: 'smooth' });
83
+ table.scrollTo({ top: ref_scrollTop.current, behavior: "smooth" });
82
84
  };
83
85
 
84
86
  const _series = sortPie(series, order);
85
- const [_alignment, position] = alignment.split(' ');
87
+ const [_alignment, position] = alignment.split(" ");
86
88
  const length = _series.length;
87
89
 
88
90
  const onClick = useCallback(
@@ -90,168 +92,249 @@ export default memo(
90
92
  const { dataset } = e.currentTarget;
91
93
  const { name } = dataset;
92
94
  filterData && interactive && filterData(name);
95
+ pieClick && pieClick(e);
93
96
  },
94
- [interactive, filterData]
97
+ [interactive, filterData, pieClick]
95
98
  );
96
99
 
97
100
  if (judge == 0) {
98
101
  _series.forEach((d) => {
99
- d.percent=0
100
- })
102
+ d.percent = 0;
103
+ });
101
104
  }
102
105
 
103
106
  // 计算最大宽度
104
107
  const valueFont = config.value?.font || {};
105
108
  const percentFont = config.percent?.font || {};
106
- const valueSuffix = config.value?.suffix?.text || '';
109
+ const valueSuffix = config.value?.suffix?.text || "";
107
110
  const valueSplitConfig = config.value?.splitConfig || {};
108
111
  const getValueStr = (item) => {
109
- let valueStr = (item.data?.y ?? item.value ?? '') + (valueSuffix || '');
112
+ let valueStr = (item.data?.y ?? item.value ?? "") + (valueSuffix || "");
110
113
  if (valueSplitConfig.show && valueSplitConfig.separator) {
111
- valueStr = valueStr.toString().replace(/\B(?=(\d{3})+(?!\d))/g, valueSplitConfig.separator);
114
+ valueStr = valueStr
115
+ .toString()
116
+ .replace(/\B(?=(\d{3})+(?!\d))/g, valueSplitConfig.separator);
112
117
  }
113
118
  return valueStr;
114
119
  };
115
120
  const valueMaxWidth = Math.max(
116
- ..._series.map(item => parseFloat(getCanvasTextWidth(getValueStr(item), valueFont.letterSpacing || 0, `${valueFont.fontSize || 12}px ${valueFont.fontFamily || 'Arial'}`)))
121
+ ..._series.map((item) =>
122
+ parseFloat(
123
+ getCanvasTextWidth(
124
+ getValueStr(item),
125
+ valueFont.letterSpacing || 0,
126
+ `${valueFont.fontSize || 12}px ${valueFont.fontFamily || "Arial"}`
127
+ )
128
+ )
129
+ )
117
130
  );
118
131
  const percentMaxWidth = Math.max(
119
- ..._series.map(item => {
120
- const percentStr = (item.percent !== undefined ? item.percent : item.data?.percent) + '%';
121
- return parseFloat(getCanvasTextWidth(percentStr, percentFont.letterSpacing || 0, `${percentFont.fontSize || 12}px ${percentFont.fontFamily || 'Arial'}`));
132
+ ..._series.map((item) => {
133
+ const percentStr =
134
+ (item.percent !== undefined ? item.percent : item.data?.percent) +
135
+ "%";
136
+ return parseFloat(
137
+ getCanvasTextWidth(
138
+ percentStr,
139
+ percentFont.letterSpacing || 0,
140
+ `${percentFont.fontSize || 12}px ${
141
+ percentFont.fontFamily || "Arial"
142
+ }`
143
+ )
144
+ );
122
145
  })
123
146
  );
124
147
  const nameMaxWidth = config.name?.maxWidth || 80;
125
148
 
126
- const stylePieOrAxis=formatter?{
127
- display:'flex',
128
- alignContent:alignment.split(" ")[0]=="center"&&(alignment.split(" ")[1]=="left"||alignment.split(" ")[1]=="right")?alignment.split(" ")[1]=="left"?"flex-start":"flex-end":alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
129
- flexDirection:"column",
130
- position: 'absolute',
131
- ...getPosition(position, _alignment, x, y),
132
- height: loop.show ? height : 'auto',
133
- overflowY: loop.show ? 'scroll' : 'auto'
134
- }:{
135
- display:'flex',
136
- flexWrap:"wrap",
137
- alignContent:alignment.split(" ")[0]=="center"&&(alignment.split(" ")[1]=="left"||alignment.split(" ")[1]=="right")?alignment.split(" ")[1]=="left"?"flex-start":"flex-end":alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
138
- flexDirection: "column",
139
- position: 'absolute',
140
- ...getPosition(position, _alignment, x, y),
141
- height: loop.show ? height : 'auto',
142
- overflowY: loop.show ? 'scroll' : 'auto'
143
- }
144
- return (
145
- LegendType=="FixedWidth"?
149
+ const stylePieOrAxis = formatter
150
+ ? {
151
+ display: "flex",
152
+ alignContent:
153
+ alignment.split(" ")[0] == "center" &&
154
+ (alignment.split(" ")[1] == "left" ||
155
+ alignment.split(" ")[1] == "right")
156
+ ? alignment.split(" ")[1] == "left"
157
+ ? "flex-start"
158
+ : "flex-end"
159
+ : alignment.split(" ")[0] == "left"
160
+ ? "flex-start"
161
+ : alignment.split(" ")[0] == "center"
162
+ ? "center"
163
+ : "flex-end",
164
+ flexDirection: "column",
165
+ position: "absolute",
166
+ ...getPosition(position, _alignment, x, y),
167
+ height: loop.show ? height : "auto",
168
+ overflowY: loop.show ? "scroll" : "auto",
169
+ }
170
+ : {
171
+ display: "flex",
172
+ flexWrap: "wrap",
173
+ alignContent:
174
+ alignment.split(" ")[0] == "center" &&
175
+ (alignment.split(" ")[1] == "left" ||
176
+ alignment.split(" ")[1] == "right")
177
+ ? alignment.split(" ")[1] == "left"
178
+ ? "flex-start"
179
+ : "flex-end"
180
+ : alignment.split(" ")[0] == "left"
181
+ ? "flex-start"
182
+ : alignment.split(" ")[0] == "center"
183
+ ? "center"
184
+ : "flex-end",
185
+ flexDirection: "column",
186
+ position: "absolute",
187
+ ...getPosition(position, _alignment, x, y),
188
+ height: loop.show ? height : "auto",
189
+ overflowY: loop.show ? "scroll" : "auto",
190
+ };
191
+ return LegendType == "FixedWidth" ? (
146
192
  <div
147
- className='__easyv-legend-wrapper'
193
+ className="__easyv-legend-wrapper"
148
194
  style={{
149
- position: 'absolute',
150
- display: 'flex',
195
+ position: "absolute",
196
+ display: "flex",
151
197
  ...getPosition(position, _alignment, x, y),
152
- height: loop.show ? height : 'auto',
153
- overflowY: loop.show ? 'scroll' : 'auto'
198
+ height: loop.show ? height : "auto",
199
+ overflowY: loop.show ? "scroll" : "auto",
154
200
  }}
155
201
  ref={ref_container}
156
202
  >
157
203
  <ul
158
204
  style={{
159
- display: 'grid',
160
- gridGap: gridRowGap + 'px ' + gridColumnGap + 'px',
161
- gridTemplateColumns:formatter?`${nameMaxWidth}px ${valueMaxWidth}px ${percentMaxWidth}px`:
162
- 'repeat(' + Math.min(gridTemplateColumns, length) + ', 1fr)',//饼图或者柱状图配合不同的图例显示格式
205
+ display: "grid",
206
+ gridGap: gridRowGap + "px " + gridColumnGap + "px",
207
+ gridTemplateColumns: formatter
208
+ ? `${nameMaxWidth}px ${valueMaxWidth}px ${percentMaxWidth}px`
209
+ : "repeat(" + Math.min(gridTemplateColumns, length) + ", 1fr)", //饼图或者柱状图配合不同的图例显示格式
163
210
  }}
164
211
  >
165
- {_series.map((series, index) => {
166
- const { type, name, displayName, icon, selected } = series;
212
+ {_series.map((series, i) => {
213
+ const { type, name, displayName, icon, selected, index } = series;
167
214
  const _icon = getIcon(type, icon, series?.config?.line?.type);
168
215
  return (
169
216
  <li
170
- key={index}
217
+ key={i}
171
218
  onClick={onClick}
172
- data-name={name}
219
+ data-name={displayName || name}
220
+ data-index={index}
173
221
  style={{
174
- display: 'flex',
222
+ display: "flex",
175
223
  opacity: selected === false ? opacity / 100 : 1,
176
- alignItems: 'center',
224
+ alignItems: "center",
177
225
  cursor: "pointer",
178
226
  gap: _icon.gap,
179
227
  }}
180
228
  >
181
229
  {formatter ? (
182
- formatter(series, { ...config, valueMaxWidth, percentMaxWidth, nameMaxWidth })
230
+ formatter(series, {
231
+ ...config,
232
+ valueMaxWidth,
233
+ percentMaxWidth,
234
+ nameMaxWidth,
235
+ })
183
236
  ) : (
184
237
  <>
185
238
  <span style={_icon} />
186
- <TextOverflow type={textOverflow} value={displayName || name} style={{
239
+ <TextOverflow
240
+ type={textOverflow}
241
+ value={displayName || name}
242
+ style={{
187
243
  ...font,
188
- width:maxWidth,
189
- fontStyle: italic ? 'italic' : 'normal',
190
- fontWeight: bold ? 'bold' : 'normal',
191
- }} speed={speed}></TextOverflow>
192
-
244
+ width: maxWidth,
245
+ fontStyle: italic ? "italic" : "normal",
246
+ fontWeight: bold ? "bold" : "normal",
247
+ }}
248
+ speed={speed}
249
+ ></TextOverflow>
193
250
  </>
194
251
  )}
195
252
  </li>
196
253
  );
197
254
  })}
198
255
  </ul>
199
- </div>:<div
200
- className='__easyv-legend-wrapper'
256
+ </div>
257
+ ) : (
258
+ <div
259
+ className="__easyv-legend-wrapper"
201
260
  style={stylePieOrAxis}
202
261
  ref={ref_container}
203
262
  >
204
-
205
- {[...Array(Math.ceil(series.length/gridTemplateColumns))].map((_,indexs)=>(
206
- <ul
207
- key={indexs}
208
- style={{
209
- display: 'flex',
210
- width: 'fit-content',
211
- justifyContent:alignment.split(" ")[0]=="left"?"flex-start":alignment.split(" ")[0]=="center"?"center":"flex-end",
212
- marginBottom:"0px",
213
- gap:`${gridRowGap}px ${gridColumnGap}px`,
214
- marginBottom:gridRowGap+"px"
215
- }}
216
- >
217
- {_series.map((series, index) => {
218
- if(Math.floor(index/gridTemplateColumns)==indexs){
219
- const { type, name, displayName, icon, selected } = series;
220
- const _icon = getIcon(type, icon, series?.config?.line?.type);
221
- return (
222
- <li
223
- key={index}
224
- onClick={onClick}
225
- data-name={name}
263
+ {[...Array(Math.ceil(series.length / gridTemplateColumns))].map(
264
+ (_, indexs) => (
265
+ <ul
266
+ key={indexs}
226
267
  style={{
227
- display: 'flex',
228
- opacity: selected === false ? opacity / 100 : 1,
229
- alignItems: 'center',
230
- cursor: "pointer",
231
- gap: _icon.gap,
268
+ display: "flex",
269
+ width: "fit-content",
270
+ justifyContent:
271
+ alignment.split(" ")[0] == "left"
272
+ ? "flex-start"
273
+ : alignment.split(" ")[0] == "center"
274
+ ? "center"
275
+ : "flex-end",
276
+ marginBottom: "0px",
277
+ gap: `${gridRowGap}px ${gridColumnGap}px`,
278
+ marginBottom: gridRowGap + "px",
232
279
  }}
233
280
  >
234
- {formatter ? (
235
- formatter(series, { ...config, valueMaxWidth, percentMaxWidth, nameMaxWidth })
236
- ) : (
237
- <>
238
- <span style={_icon} />
239
- <TextOverflow ShowType={LegendType} type="ellipsis" value={displayName || name} style={{
240
- ...font,
241
- fontStyle: italic ? 'italic' : 'normal',
242
- fontWeight: bold ? 'bold' : 'normal',
243
- minWidth:getCanvasTextWidth(displayName?(displayName.substring(0,5) || name.substring(0,5)):"",font.letterSpacing,`${font.fontSize}px ${font.fontFamily}` )
244
- }} speed={speed}></TextOverflow>
245
-
246
- </>
247
- )}
248
- </li>
249
- );
250
- }
251
- })}
252
- </ul>
253
- ))
254
- }
281
+ {_series.map((series, i) => {
282
+ if (Math.floor(i / gridTemplateColumns) == indexs) {
283
+ const { type, name, displayName, icon, selected, index } =
284
+ series;
285
+ const _icon = getIcon(type, icon, series?.config?.line?.type);
286
+ return (
287
+ <li
288
+ key={i}
289
+ onClick={onClick}
290
+ data-name={displayName || name}
291
+ data-index={index}
292
+ style={{
293
+ display: "flex",
294
+ opacity: selected === false ? opacity / 100 : 1,
295
+ alignItems: "center",
296
+ cursor: "pointer",
297
+ gap: _icon.gap,
298
+ }}
299
+ >
300
+ {formatter ? (
301
+ formatter(series, {
302
+ ...config,
303
+ valueMaxWidth,
304
+ percentMaxWidth,
305
+ nameMaxWidth,
306
+ })
307
+ ) : (
308
+ <>
309
+ <span style={_icon} />
310
+ <TextOverflow
311
+ ShowType={LegendType}
312
+ type="ellipsis"
313
+ value={displayName || name}
314
+ style={{
315
+ ...font,
316
+ fontStyle: italic ? "italic" : "normal",
317
+ fontWeight: bold ? "bold" : "normal",
318
+ minWidth: getCanvasTextWidth(
319
+ displayName
320
+ ? displayName.substring(0, 5) ||
321
+ name.substring(0, 5)
322
+ : "",
323
+ font.letterSpacing,
324
+ `${font.fontSize}px ${font.fontFamily}`
325
+ ),
326
+ }}
327
+ speed={speed}
328
+ ></TextOverflow>
329
+ </>
330
+ )}
331
+ </li>
332
+ );
333
+ }
334
+ })}
335
+ </ul>
336
+ )
337
+ )}
255
338
  </div>
256
339
  );
257
340
  }
@@ -259,38 +342,42 @@ const stylePieOrAxis=formatter?{
259
342
 
260
343
  const getPosition = (position, alignment, x = 0, y = 0) => {
261
344
  switch (position) {
262
- case 'top':
345
+ case "top":
263
346
  return {
264
- left: alignment == 'left' ? 5 : alignment == 'center' ? '50%' : '',
265
- right: alignment == 'right' ? 10 : '',
347
+ left: alignment == "left" ? 5 : alignment == "center" ? "50%" : "",
348
+ right: alignment == "right" ? 10 : "",
266
349
  top: 5,
267
- transform: `translate3d(calc(${alignment == 'center' ? '-50%' : '0px'} + ${x}px), ${y}px, 0px)`
350
+ transform: `translate3d(calc(${
351
+ alignment == "center" ? "-50%" : "0px"
352
+ } + ${x}px), ${y}px, 0px)`,
268
353
  };
269
- case 'right':
354
+ case "right":
270
355
  return {
271
- top: '50%',
356
+ top: "50%",
272
357
  right: 10,
273
- transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`
358
+ transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`,
274
359
  };
275
- case 'left':
360
+ case "left":
276
361
  return {
277
- top: '50%',
362
+ top: "50%",
278
363
  left: 5,
279
- transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`
364
+ transform: `translate3d(${x}px, calc(-50% + ${y}px), 0px)`,
280
365
  };
281
366
  default: // bottom
282
367
  return {
283
- left: alignment == 'left' ? 5 : alignment == 'center' ? '50%' : '',
284
- right: alignment == 'right' ? 10 : '',
368
+ left: alignment == "left" ? 5 : alignment == "center" ? "50%" : "",
369
+ right: alignment == "right" ? 10 : "",
285
370
  bottom: 5,
286
- transform: `translate3d(calc(${alignment == 'center' ? '-50%' : '0px'} + ${x}px), ${y}px, 0px)`
371
+ transform: `translate3d(calc(${
372
+ alignment == "center" ? "-50%" : "0px"
373
+ } + ${x}px), ${y}px, 0px)`,
287
374
  };
288
375
  }
289
376
  };
290
- const getCanvasTextWidth=(text,letterSpacing, font = '16px Arial')=>{
291
- const canvas = document.createElement('canvas');
292
- const ctx = canvas.getContext('2d');
377
+ const getCanvasTextWidth = (text, letterSpacing, font = "16px Arial") => {
378
+ const canvas = document.createElement("canvas");
379
+ const ctx = canvas.getContext("2d");
293
380
  ctx.font = font;
294
- return ctx.measureText(text).width+(text.length)*letterSpacing+"px";
381
+ return ctx.measureText(text).width + text.length * letterSpacing + "px";
295
382
  // return ctx.measureText(text).width+(text.length-1)*letterSpacing+"px";//-1有bug
296
- }
383
+ };
@@ -653,6 +653,7 @@ const Component = memo(
653
653
  ...arc,
654
654
  percent: arc.percent.toFixed(legendPrecision),
655
655
  }))}
656
+ pieClick={onClick}
656
657
  formatter={formatter}
657
658
  judge={judgeData}
658
659
  />
@@ -921,6 +922,7 @@ const Component = memo(
921
922
  ...arc,
922
923
  percent: arc.percent.toFixed(legendPrecision),
923
924
  }))}
925
+ pieClick={onClick}
924
926
  formatter={formatter}
925
927
  judge={judgeData}
926
928
  />