@semcore/d3-chart 2.0.9 → 2.2.0

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.
Files changed (105) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/lib/cjs/Area.js +70 -29
  3. package/lib/cjs/Area.js.map +1 -1
  4. package/lib/cjs/Bar.js +6 -4
  5. package/lib/cjs/Bar.js.map +1 -1
  6. package/lib/cjs/Bubble.js +1 -0
  7. package/lib/cjs/Bubble.js.map +1 -1
  8. package/lib/cjs/Donut.js +120 -44
  9. package/lib/cjs/Donut.js.map +1 -1
  10. package/lib/cjs/Dots.js +24 -25
  11. package/lib/cjs/Dots.js.map +1 -1
  12. package/lib/cjs/GroupBar.js +7 -7
  13. package/lib/cjs/GroupBar.js.map +1 -1
  14. package/lib/cjs/Line.js +4 -2
  15. package/lib/cjs/Line.js.map +1 -1
  16. package/lib/cjs/ReferenceLine.js +258 -0
  17. package/lib/cjs/ReferenceLine.js.map +1 -0
  18. package/lib/cjs/ResponsiveContainer.js +1 -1
  19. package/lib/cjs/ResponsiveContainer.js.map +1 -1
  20. package/lib/cjs/ScatterPlot.js +1 -0
  21. package/lib/cjs/ScatterPlot.js.map +1 -1
  22. package/lib/cjs/StackBar.js +6 -6
  23. package/lib/cjs/StackedArea.js +7 -7
  24. package/lib/cjs/Tooltip.js +3 -2
  25. package/lib/cjs/Tooltip.js.map +1 -1
  26. package/lib/cjs/createElement.js +4 -3
  27. package/lib/cjs/createElement.js.map +1 -1
  28. package/lib/cjs/index.js +8 -0
  29. package/lib/cjs/index.js.map +1 -1
  30. package/lib/cjs/style/dot.shadow.css +10 -5
  31. package/lib/cjs/style/reference-line.shadow.css +37 -0
  32. package/lib/cjs/types/Area.d.ts +1 -0
  33. package/lib/cjs/types/Bar.d.ts +4 -0
  34. package/lib/cjs/types/Bubble.d.ts +6 -1
  35. package/lib/cjs/types/Donut.d.ts +4 -0
  36. package/lib/cjs/types/ReferenceLine.d.ts +31 -0
  37. package/lib/cjs/types/Tooltip.d.ts +5 -3
  38. package/lib/cjs/types/index.d.ts +3 -0
  39. package/lib/es6/Area.js +68 -27
  40. package/lib/es6/Area.js.map +1 -1
  41. package/lib/es6/Bar.js +6 -4
  42. package/lib/es6/Bar.js.map +1 -1
  43. package/lib/es6/Bubble.js +1 -0
  44. package/lib/es6/Bubble.js.map +1 -1
  45. package/lib/es6/Donut.js +114 -44
  46. package/lib/es6/Donut.js.map +1 -1
  47. package/lib/es6/Dots.js +24 -23
  48. package/lib/es6/Dots.js.map +1 -1
  49. package/lib/es6/GroupBar.js +7 -7
  50. package/lib/es6/GroupBar.js.map +1 -1
  51. package/lib/es6/Line.js +4 -2
  52. package/lib/es6/Line.js.map +1 -1
  53. package/lib/es6/ReferenceLine.js +244 -0
  54. package/lib/es6/ReferenceLine.js.map +1 -0
  55. package/lib/es6/ResponsiveContainer.js +1 -1
  56. package/lib/es6/ResponsiveContainer.js.map +1 -1
  57. package/lib/es6/ScatterPlot.js +1 -0
  58. package/lib/es6/ScatterPlot.js.map +1 -1
  59. package/lib/es6/StackBar.js +6 -6
  60. package/lib/es6/StackedArea.js +7 -7
  61. package/lib/es6/Tooltip.js +3 -2
  62. package/lib/es6/Tooltip.js.map +1 -1
  63. package/lib/es6/createElement.js +3 -3
  64. package/lib/es6/createElement.js.map +1 -1
  65. package/lib/es6/index.js +1 -0
  66. package/lib/es6/index.js.map +1 -1
  67. package/lib/es6/style/dot.shadow.css +10 -5
  68. package/lib/es6/style/reference-line.shadow.css +37 -0
  69. package/lib/es6/types/Area.d.ts +1 -0
  70. package/lib/es6/types/Bar.d.ts +4 -0
  71. package/lib/es6/types/Bubble.d.ts +6 -1
  72. package/lib/es6/types/Donut.d.ts +4 -0
  73. package/lib/es6/types/ReferenceLine.d.ts +31 -0
  74. package/lib/es6/types/Tooltip.d.ts +5 -3
  75. package/lib/es6/types/index.d.ts +3 -0
  76. package/lib/types/Area.d.ts +1 -0
  77. package/lib/types/Bar.d.ts +4 -0
  78. package/lib/types/Bubble.d.ts +6 -1
  79. package/lib/types/Donut.d.ts +4 -0
  80. package/lib/types/ReferenceLine.d.ts +31 -0
  81. package/lib/types/Tooltip.d.ts +5 -3
  82. package/lib/types/index.d.ts +3 -0
  83. package/package.json +11 -11
  84. package/src/Area.jsx +41 -8
  85. package/src/Bar.jsx +6 -5
  86. package/src/Bubble.jsx +1 -0
  87. package/src/Donut.jsx +96 -29
  88. package/src/Dots.jsx +11 -14
  89. package/src/GroupBar.jsx +1 -1
  90. package/src/Line.jsx +2 -1
  91. package/src/ReferenceLine.jsx +146 -0
  92. package/src/ResponsiveContainer.jsx +1 -1
  93. package/src/ScatterPlot.jsx +1 -0
  94. package/src/Tooltip.jsx +2 -3
  95. package/src/createElement.jsx +4 -2
  96. package/src/index.js +1 -0
  97. package/src/style/dot.shadow.css +10 -5
  98. package/src/style/reference-line.shadow.css +37 -0
  99. package/src/types/Area.d.ts +1 -0
  100. package/src/types/Bar.d.ts +4 -0
  101. package/src/types/Bubble.d.ts +6 -1
  102. package/src/types/Donut.d.ts +4 -0
  103. package/src/types/ReferenceLine.d.ts +31 -0
  104. package/src/types/Tooltip.d.ts +5 -3
  105. package/src/types/index.d.ts +3 -0
@@ -1,20 +1,21 @@
1
1
  @import '@semcore/utils/style/var.css';
2
2
  @import '@semcore/d3-chart/src/style/var.css';
3
3
 
4
+ SDots {
5
+ & SDot {
6
+ transition-duration: var(--duration);
7
+ }
8
+ }
9
+
4
10
  SDot {
5
11
  stroke-width: 2px;
6
12
  stroke: #fff;
7
13
  r: 6px;
8
14
  fill: var(--blue-03);
9
15
  transition-property: cx, cy;
10
- transition-duration: var(--duration);
11
16
  transition-timing-function: ease-in-out;
12
17
  }
13
18
 
14
- SDot[color] {
15
- fill: var(--color);
16
- }
17
-
18
19
  SDot[hide] {
19
20
  display: none;
20
21
  }
@@ -22,3 +23,7 @@ SDot[hide] {
22
23
  SDot[active] {
23
24
  r: 8px;
24
25
  }
26
+
27
+ SDot[color] {
28
+ fill: var(--color);
29
+ }
@@ -0,0 +1,37 @@
1
+ @import '@semcore/utils/style/var.css';
2
+
3
+ SReferenceLine {
4
+ fill: none;
5
+ stroke: var(--gray-300);
6
+ }
7
+
8
+ STitle {
9
+ font-size: var(--fs-100);
10
+ fill: var(--gray-500);
11
+ transform-origin: var(--transform-origin);
12
+ }
13
+
14
+ STitle[position='top'] {
15
+ text-anchor: middle;
16
+ }
17
+
18
+ STitle[position='bottom'] {
19
+ text-anchor: middle;
20
+ alignment-baseline: hanging;
21
+ }
22
+
23
+ STitle[position='right'] {
24
+ transform: rotate(-90deg);
25
+ alignment-baseline: middle;
26
+ text-anchor: middle;
27
+ }
28
+
29
+ STitle[position='left'] {
30
+ transform: rotate(-90deg);
31
+ text-anchor: middle;
32
+ alignment-baseline: middle;
33
+ }
34
+
35
+ SBackground {
36
+ fill: color-mod(var(--gray-200) a(20%));
37
+ }
@@ -42,6 +42,7 @@ export interface IAreaNullProps extends IContext {
42
42
  declare const Area: (<T>(props: CProps<IAreaProps & T>) => ReturnEl) & {
43
43
  Dots: <T>(props: CProps<IAreaDotsProps & T, IAreaDotsContext>) => ReturnEl;
44
44
  Null: <T>(props: CProps<IAreaNullProps & T>) => ReturnEl;
45
+ Line: <T>(props: CProps<IContext & T>) => ReturnEl;
45
46
  };
46
47
 
47
48
  export default Area;
@@ -19,6 +19,10 @@ export interface IBarProps extends IContext {
19
19
  * @default 2
20
20
  */
21
21
  r?: number | number[];
22
+ /** Minimal height
23
+ * @default 4
24
+ */
25
+ hMin?: number;
22
26
  }
23
27
 
24
28
  export interface IBarContext {
@@ -22,6 +22,11 @@ export interface IBubbleProps extends IContext {
22
22
  duration?: number;
23
23
  }
24
24
 
25
- declare const Bubble: <T>(props: CProps<IBubbleProps & T>) => ReturnEl;
25
+ export interface IBubbleContext {
26
+ /** Index element of data */
27
+ index: number;
28
+ }
29
+
30
+ declare const Bubble: <T>(props: CProps<IBubbleProps & T, IBubbleContext>) => ReturnEl;
26
31
 
27
32
  export default Bubble;
@@ -27,6 +27,10 @@ export interface IPieProps extends IContext {
27
27
  @default #50aef4
28
28
  **/
29
29
  color?: string;
30
+ /**
31
+ * Active sector
32
+ * */
33
+ active?: boolean;
30
34
  }
31
35
 
32
36
  export interface IEmptyDataProps extends IContext {}
@@ -0,0 +1,31 @@
1
+ import { CProps, ReturnEl } from '@semcore/core';
2
+ import IContext from './context';
3
+
4
+ export interface IReferenceLineProps extends IContext {
5
+ /** The position of the title relative reference line
6
+ * @default 'left' */
7
+ position?: 'top' | 'right' | 'bottom' | 'left';
8
+ /** Value element of data */
9
+ value: any;
10
+ }
11
+
12
+ export interface IReferenceLineTitleProps extends IContext {
13
+ /** The position of the axis relative reference line */
14
+ position?: 'top' | 'right' | 'bottom' | 'left';
15
+ /** Value element of data */
16
+ value: any;
17
+ }
18
+
19
+ export interface IReferenceLineBackgroundProps extends IContext {
20
+ /** The position of the axis relative reference line */
21
+ position?: 'top' | 'right' | 'bottom' | 'left';
22
+ /** Value element of data */
23
+ value: any;
24
+ }
25
+
26
+ declare const ReferenceLine: (<T>(props: CProps<IReferenceLineProps & T>) => ReturnEl) & {
27
+ Title: <T>(props: CProps<IReferenceLineTitleProps & T>) => ReturnEl;
28
+ Background: <T>(props: CProps<IReferenceLineBackgroundProps & T>) => ReturnEl;
29
+ };
30
+
31
+ export default ReferenceLine;
@@ -4,14 +4,14 @@ import { CProps, PropGetterFn, ReturnEl } from '@semcore/core';
4
4
  import { IBoxProps } from '@semcore/flex-box';
5
5
  import IContext from './context';
6
6
 
7
- export interface ITooltipProps extends IPopperProps, IPopperTriggerProps, IContext {
7
+ export interface ITooltipChartProps extends IPopperProps, IPopperTriggerProps, IContext {
8
8
  /** Field from data for XAxis */
9
9
  x?: string;
10
10
  /** Field from data for YAxis */
11
11
  y?: string;
12
12
  }
13
13
 
14
- export interface ITooltipContext {
14
+ export interface ITooltipChartContext {
15
15
  getTriggerProps: PropGetterFn;
16
16
  getPopperProps: PropGetterFn;
17
17
  /** Index active value for Axis x */
@@ -20,7 +20,9 @@ export interface ITooltipContext {
20
20
  yIndex: number | null;
21
21
  }
22
22
 
23
- declare const Tooltip: (<T>(props: CProps<ITooltipProps & T, ITooltipContext>) => ReturnEl) & {
23
+ declare const Tooltip: (<T>(
24
+ props: CProps<ITooltipChartProps & T, ITooltipChartContext>,
25
+ ) => ReturnEl) & {
24
26
  Trigger: <T>(props: CProps<ComponentProps<typeof Popper.Trigger> & T>) => ReturnEl;
25
27
  Popper: <T>(props: CProps<ComponentProps<typeof Popper.Popper> & T>) => ReturnEl;
26
28
  Title: <T>(props: CProps<IBoxProps & T>) => ReturnEl;
@@ -51,3 +51,6 @@ export * from './ScatterPlot';
51
51
 
52
52
  export { default as Bubble } from './Bubble';
53
53
  export * from './Bubble';
54
+
55
+ export { default as ReferenceLine } from './ReferenceLine';
56
+ export * from './ReferenceLine';
@@ -42,6 +42,7 @@ export interface IAreaNullProps extends IContext {
42
42
  declare const Area: (<T>(props: CProps<IAreaProps & T>) => ReturnEl) & {
43
43
  Dots: <T>(props: CProps<IAreaDotsProps & T, IAreaDotsContext>) => ReturnEl;
44
44
  Null: <T>(props: CProps<IAreaNullProps & T>) => ReturnEl;
45
+ Line: <T>(props: CProps<IContext & T>) => ReturnEl;
45
46
  };
46
47
 
47
48
  export default Area;
@@ -19,6 +19,10 @@ export interface IBarProps extends IContext {
19
19
  * @default 2
20
20
  */
21
21
  r?: number | number[];
22
+ /** Minimal height
23
+ * @default 4
24
+ */
25
+ hMin?: number;
22
26
  }
23
27
 
24
28
  export interface IBarContext {
@@ -22,6 +22,11 @@ export interface IBubbleProps extends IContext {
22
22
  duration?: number;
23
23
  }
24
24
 
25
- declare const Bubble: <T>(props: CProps<IBubbleProps & T>) => ReturnEl;
25
+ export interface IBubbleContext {
26
+ /** Index element of data */
27
+ index: number;
28
+ }
29
+
30
+ declare const Bubble: <T>(props: CProps<IBubbleProps & T, IBubbleContext>) => ReturnEl;
26
31
 
27
32
  export default Bubble;
@@ -27,6 +27,10 @@ export interface IPieProps extends IContext {
27
27
  @default #50aef4
28
28
  **/
29
29
  color?: string;
30
+ /**
31
+ * Active sector
32
+ * */
33
+ active?: boolean;
30
34
  }
31
35
 
32
36
  export interface IEmptyDataProps extends IContext {}
@@ -0,0 +1,31 @@
1
+ import { CProps, ReturnEl } from '@semcore/core';
2
+ import IContext from './context';
3
+
4
+ export interface IReferenceLineProps extends IContext {
5
+ /** The position of the title relative reference line
6
+ * @default 'left' */
7
+ position?: 'top' | 'right' | 'bottom' | 'left';
8
+ /** Value element of data */
9
+ value: any;
10
+ }
11
+
12
+ export interface IReferenceLineTitleProps extends IContext {
13
+ /** The position of the axis relative reference line */
14
+ position?: 'top' | 'right' | 'bottom' | 'left';
15
+ /** Value element of data */
16
+ value: any;
17
+ }
18
+
19
+ export interface IReferenceLineBackgroundProps extends IContext {
20
+ /** The position of the axis relative reference line */
21
+ position?: 'top' | 'right' | 'bottom' | 'left';
22
+ /** Value element of data */
23
+ value: any;
24
+ }
25
+
26
+ declare const ReferenceLine: (<T>(props: CProps<IReferenceLineProps & T>) => ReturnEl) & {
27
+ Title: <T>(props: CProps<IReferenceLineTitleProps & T>) => ReturnEl;
28
+ Background: <T>(props: CProps<IReferenceLineBackgroundProps & T>) => ReturnEl;
29
+ };
30
+
31
+ export default ReferenceLine;
@@ -4,14 +4,14 @@ import { CProps, PropGetterFn, ReturnEl } from '@semcore/core';
4
4
  import { IBoxProps } from '@semcore/flex-box';
5
5
  import IContext from './context';
6
6
 
7
- export interface ITooltipProps extends IPopperProps, IPopperTriggerProps, IContext {
7
+ export interface ITooltipChartProps extends IPopperProps, IPopperTriggerProps, IContext {
8
8
  /** Field from data for XAxis */
9
9
  x?: string;
10
10
  /** Field from data for YAxis */
11
11
  y?: string;
12
12
  }
13
13
 
14
- export interface ITooltipContext {
14
+ export interface ITooltipChartContext {
15
15
  getTriggerProps: PropGetterFn;
16
16
  getPopperProps: PropGetterFn;
17
17
  /** Index active value for Axis x */
@@ -20,7 +20,9 @@ export interface ITooltipContext {
20
20
  yIndex: number | null;
21
21
  }
22
22
 
23
- declare const Tooltip: (<T>(props: CProps<ITooltipProps & T, ITooltipContext>) => ReturnEl) & {
23
+ declare const Tooltip: (<T>(
24
+ props: CProps<ITooltipChartProps & T, ITooltipChartContext>,
25
+ ) => ReturnEl) & {
24
26
  Trigger: <T>(props: CProps<ComponentProps<typeof Popper.Trigger> & T>) => ReturnEl;
25
27
  Popper: <T>(props: CProps<ComponentProps<typeof Popper.Popper> & T>) => ReturnEl;
26
28
  Title: <T>(props: CProps<IBoxProps & T>) => ReturnEl;
@@ -51,3 +51,6 @@ export * from './ScatterPlot';
51
51
 
52
52
  export { default as Bubble } from './Bubble';
53
53
  export * from './Bubble';
54
+
55
+ export { default as ReferenceLine } from './ReferenceLine';
56
+ export * from './ReferenceLine';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@semcore/d3-chart",
3
3
  "description": "SEMRush D3 Chart Component",
4
- "version": "2.0.9",
4
+ "version": "2.2.0",
5
5
  "main": "lib/cjs/index.js",
6
6
  "module": "lib/es6/index.js",
7
7
  "typings": "lib/types/index.d.ts",
@@ -19,12 +19,12 @@
19
19
  "@semcore/utils": "^3.15",
20
20
  "@upsetjs/venn.js": "1.4.1",
21
21
  "d3-array": "3.1.6",
22
- "d3-shape": "3.1.0",
23
- "d3-scale": "3.3.0",
24
22
  "d3-interpolate": "3.0.1",
23
+ "d3-scale": "3.3.0",
24
+ "d3-shape": "3.1.0",
25
25
  "d3-transition": "3.0.1",
26
- "resize-observer-polyfill": "1.5.1",
27
- "hoist-non-react-statics": "3.3.2"
26
+ "hoist-non-react-statics": "3.3.2",
27
+ "resize-observer-polyfill": "1.5.1"
28
28
  },
29
29
  "peerDependencies": {
30
30
  "@semcore/core": "^1.11",
@@ -39,14 +39,14 @@
39
39
  "directory": "semcore/d3-chart"
40
40
  },
41
41
  "devDependencies": {
42
+ "@semcore/button": "*",
43
+ "@semcore/checkbox": "*",
44
+ "@semcore/dropdown-menu": "*",
45
+ "@semcore/icon": "*",
42
46
  "@semcore/jest-preset-ui": "1.0.0",
47
+ "@semcore/typography": "*",
43
48
  "@types/d3-array": "^3.0.2",
44
49
  "@types/d3-scale": "^4.0.2",
45
- "@types/d3-transition": "^3.0.1",
46
- "@semcore/typography": "*",
47
- "@semcore/dropdown-menu": "*",
48
- "@semcore/button": "*",
49
- "@semcore/checkbox": "*",
50
- "@semcore/icon": "*"
50
+ "@types/d3-transition": "^3.0.1"
51
51
  }
52
52
  }
package/src/Area.jsx CHANGED
@@ -6,6 +6,7 @@ import createElement from './createElement';
6
6
  import { definedData, scaleOfBandwidth, getNullData, definedNullData } from './utils';
7
7
  import ClipPath from './ClipPath';
8
8
  import uniqueIDEnhancement from '@semcore/utils/lib/uniqueID';
9
+ import findComponent from '@semcore/utils/lib/findComponent';
9
10
 
10
11
  import style from './style/area.shadow.css';
11
12
 
@@ -55,18 +56,34 @@ class AreaRoot extends Component {
55
56
  };
56
57
  }
57
58
 
59
+ getLineProps() {
60
+ const { duration, color, data, d3Line, uid } = this.asProps;
61
+
62
+ return {
63
+ uid,
64
+ data,
65
+ d3: d3Line,
66
+ color,
67
+ duration,
68
+ };
69
+ }
70
+
58
71
  render() {
59
72
  const SArea = this.Element;
60
73
  const SAreaLine = 'path';
61
- const { styles, hide, d3, d3Line, data, color, uid, size, duration } = this.asProps;
74
+ const { styles, hide, d3, d3Line, data, color, uid, size, duration, Children } = this.asProps;
75
+ const advanceMode = !!findComponent(Children, [Area.Line.displayName]);
76
+
62
77
  return sstyled(styles)(
63
78
  <>
64
- <SAreaLine
65
- clipPath={`url(#${uid})`}
66
- d={d3Line(data)}
67
- color={color}
68
- use:duration={`${duration}ms`}
69
- />
79
+ {!advanceMode && (
80
+ <SAreaLine
81
+ clipPath={`url(#${uid})`}
82
+ d={d3Line(data)}
83
+ color={color}
84
+ use:duration={`${duration}ms`}
85
+ />
86
+ )}
70
87
  <SArea
71
88
  clipPath={`url(#${uid})`}
72
89
  render="path"
@@ -93,12 +110,28 @@ class AreaRoot extends Component {
93
110
  }
94
111
  }
95
112
 
113
+ function Line(props) {
114
+ const { Element: SAreaLine, styles, d3, data, color, duration, uid } = props;
115
+ return sstyled(styles)(
116
+ <SAreaLine
117
+ render="path"
118
+ clipPath={`url(#${uid})`}
119
+ d={d3(data)}
120
+ color={color}
121
+ use:duration={`${duration}ms`}
122
+ />,
123
+ );
124
+ }
125
+
96
126
  function Null(props) {
97
127
  const { Element: SNull, styles, d3, data, hide, color } = props;
98
128
  return sstyled(styles)(<SNull render="path" d={d3(data)} hide={hide} color={color} />);
99
129
  }
100
130
 
101
- export default createElement(AreaRoot, {
131
+ const Area = createElement(AreaRoot, {
102
132
  Dots,
103
133
  Null,
134
+ Line,
104
135
  });
136
+
137
+ export default Area;
package/src/Bar.jsx CHANGED
@@ -17,6 +17,7 @@ class BarRoot extends Component {
17
17
  offset: [0, 0],
18
18
  duration: 500,
19
19
  r: 2,
20
+ hMin: 4,
20
21
  };
21
22
 
22
23
  getBackgroundProps(props, index) {
@@ -58,15 +59,15 @@ class BarRoot extends Component {
58
59
  duration,
59
60
  uid,
60
61
  r,
62
+ hMin,
61
63
  width: widthProps,
62
64
  } = this.asProps;
63
65
 
64
66
  const [xScale, yScale] = scale;
65
- const barY = yScale(Math.max(d[y0] ?? 0, d[y])) + offset[1];
67
+ const barY = yScale(Math.max(d[y0] ?? 0, d[y])) + offset[1] - (Object.is(d[y], 0) ? hMin : 0);
66
68
  const barX = xScale(d[x]) + offset[0];
67
- const height = Math.abs(
68
- yScale(d[y]) - Math.min(yScale(yScale.domain()[0]), yScale(d[y0] ?? 0)),
69
- );
69
+ const height =
70
+ Math.abs(yScale(d[y]) - Math.min(yScale(yScale.domain()[0]), yScale(d[y0] ?? 0))) || hMin;
70
71
  const width = widthProps || getBandwidth(xScale);
71
72
  const dSvg = getRect({
72
73
  x: barX,
@@ -74,7 +75,7 @@ class BarRoot extends Component {
74
75
  width,
75
76
  height,
76
77
  radius: Array.isArray(r) ? r[i] : r,
77
- position: d[y] > 0 ? 'top' : 'bottom',
78
+ position: d[y] > 0 || Object.is(d[y], 0) ? 'top' : 'bottom',
78
79
  });
79
80
 
80
81
  return sstyled(styles)(
package/src/Bubble.jsx CHANGED
@@ -117,6 +117,7 @@ class BubbleRoot extends Component {
117
117
  )}
118
118
  <SBubble
119
119
  id={`${uid}${uid}`}
120
+ index={i}
120
121
  render="circle"
121
122
  clipPath={`url(#${uid})`}
122
123
  cx={xScale(d[x]) + offset[0]}
package/src/Donut.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import React from 'react';
1
+ import React, { useEffect, useState } from 'react';
2
2
  import { arc, pie } from 'd3-shape';
3
3
  import { Component, sstyled } from '@semcore/core';
4
4
  import canUseDOM from '@semcore/utils/lib/canUseDOM';
@@ -13,7 +13,7 @@ import style from './style/donut.shadow.css';
13
13
 
14
14
  const DEFAULT_INSTANCE = Symbol('DEFAULT_INSTANCE');
15
15
 
16
- function animationInitialPie({ halfsize, d3Arc, arcs }) {
16
+ function animationInitialPie({ halfsize, d3Arc, d3ArcOut, arcs, activeIndexPie }) {
17
17
  return function (_, ind) {
18
18
  const d = arcs[ind];
19
19
  if (!d) return () => '';
@@ -22,7 +22,7 @@ function animationInitialPie({ halfsize, d3Arc, arcs }) {
22
22
  return function (t) {
23
23
  d.startAngle = iStart(t);
24
24
  d.endAngle = iEnd(t);
25
- return d3Arc(d);
25
+ return ind === activeIndexPie ? d3ArcOut(d) : d3Arc(d);
26
26
  };
27
27
  };
28
28
  }
@@ -84,6 +84,11 @@ class DonutRoot extends Component {
84
84
  const d3Arc = arc()
85
85
  .outerRadius(getOuterRadius({ size, halfsize, outerRadius }))
86
86
  .innerRadius(innerRadius > increaseFactor ? innerRadius - increaseFactor : innerRadius);
87
+
88
+ const d3ArcOut = arc()
89
+ .outerRadius(getOuterRadius({ size, halfsize, outerRadius }) + increaseFactor)
90
+ .innerRadius(innerRadius > increaseFactor ? innerRadius - increaseFactor : innerRadius);
91
+
87
92
  let d3Pie = pie()
88
93
  .sort(null)
89
94
  .value(([, value]) => value);
@@ -95,6 +100,7 @@ class DonutRoot extends Component {
95
100
  return {
96
101
  d3Pie,
97
102
  d3Arc,
103
+ d3ArcOut,
98
104
  duration: 500,
99
105
  };
100
106
  };
@@ -105,6 +111,7 @@ class DonutRoot extends Component {
105
111
  }
106
112
 
107
113
  virtualElement = canUseDOM() ? document.createElement('div') : {};
114
+ activeIndexPie = undefined;
108
115
 
109
116
  generateGetBoundingClientRect(x = 0, y = 0) {
110
117
  return () => ({ width: 0, height: 0, top: y, right: x, bottom: y, left: x });
@@ -137,41 +144,67 @@ class DonutRoot extends Component {
137
144
  return d3Pie(pieData);
138
145
  }
139
146
 
140
- bindHandlerTooltip = (visible, props) => ({ clientX: x, clientY: y }) => {
141
- const { eventEmitter } = this.asProps;
142
- this.virtualElement.getBoundingClientRect = this.generateGetBoundingClientRect(x, y);
143
- this.virtualElement[CONSTANT.VIRTUAL_ELEMENT] = true;
144
- eventEmitter.emit('onTooltipVisible', visible, props, this.virtualElement);
145
- };
147
+ bindHandlerTooltip =
148
+ (visible, props) =>
149
+ ({ clientX: x, clientY: y }) => {
150
+ const { eventEmitter } = this.asProps;
151
+ this.virtualElement.getBoundingClientRect = this.generateGetBoundingClientRect(x, y);
152
+ this.virtualElement[CONSTANT.VIRTUAL_ELEMENT] = true;
153
+ eventEmitter.emit('onTooltipVisible', visible, props, this.virtualElement);
154
+ };
146
155
 
147
- getPieProps(props) {
148
- let { d3Arc, duration, innerRadius } = this.asProps;
156
+ animationActivePie = (props) => {
157
+ let { duration, innerRadius } = this.asProps;
158
+ const { active, data, selector } = props;
149
159
  innerRadius = innerRadius > increaseFactor ? innerRadius - increaseFactor : innerRadius;
150
160
  const outerRadius = getOuterRadius(this.asProps);
161
+ active
162
+ ? animationHoverPie({
163
+ d: data,
164
+ selector: `#${this.id} ${selector}`,
165
+ duration: duration === 0 ? 0 : 300,
166
+ innerRadius,
167
+ outerRadius: [outerRadius, outerRadius + increaseFactor],
168
+ })
169
+ : animationHoverPie({
170
+ d: data,
171
+ selector: `#${this.id} ${selector}`,
172
+ duration: duration === 0 ? 0 : 300,
173
+ innerRadius,
174
+ outerRadius: [outerRadius + increaseFactor, outerRadius],
175
+ });
176
+ };
177
+
178
+ getPieProps(props, ind) {
179
+ const { d3Arc, d3ArcOut } = this.asProps;
180
+ const { active } = props;
151
181
  const data = this.arcs.find((arc) => arc.data[0] === props.dataKey);
182
+ if (active) {
183
+ this.activeIndexPie = ind;
184
+ }
152
185
 
153
186
  return {
154
187
  data,
155
188
  d3Arc,
189
+ d3ArcOut,
190
+ $animationActivePie: this.animationActivePie,
156
191
  onMouseMove: this.bindHandlerTooltip(true, props),
157
192
  onMouseLeave: this.bindHandlerTooltip(false, props),
158
193
  onMouseOver: (e) => {
159
- animationHoverPie({
160
- d: data,
161
- selector: `#${this.id} [d="${e.target.getAttribute('d')}"]`,
162
- duration: duration === 0 ? 0 : 300,
163
- innerRadius,
164
- outerRadius: [outerRadius, outerRadius + increaseFactor],
165
- });
194
+ !active &&
195
+ this.animationActivePie({
196
+ active: true,
197
+ data,
198
+ selector: `[d="${e.target.getAttribute('d')}"]`,
199
+ });
166
200
  },
167
201
  onMouseOut: (e) => {
168
- animationHoverPie({
169
- d: data,
170
- selector: `#${this.id} [d="${e.target.getAttribute('d')}"]`,
171
- duration: duration === 0 ? 0 : 300,
172
- innerRadius,
173
- outerRadius: [outerRadius + increaseFactor, outerRadius],
174
- });
202
+ !active &&
203
+ this.animationActivePie({
204
+ active: false,
205
+ data,
206
+ selector: `[d="${e.target.getAttribute('d')}"]`,
207
+ });
175
208
  },
176
209
  };
177
210
  }
@@ -197,8 +230,9 @@ class DonutRoot extends Component {
197
230
  }
198
231
 
199
232
  componentDidMount() {
200
- const { duration, d3Arc, halfsize } = this.asProps;
233
+ const { duration, d3Arc, halfsize, d3ArcOut } = this.asProps;
201
234
  const arcs = this.arcs;
235
+
202
236
  if (duration > 0) {
203
237
  transition()
204
238
  .selection()
@@ -208,7 +242,16 @@ class DonutRoot extends Component {
208
242
  })
209
243
  .transition()
210
244
  .duration(duration)
211
- .attrTween('d', animationInitialPie({ halfsize, d3Arc, arcs }));
245
+ .attrTween(
246
+ 'd',
247
+ animationInitialPie({
248
+ halfsize,
249
+ d3Arc,
250
+ d3ArcOut,
251
+ arcs,
252
+ activeIndexPie: this.activeIndexPie,
253
+ }),
254
+ );
212
255
  }
213
256
  }
214
257
 
@@ -229,8 +272,32 @@ class DonutRoot extends Component {
229
272
  }
230
273
  }
231
274
 
232
- function Pie({ Element: SPie, styles, d3Arc, data, color }) {
233
- return sstyled(styles)(<SPie render="path" color={color} d={d3Arc(data)} />);
275
+ function Pie({
276
+ Element: SPie,
277
+ styles,
278
+ d3Arc,
279
+ data,
280
+ color,
281
+ $animationActivePie,
282
+ active,
283
+ d3ArcOut,
284
+ ...other
285
+ }) {
286
+ const [isMount, setIsMount] = useState(false);
287
+ useEffect(() => {
288
+ //you should't run animation for first render
289
+ if (!isMount) {
290
+ setIsMount(true);
291
+ return;
292
+ }
293
+ if (active !== undefined && active !== null) {
294
+ //name must unique on page
295
+ $animationActivePie({ ...other, active, data, selector: `[name="${other.name}"]` });
296
+ }
297
+ }, [active]);
298
+ return sstyled(styles)(
299
+ <SPie render="path" color={color} d={active ? d3ArcOut(data) : d3Arc(data)} />,
300
+ );
234
301
  }
235
302
 
236
303
  function EmptyData({ Element: SEmptyData, styles, d3Arc, color }) {