@easyv/charts 1.4.14 → 1.4.16

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 (53) hide show
  1. package/.husky/commit-msg +1 -1
  2. package/lib/components/AnimateData.js +8 -16
  3. package/lib/components/Axis.js +199 -191
  4. package/lib/components/Background.js +16 -24
  5. package/lib/components/Band.js +98 -91
  6. package/lib/components/BaseLine.js +39 -40
  7. package/lib/components/Brush.js +29 -46
  8. package/lib/components/Carousel.js +13 -40
  9. package/lib/components/CartesianChart.js +66 -86
  10. package/lib/components/Chart.js +23 -36
  11. package/lib/components/ChartContainer.js +18 -27
  12. package/lib/components/ConicalGradient.js +35 -68
  13. package/lib/components/ExtentData.js +9 -17
  14. package/lib/components/FilterData.js +16 -27
  15. package/lib/components/Indicator.js +6 -8
  16. package/lib/components/Label.js +120 -134
  17. package/lib/components/Legend.js +41 -66
  18. package/lib/components/Lighter.js +19 -48
  19. package/lib/components/Line.js +39 -59
  20. package/lib/components/LinearGradient.js +14 -20
  21. package/lib/components/Mapping.js +9 -34
  22. package/lib/components/Marquee.js +14 -30
  23. package/lib/components/PieChart.js +306 -400
  24. package/lib/components/StackData.js +8 -18
  25. package/lib/components/StereoBar.js +65 -105
  26. package/lib/components/TextOverflow.js +9 -22
  27. package/lib/components/Tooltip.js +41 -55
  28. package/lib/components/index.js +0 -27
  29. package/lib/context/index.js +0 -2
  30. package/lib/element/ConicGradient.js +29 -35
  31. package/lib/element/Line.js +9 -13
  32. package/lib/element/index.js +0 -2
  33. package/lib/formatter/index.js +0 -2
  34. package/lib/formatter/legend.js +30 -41
  35. package/lib/hooks/index.js +0 -8
  36. package/lib/hooks/useAnimateData.js +3 -16
  37. package/lib/hooks/useAxes.js +253 -114
  38. package/lib/hooks/useCarouselAxisX.js +26 -56
  39. package/lib/hooks/useExtentData.js +47 -44
  40. package/lib/hooks/useFilterData.js +8 -29
  41. package/lib/hooks/useStackData.js +7 -30
  42. package/lib/hooks/useTooltip.js +26 -43
  43. package/lib/index.js +0 -15
  44. package/lib/utils/index.js +95 -247
  45. package/package.json +55 -54
  46. package/src/components/Axis.tsx +246 -157
  47. package/src/components/Band.tsx +91 -56
  48. package/src/components/BaseLine.js +22 -5
  49. package/src/components/CartesianChart.js +1 -0
  50. package/src/components/Label.js +56 -46
  51. package/src/components/TextOverflow.tsx +1 -2
  52. package/src/hooks/useAxes.js +336 -117
  53. package/src/hooks/useExtentData.js +37 -10
@@ -1,23 +1,23 @@
1
1
  /**
2
2
  * (柱状/条形)图柱子
3
3
  */
4
- import React, { memo } from 'react';
5
- import { min, max } from 'd3v7';
6
- import { getBandBackground, getSeriesInfo } from '../utils';
4
+ import React, { memo } from "react";
5
+ import { min, max } from "d3v7";
6
+ import { getBandBackground, getSeriesInfo } from "../utils";
7
7
 
8
8
  const getHighlightData = (data: Array<DataWithBoundType>, extent: string) => {
9
9
  switch (extent) {
10
- case 'min':
10
+ case "min":
11
11
  const minData = min(data, (d: DataWithBoundType) => d.data.y);
12
12
  return data.map((item) => ({
13
13
  ...item,
14
- flag: minData == item.data.y ? 'min' : '',
14
+ flag: minData == item.data.y ? "min" : "",
15
15
  }));
16
- case 'max':
16
+ case "max":
17
17
  const maxData = max(data, (d: DataWithBoundType) => d.data.y);
18
18
  return data.map((item) => ({
19
19
  ...item,
20
- flag: maxData == item.data.y ? 'max' : '',
20
+ flag: maxData == item.data.y ? "max" : "",
21
21
  }));
22
22
  default:
23
23
  return data;
@@ -57,11 +57,11 @@ const getBorderRadius = ({
57
57
  }) => {
58
58
  return isVertical
59
59
  ? positive
60
- ? '0px ' + seriesWidth + 'px ' + seriesWidth + 'px 0'
61
- : seriesWidth + 'px 0 0 ' + seriesWidth + 'px'
60
+ ? "0px " + seriesWidth + "px " + seriesWidth + "px 0"
61
+ : seriesWidth + "px 0 0 " + seriesWidth + "px"
62
62
  : positive
63
- ? seriesWidth / 2 + 'px ' + seriesWidth / 2 + 'px 0 0'
64
- : '0 0 ' + seriesWidth / 2 + 'px ' + seriesWidth / 2 + 'px';
63
+ ? seriesWidth / 2 + "px " + seriesWidth / 2 + "px 0 0"
64
+ : "0 0 " + seriesWidth / 2 + "px " + seriesWidth / 2 + "px";
65
65
  };
66
66
 
67
67
  export default memo(
@@ -79,12 +79,12 @@ export default memo(
79
79
  border,
80
80
  opacity,
81
81
  highlight: { show: showHighlight, extent, fill: highlightFill },
82
- headDecorate
82
+ headDecorate,
83
83
  },
84
84
  bandLength = 0,
85
85
  data,
86
86
  xAxis: { scaler: xScaler, step, direction },
87
- yAxis: { scaler: yScaler },
87
+ yAxis: { scaler: yScaler, isClipAxis, clipValue },
88
88
  }: any) => {
89
89
  if (!data.length) return null;
90
90
 
@@ -97,10 +97,10 @@ export default memo(
97
97
 
98
98
  const _data = showHighlight ? getHighlightData(data, extent) : data;
99
99
 
100
- const isVertical = direction === 'vertical';
100
+ const isVertical = direction === "vertical";
101
101
  const borderStr = `${border.borderColor} solid ${border.borderWidth}px`;
102
102
  return (
103
- <g className='__easyv-band'>
103
+ <g className="__easyv-band">
104
104
  {_data.map(
105
105
  (
106
106
  {
@@ -112,21 +112,47 @@ export default memo(
112
112
  }: DataWithBoundType,
113
113
  i: number
114
114
  ) => {
115
- const y1 = yScaler(isVertical ? end : start);
116
- const y2 = yScaler(isVertical ? start : end);
115
+ //todo 柱状中空设置
116
+ let y1:number, y2: number;
117
+ //断轴图相关,断轴图的scaler是一个数组,内含上断轴下断轴的scaler
118
+ if (isClipAxis) {
119
+ if (end > +clipValue) {
120
+ y1 = yScaler[1](start);
121
+ y2 = yScaler[0](end);
122
+ } else {
123
+ y1 = yScaler[1](start);
124
+ y2 = yScaler[1](end);
125
+ }
126
+ } else {
127
+ y1 = yScaler(isVertical ? end : start);
128
+ y2 = yScaler(isVertical ? start : end);
129
+ }
117
130
 
118
131
  const positionX =
119
132
  xScaler(x) - step / 2 + seriesStart + index * seriesStep;
120
133
 
121
- let showHead , headUrl, headWidth, headHeight, headTranslate;
122
- if(headDecorate){
123
- showHead = headDecorate.show,
124
- headUrl = headDecorate.url,
125
- headWidth = headDecorate.size.width,
126
- headHeight = headDecorate.size.height,
127
- headTranslate = headDecorate.translate;
134
+ let showHead, headUrl, headWidth, headHeight, headTranslate;
135
+ if (headDecorate) {
136
+ (showHead = headDecorate.show),
137
+ (headUrl = headDecorate.url),
138
+ (headWidth = headDecorate.size.width),
139
+ (headHeight = headDecorate.size.height),
140
+ (headTranslate = headDecorate.translate);
128
141
  }
129
-
142
+ //断轴图相关,将柱形在断轴处切开
143
+ const setClipPath = () => {
144
+ if (isClipAxis && end > +clipValue) {
145
+ let clipValueY2 = yScaler[0](clipValue); //上方
146
+ let clipValueY1 = yScaler[1](clipValue); //下方
147
+ let top = Math.abs((y2-clipValueY2)/(y1-y2))*100;
148
+ let bottom = Math.abs((y2-clipValueY1)/(y1-y2))*100;
149
+
150
+ //clip path属性
151
+ return `polygon(0% 0%, 0% 100%, 0 100%, 0 ${top}%, 100% ${top}%, 100% ${bottom}%, 0 ${bottom}%, 0 100%, 100% 100%, 100% 0%)`;
152
+ } else {
153
+ return "none";
154
+ }
155
+ };
130
156
  if (isNaN(positionX)) return null;
131
157
  const positionY = y < 0 ? y1 : y2;
132
158
  const attr = getAttr({
@@ -140,58 +166,67 @@ export default memo(
140
166
  <foreignObject
141
167
  key={i}
142
168
  style={{
143
- overflow:"visible",
144
- position:"relative",
145
- cursor:"pointer"
169
+ overflow: "visible",
170
+ position: "relative",
171
+ cursor: "pointer",
146
172
  }}
147
173
  {...attr}
148
174
  onClick={triggerClick}
149
175
  data-data={JSON.stringify(data)}
150
176
  >
151
- {headUrl && showHead && <div style={{
152
- position:"absolute",
153
- background:`url(${window.appConfig.ASSETS_URL+headUrl}) 0 0/100% 100%`,
154
- width:headWidth,
155
- height:headHeight,
156
- left:isVertical?"100%":"50%",
157
- top:isVertical?"50%":"0",
158
- zIndex:1,
159
- transform:`translate(calc(-50% + ${headTranslate.x}px), calc(-50% + ${headTranslate.y}px))`
160
- }}></div>}
177
+ {headUrl && showHead && (
178
+ <div
179
+ style={{
180
+ position: "absolute",
181
+ background: `url(${
182
+ window.appConfig.ASSETS_URL + headUrl
183
+ }) 0 0/100% 100%`,
184
+ width: headWidth,
185
+ height: headHeight,
186
+ left: isVertical ? "100%" : "50%",
187
+ top: isVertical ? "50%" : "0",
188
+ zIndex: 1,
189
+ transform: `translate(calc(-50% + ${headTranslate.x}px), calc(-50% + ${headTranslate.y}px))`,
190
+ }}
191
+ ></div>
192
+ )}
161
193
  <div
162
194
  style={{
163
- width: '100%',
164
- height: '100%',
195
+ width: "100%",
196
+ height: "100%",
165
197
  /** Safari Bug **/
166
- position: 'fixed',
167
- opacity: fillType == 'pattern' ? opacity : 1,
198
+ position: "fixed",
199
+ clipPath: setClipPath(),
200
+ opacity: fillType == "pattern" ? opacity : 1,
168
201
  background:
169
- fillType == 'pattern'
202
+ fillType == "pattern"
170
203
  ? `50% 50% / ${size.width}px ${size.height}px repeat ` +
171
- 'url(' +
204
+ "url(" +
172
205
  url +
173
- ')'
206
+ ")"
174
207
  : getBandBackground(
175
208
  pattern,
176
209
  extent === flag ? highlightFill : fill
177
210
  ),
178
211
  borderRadius:
179
- style == 'square'
180
- ? '0 0 0 0'
212
+ style == "square"
213
+ ? "0 0 0 0"
181
214
  : getBorderRadius({
182
215
  isVertical,
183
216
  positive: y > 0,
184
217
  seriesWidth,
185
218
  }),
186
- ...(isVertical?{
187
- borderTop:borderStr,
188
- borderRight:borderStr,
189
- borderBottom:borderStr
190
- }:{
191
- borderTop:borderStr,
192
- borderRight:borderStr,
193
- borderLeft:borderStr
194
- })
219
+ ...(isVertical
220
+ ? {
221
+ borderTop: borderStr,
222
+ borderRight: borderStr,
223
+ borderBottom: borderStr,
224
+ }
225
+ : {
226
+ borderTop: borderStr,
227
+ borderRight: borderStr,
228
+ borderLeft: borderStr,
229
+ }),
195
230
  }}
196
231
  />
197
232
  </foreignObject>
@@ -34,14 +34,31 @@ export default memo(
34
34
  strokeDasharray,
35
35
  },
36
36
  },
37
- yAxis: { scaler: yScaler },
37
+ yAxis: { scaler: yScaler,clipValue,isClipAxis },
38
38
  data
39
39
  }) => {
40
40
  try{
41
- const x1 = orientation == 'left' ? yScaler(data.value) : marginLeft,
42
- x2 = orientation == 'left' ? yScaler(data.value) : width - marginRight,
43
- y1 = orientation == 'left' ? marginLeft : yScaler(data.value),
44
- y2 = orientation == 'left' ? height - marginRight : yScaler(data.value);
41
+
42
+ let x1,x2,y1,y2
43
+ if (isClipAxis) {
44
+ if (data.value > +clipValue) {
45
+ x1 = orientation == 'left' ? yScaler[0](data.value) : marginLeft,
46
+ x2 = orientation == 'left' ? yScaler[0](data.value) : width - marginRight,
47
+ y1 = orientation == 'left' ? marginLeft : yScaler[0](data.value),
48
+ y2 = orientation == 'left' ? height - marginRight : yScaler[0](data.value);
49
+ } else {
50
+ x1 = orientation == 'left' ? yScaler[1](data.value) : marginLeft,
51
+ x2 = orientation == 'left' ? yScaler[1](data.value) : width - marginRight,
52
+ y1 = orientation == 'left' ? marginLeft : yScaler[1](data.value),
53
+ y2 = orientation == 'left' ? height - marginRight : yScaler[1](data.value);
54
+ }
55
+ } else {
56
+ x1 = orientation == 'left' ? yScaler(data.value) : marginLeft,
57
+ x2 = orientation == 'left' ? yScaler(data.value) : width - marginRight,
58
+ y1 = orientation == 'left' ? marginLeft : yScaler(data.value),
59
+ y2 = orientation == 'left' ? height - marginRight : yScaler(data.value);
60
+ }
61
+
45
62
  return (
46
63
  <>
47
64
  <g className='__easyv-baseLine' >
@@ -70,6 +70,7 @@ const Chart = memo(
70
70
  } = useContext(chartContext);
71
71
  const svg = useRef();
72
72
  const axes = useAxes({ axes: axesConfig, context });
73
+
73
74
  const axisX = useCarouselAxisX(axes.get('x'), animation, isHover);
74
75
  const xLineRange = width-marginLeft-marginRight;
75
76
  const yLineRange = height-marginTop-marginBottom;
@@ -1,9 +1,9 @@
1
1
  /**
2
2
  * 轴类图表标签
3
3
  */
4
- import { memo, useContext } from 'react';
5
- import { getTranslate2d, getSeriesInfo } from '../utils';
6
- import { chartContext } from '../context';
4
+ import { memo, useContext } from "react";
5
+ import { getTranslate2d, getSeriesInfo } from "../utils";
6
+ import { chartContext } from "../context";
7
7
 
8
8
  export default memo(
9
9
  ({
@@ -17,10 +17,10 @@ export default memo(
17
17
  bandLength = 0,
18
18
  data,
19
19
  xAxis: { scaler: xScaler, step, direction },
20
- yAxis: { scaler: yScaler },
20
+ yAxis: { scaler: yScaler, isClipAxis, clipValue },
21
21
  triggerClick,
22
22
  }) => {
23
- const lineType = config.hasOwnProperty('line'); // 堆叠处理
23
+ const lineType = config.hasOwnProperty("line"); // 堆叠处理
24
24
  const showIcon = icon && icon.show;
25
25
  const showLabel = label && label.show;
26
26
 
@@ -33,30 +33,40 @@ export default memo(
33
33
  paddingInner,
34
34
  paddingOuter,
35
35
  });
36
- const isVertical = direction === 'vertical';
36
+ const isVertical = direction === "vertical";
37
37
  const _position = label.position;
38
38
  return (
39
- <g className='__easyv-label'>
39
+ <g className="__easyv-label">
40
40
  {data.map(
41
41
  (
42
42
  { index, bound: [start, end], data, data: { x, y, showY, s } },
43
43
  i
44
44
  ) => {
45
- const y1 = yScaler(isVertical ? end : start);
46
-
47
- // 处理z型折线图和堆叠柱图的逻辑冲突
48
- const y2 = lineType
49
- ? start
50
- ? yScaler(isVertical ? start : end - start)
51
- : yScaler(isVertical ? start : end)
52
- : yScaler(isVertical ? start : end);
45
+ let y1, y2;
46
+ if (isClipAxis) {
47
+ if (end > +clipValue) {
48
+ y1 = yScaler[1](start);
49
+ y2 = yScaler[0](end);
50
+ } else {
51
+ y1 = yScaler[1](start);
52
+ y2 = yScaler[1](end);
53
+ }
54
+ } else {
55
+ y1 = yScaler(isVertical ? end : start);
56
+ // 处理z型折线图和堆叠柱图的逻辑冲突
57
+ y2 = lineType
58
+ ? start
59
+ ? yScaler(isVertical ? start : end - start)
60
+ : yScaler(isVertical ? start : end)
61
+ : yScaler(isVertical ? start : end);
62
+ }
53
63
 
54
64
  // const y2 = yScaler(isVertical ? start : end);
55
65
  const positionX =
56
66
  xScaler(x) - step / 2 + seriesStart + index * seriesStep;
57
67
 
58
68
  if (isNaN(positionX)) return null;
59
- const position = positionX + (config.line?step:seriesWidth) / 2;
69
+ const position = positionX + (config.line ? step : seriesWidth) / 2;
60
70
  const labelPosition = isVertical
61
71
  ? getVerticalLabel({
62
72
  position: _position,
@@ -76,18 +86,18 @@ export default memo(
76
86
  ? {
77
87
  ...labelPosition,
78
88
  y: position,
79
- dominantBaseline: 'middle',
89
+ dominantBaseline: "middle",
80
90
  }
81
91
  : {
82
92
  ...labelPosition,
83
93
  x: position,
84
- textAnchor: 'middle',
94
+ textAnchor: "middle",
85
95
  };
86
96
  return (
87
97
  <g
88
98
  key={i}
89
99
  onClick={triggerClick}
90
- style={{cursor:"pointer"}}
100
+ style={{ cursor: "pointer" }}
91
101
  data-data={JSON.stringify(data)}
92
102
  >
93
103
  {showIcon && !isNaN(attr.y) && (
@@ -111,8 +121,8 @@ const Label = ({
111
121
  font,
112
122
  translate: { x: translateX = 0, y: translateY = 0 },
113
123
  },
114
- textAnchor = 'middle',
115
- dominantBaseline = 'middle',
124
+ textAnchor = "middle",
125
+ dominantBaseline = "middle",
116
126
  }) => {
117
127
  return (
118
128
  <text
@@ -143,9 +153,9 @@ const Icon = ({
143
153
  size: { width, height },
144
154
  },
145
155
  }) =>
146
- mode == 'single' ? (
156
+ mode == "single" ? (
147
157
  <Circle cx={cx} cy={cy} color={color} radius={radius} />
148
- ) : mode == 'double' ? (
158
+ ) : mode == "double" ? (
149
159
  <>
150
160
  <Circle cx={cx} cy={cy} {...outer} />
151
161
  <Circle cx={cx} cy={cy} {...inner} />
@@ -163,64 +173,64 @@ const Icon = ({
163
173
  );
164
174
 
165
175
  const Circle = ({ cx, cy, color, radius }) => (
166
- <circle cx={cx} cy={cy} fill={color} r={radius} stroke='none' />
176
+ <circle cx={cx} cy={cy} fill={color} r={radius} stroke="none" />
167
177
  );
168
178
 
169
- const getVerticalLabel = ({ position = 'outerStart', width, y, y1, y2 }) => {
179
+ const getVerticalLabel = ({ position = "outerStart", width, y, y1, y2 }) => {
170
180
  switch (position) {
171
- case 'start':
181
+ case "start":
172
182
  return {
173
183
  x: y > 0 ? y2 : y1,
174
- textAnchor: 'start',
184
+ textAnchor: "start",
175
185
  };
176
- case 'middle':
186
+ case "middle":
177
187
  return {
178
188
  x: (y1 + y2) / 2,
179
- textAnchor: 'middle',
189
+ textAnchor: "middle",
180
190
  };
181
- case 'end':
191
+ case "end":
182
192
  return {
183
193
  x: y > 0 ? y1 : y2,
184
- textAnchor: 'end',
194
+ textAnchor: "end",
185
195
  };
186
- case 'outerStart':
196
+ case "outerStart":
187
197
  return {
188
198
  x: y1,
189
- textAnchor: y > 0 ? 'start' : 'end',
199
+ textAnchor: y > 0 ? "start" : "end",
190
200
  };
191
- case 'chartStart':
201
+ case "chartStart":
192
202
  return {
193
203
  x: y > 0 ? width : 0,
194
- textAnchor: y > 0 ? 'start' : 'end',
204
+ textAnchor: y > 0 ? "start" : "end",
195
205
  };
196
206
  }
197
207
  };
198
- const getHorizontalLabel = ({ position = 'outerStart', height, y, y1, y2 }) => {
208
+ const getHorizontalLabel = ({ position = "outerStart", height, y, y1, y2 }) => {
199
209
  switch (position) {
200
- case 'start':
210
+ case "start":
201
211
  return {
202
212
  y: y > 0 ? y1 : y2,
203
- dominantBaseline: 'text-after-edge',
213
+ dominantBaseline: "text-after-edge",
204
214
  };
205
- case 'middle':
215
+ case "middle":
206
216
  return {
207
217
  y: (y1 + y2) / 2,
208
- dominantBaseline: 'middle',
218
+ dominantBaseline: "middle",
209
219
  };
210
- case 'end':
220
+ case "end":
211
221
  return {
212
222
  y: y > 0 ? y2 : y1,
213
- dominantBaseline: 'text-before-edge',
223
+ dominantBaseline: "text-before-edge",
214
224
  };
215
- case 'outerStart':
225
+ case "outerStart":
216
226
  return {
217
227
  y: y2,
218
- dominantBaseline: y >= 0 ? 'text-after-edge' : 'text-before-edge',
228
+ dominantBaseline: y >= 0 ? "text-after-edge" : "text-before-edge",
219
229
  };
220
- case 'chartStart':
230
+ case "chartStart":
221
231
  return {
222
232
  y: y > 0 ? 0 : height,
223
- dominantBaseline: y > 0 ? 'text-after-edge' : 'text-before-edge',
233
+ dominantBaseline: y > 0 ? "text-after-edge" : "text-before-edge",
224
234
  };
225
235
  }
226
236
  };
@@ -47,7 +47,6 @@ export default memo(forwardRef((props:flowText, ref:any) => {
47
47
  ...getTextOverflow(type),
48
48
  ...style
49
49
  }
50
-
51
50
  return type == 'marquee' ? (
52
51
  <Marquee
53
52
  value={value}
@@ -55,6 +54,6 @@ export default memo(forwardRef((props:flowText, ref:any) => {
55
54
  style={styles}
56
55
  ref={ref} />
57
56
  ) : (
58
- <div style={styles} ref={ref} title={type=="ellipsis"?value || undefined:undefined} dangerouslySetInnerHTML={{__html:value}}></div>
57
+ <div style={styles} ref={ref} title={type=="ellipsis"?value.replace(/<\/?.+?>/g,"") || undefined:undefined} dangerouslySetInnerHTML={{__html:value}}></div>
59
58
  );
60
59
  }));