@easyv/charts 1.10.28 → 1.10.30

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.
@@ -54,16 +54,34 @@ export default memo(
54
54
  const ref_container = useRef(null); // 滚动容器
55
55
  const ref_scrollTop = useRef(0); // 当前滚动距离
56
56
 
57
- const [scrollStep, setScrollStep] = useState(0); // 行高度
57
+ const [scrollStep, setScrollStep] = useState(0); // 每次滚动距离
58
+ const [loopContainerHeight, setLoopContainerHeight] = useState(null); // 按父高度推算的 loop 视口高度
58
59
 
59
- // 初始化行高
60
+ // 根据父级 height 计算可见项数,视口高度 = N*行高 + (N-1)*间距(最后一项下方不留空)
60
61
  useEffect(() => {
61
- if (ref_container.current) {
62
- const rowHeight =
63
- ref_container.current.querySelector("li").clientHeight + gridRowGap;
64
- setScrollStep(rowHeight);
62
+ if (!ref_container.current) return;
63
+ const li = ref_container.current.querySelector("li");
64
+ if (!li) return;
65
+ const itemHeight = li.offsetHeight;
66
+ const step = itemHeight + gridRowGap;
67
+ setScrollStep(step);
68
+ if (!loop.show || !height) {
69
+ setLoopContainerHeight(null);
70
+ return;
65
71
  }
66
- }, [gridRowGap]);
72
+ const totalItems = series?.length ?? 0;
73
+ const visibleCount = Math.min(
74
+ totalItems,
75
+ Math.max(1, Math.floor((height + gridRowGap) / step)),
76
+ );
77
+ setLoopContainerHeight(
78
+ visibleCount * itemHeight + Math.max(0, visibleCount - 1) * gridRowGap,
79
+ );
80
+ }, [gridRowGap, loop.show, series, height]);
81
+
82
+ const loopHeight = loop.show
83
+ ? (loopContainerHeight ?? height ?? "auto")
84
+ : "auto";
67
85
 
68
86
  // 启动自动滚动定时器
69
87
  useEffect(() => {
@@ -249,6 +267,9 @@ export default memo(
249
267
  isCenterTopOrBottom &&
250
268
  fixedColumnsPerRow > 1;
251
269
 
270
+ const columnsPerRow = Math.max(1, Number(gridTemplateColumns) || 1);
271
+ const totalRows = Math.ceil(length / columnsPerRow);
272
+
252
273
  const formatterExtra = {
253
274
  ...config,
254
275
  valueMaxWidth,
@@ -330,25 +351,26 @@ export default memo(
330
351
  );
331
352
  };
332
353
 
354
+ const legendAlignContent =
355
+ alignment.split(" ")[0] == "center" &&
356
+ (alignment.split(" ")[1] == "left" || alignment.split(" ")[1] == "right")
357
+ ? alignment.split(" ")[1] == "left"
358
+ ? "flex-start"
359
+ : "flex-end"
360
+ : alignment.split(" ")[0] == "left"
361
+ ? "flex-start"
362
+ : alignment.split(" ")[0] == "center"
363
+ ? "center"
364
+ : "flex-end";
333
365
  const stylePieOrAxis = formatter
334
366
  ? {
335
367
  display: "flex",
336
- alignContent:
337
- alignment.split(" ")[0] == "center" &&
338
- (alignment.split(" ")[1] == "left" ||
339
- alignment.split(" ")[1] == "right")
340
- ? alignment.split(" ")[1] == "left"
341
- ? "flex-start"
342
- : "flex-end"
343
- : alignment.split(" ")[0] == "left"
344
- ? "flex-start"
345
- : alignment.split(" ")[0] == "center"
346
- ? "center"
347
- : "flex-end",
368
+ alignContent: loop.show ? "flex-start" : legendAlignContent,
348
369
  flexDirection: "column",
370
+ gap: loop.show ? `${gridRowGap}px` : undefined,
349
371
  position: "absolute",
350
372
  ...getPosition(position, _alignment, x, y),
351
- height: loop.show ? height : "auto",
373
+ height: loopHeight,
352
374
  overflowY: loop.show ? "scroll" : "auto",
353
375
  }
354
376
  : {
@@ -357,7 +379,7 @@ export default memo(
357
379
  boxSizing: "border-box",
358
380
  position: "absolute",
359
381
  ...getPosition(position, _alignment, x, y),
360
- height: loop.show ? height : "auto",
382
+ height: loopHeight,
361
383
  overflowY: loop.show ? "scroll" : "auto",
362
384
  };
363
385
  if (isPieAdaptive && isSideLegend) {
@@ -369,8 +391,9 @@ export default memo(
369
391
  width: "max-content",
370
392
  maxWidth: sideLegendMaxWidth || undefined,
371
393
  alignItems: "flex-start",
394
+ ...(loop.show ? { justifyContent: "flex-start" } : {}),
372
395
  ...getPosition(position, _alignment, x, y),
373
- height: loop.show ? height : "auto",
396
+ height: loopHeight,
374
397
  overflowY: loop.show ? "scroll" : "auto",
375
398
  };
376
399
  const pieAdaptiveListStyle = {
@@ -404,7 +427,7 @@ export default memo(
404
427
  maxWidth: pieLegendFullWidth || "100%",
405
428
  boxSizing: "border-box",
406
429
  ...getPosition(position, _alignment, x, y),
407
- height: loop.show ? height : "auto",
430
+ height: loopHeight,
408
431
  overflowY: loop.show ? "scroll" : "auto",
409
432
  };
410
433
  const topBottomListStyle = {
@@ -491,7 +514,7 @@ export default memo(
491
514
  position: "absolute",
492
515
  display: "flex",
493
516
  ...getPosition(position, _alignment, x, y),
494
- height: loop.show ? height : "auto",
517
+ height: loopHeight,
495
518
  overflowY: loop.show ? "scroll" : "auto",
496
519
  }}
497
520
  ref={ref_container}
@@ -577,66 +600,60 @@ export default memo(
577
600
  ref={ref_container}
578
601
  >
579
602
  {formatter ? (
580
- [...Array(Math.ceil(series.length / gridTemplateColumns))].map(
581
- (_, indexs) => (
582
- <ul
583
- key={indexs}
584
- style={{
585
- display: "flex",
586
- width: "fit-content",
587
- justifyContent: legendMainAlign,
588
- gap: `${gridRowGap}px ${gridColumnGap}px`,
589
- marginBottom: gridRowGap + "px",
590
- }}
591
- >
592
- {_series.map((series, i) => {
593
- if (Math.floor(i / gridTemplateColumns) == indexs) {
594
- const {
595
- type,
596
- name,
597
- displayName,
598
- fieldName,
599
- icon,
600
- selected,
601
- index,
602
- } = series;
603
- const _icon = getIcon(
604
- type,
605
- icon,
606
- series?.config?.line?.type,
607
- );
608
- return (
609
- <li
610
- key={i}
611
- onClick={onClick(fieldName)}
612
- data-name={displayName || name}
613
- data-index={index}
614
- style={{
615
- display: "flex",
616
- opacity: selected === false ? opacity / 100 : 1,
617
- alignItems: "center",
618
- cursor: "pointer",
619
- gap: _icon.gap,
620
- overflow: "visible",
621
- }}
622
- >
623
- {formatter(series, {
624
- ...config,
625
- valueMaxWidth,
626
- percentMaxWidth,
627
- nameMaxWidth,
628
- otherData: data,
629
- columnsSeries,
630
- fieldColumnKeys,
631
- fieldsColumnWidths,
632
- })}
633
- </li>
634
- );
635
- }
636
- })}
637
- </ul>
638
- ),
639
- )
603
+ [...Array(totalRows)].map((_, indexs) => (
604
+ <ul
605
+ key={indexs}
606
+ style={{
607
+ display: "flex",
608
+ width: "fit-content",
609
+ justifyContent: legendMainAlign,
610
+ gap: `${gridRowGap}px ${gridColumnGap}px`,
611
+ margin: 0,
612
+ }}
613
+ >
614
+ {_series.map((series, i) => {
615
+ if (Math.floor(i / columnsPerRow) == indexs) {
616
+ const {
617
+ type,
618
+ name,
619
+ displayName,
620
+ fieldName,
621
+ icon,
622
+ selected,
623
+ index,
624
+ } = series;
625
+ const _icon = getIcon(type, icon, series?.config?.line?.type);
626
+ return (
627
+ <li
628
+ key={i}
629
+ onClick={onClick(fieldName)}
630
+ data-name={displayName || name}
631
+ data-index={index}
632
+ style={{
633
+ display: "flex",
634
+ opacity: selected === false ? opacity / 100 : 1,
635
+ alignItems: "center",
636
+ cursor: "pointer",
637
+ gap: _icon.gap,
638
+ overflow: "visible",
639
+ }}
640
+ >
641
+ {formatter(series, {
642
+ ...config,
643
+ valueMaxWidth,
644
+ percentMaxWidth,
645
+ nameMaxWidth,
646
+ otherData: data,
647
+ columnsSeries,
648
+ fieldColumnKeys,
649
+ fieldsColumnWidths,
650
+ })}
651
+ </li>
652
+ );
653
+ }
654
+ })}
655
+ </ul>
656
+ ))
640
657
  ) : (
641
658
  <ul
642
659
  style={{