1 | import { deepMix, isArray } from '@antv/util';
|
2 | import { jsx } from '../../jsx';
|
3 | import { LineViewProps } from './types';
|
4 |
|
5 | function concatPoints(children) {
|
6 | let result = [];
|
7 | for (let i = 0; i < children.length; i++) {
|
8 | const child = children[i];
|
9 | result = result.concat(child.points);
|
10 | }
|
11 | return result;
|
12 | }
|
13 |
|
14 | function formatPoint(point) {
|
15 | const { y } = point;
|
16 | return {
|
17 | x: point.x,
|
18 | y: isArray(y) ? y[1] : y,
|
19 | };
|
20 | }
|
21 |
|
22 | function getPoint(points, t: number) {
|
23 | const formatedPoints = points.map((p) => formatPoint(p));
|
24 | const firstPoint = formatedPoints[0];
|
25 | const lastPoint = formatedPoints[formatedPoints.length - 1];
|
26 | const xOffset = lastPoint.x - firstPoint.x;
|
27 | const x = firstPoint.x + xOffset * t;
|
28 |
|
29 | for (let i = 1; i < formatedPoints.length; i++) {
|
30 | const point = formatedPoints[i];
|
31 | const prevPoint = formatedPoints[i - 1];
|
32 | if (x >= prevPoint.x && x <= point.x) {
|
33 |
|
34 | const ratio = (x - prevPoint.x) / (point.x - prevPoint.x);
|
35 | return {
|
36 | x,
|
37 | y: prevPoint.y + (point.y - prevPoint.y) * ratio,
|
38 | };
|
39 | }
|
40 | }
|
41 | }
|
42 |
|
43 | function AnimationEndView(props) {
|
44 | const { record, appear, EndView } = props;
|
45 | const { children } = record;
|
46 | const points = concatPoints(children);
|
47 | const { origin } = points[0];
|
48 |
|
49 | return (
|
50 | <group
|
51 | animation={{
|
52 | appear: {
|
53 | easing: appear.easing,
|
54 | duration: appear.duration,
|
55 | onFrame: function(t) {
|
56 |
|
57 | const { element } = this;
|
58 | const children = element.get('children');
|
59 | const point = getPoint(points, t);
|
60 | children.forEach((child) => {
|
61 | child.moveTo(point.x, point.y);
|
62 | });
|
63 | },
|
64 | },
|
65 | }}
|
66 | >
|
67 | <EndView origin={origin} />
|
68 | </group>
|
69 | );
|
70 | }
|
71 |
|
72 | export default (props: LineViewProps) => {
|
73 | const { records, coord, animation, endView: EndView, clip } = props;
|
74 |
|
75 | const { left, top, width, height, center, startAngle, endAngle, radius } = coord as any;
|
76 |
|
77 | const appear = coord.isPolar
|
78 | ? {
|
79 | easing: 'quadraticOut',
|
80 | duration: 450,
|
81 | clip: {
|
82 | type: 'sector',
|
83 | property: ['endAngle'],
|
84 | attrs: {
|
85 | x: center.x,
|
86 | y: center.y,
|
87 | startAngle,
|
88 | r: radius,
|
89 | },
|
90 | start: {
|
91 | endAngle: startAngle,
|
92 | },
|
93 | end: {
|
94 | endAngle,
|
95 | },
|
96 | },
|
97 | }
|
98 | : {
|
99 | easing: 'quadraticOut',
|
100 | duration: 450,
|
101 | clip: {
|
102 | type: 'rect',
|
103 | property: ['width'],
|
104 | attrs: {
|
105 | x: left,
|
106 | y: top,
|
107 | height: height,
|
108 | },
|
109 | start: {
|
110 | width: 0,
|
111 | },
|
112 | end: {
|
113 | width: width,
|
114 | },
|
115 | },
|
116 | };
|
117 | return (
|
118 | <group
|
119 | attrs={{
|
120 | clip,
|
121 | }}
|
122 | >
|
123 | {records.map((record) => {
|
124 | const { key, children } = record;
|
125 | return (
|
126 | <group key={key}>
|
127 | {children.map((child) => {
|
128 | const { points, color, size, shape } = child;
|
129 | return (
|
130 | <polyline
|
131 | attrs={{
|
132 | points: points.map((point) => {
|
133 | return { x: point.x, y: point.y };
|
134 | }),
|
135 | stroke: color,
|
136 | ...shape,
|
137 | lineWidth: size || shape.lineWidth,
|
138 | }}
|
139 | animation={deepMix(
|
140 | {
|
141 | update: {
|
142 | easing: 'linear',
|
143 | duration: 450,
|
144 | property: ['points'],
|
145 | },
|
146 | appear,
|
147 | },
|
148 | animation
|
149 | )}
|
150 | />
|
151 | );
|
152 | })}
|
153 | {EndView ? (
|
154 | <AnimationEndView record={record} EndView={EndView} appear={appear} />
|
155 | ) : null}
|
156 | </group>
|
157 | );
|
158 | })}
|
159 | </group>
|
160 | );
|
161 | };
|