26
26
>
27
27
<div class =" label__value" >{{ value }}</div >
28
28
<div class =" label__title" v-if =" labels" >{{ labels[index] }}</div >
29
+ <div class =" label__percentage" v-if =" displayPercentage && percentages()[index] !== 100" >
30
+ {{ percentages()[index] }}%
31
+ </div >
29
32
<div class =" label__segment-percentages" v-if =" is2d()" >
30
33
<ul class =" segment-percentage__list" >
31
34
<li v-for =" (subLabel, j) in subLabels" :key =" j" >
40
43
</template >
41
44
42
45
<script >
46
+ import { interpolate } from ' polymorph-js' ;
47
+ import TWEEN from ' @tweenjs/tween.js' ;
43
48
import FunnelGraph from ' funnel-graph-js' ;
44
49
import { formatNumber } from ' funnel-graph-js/src/js/number' ;
45
50
import { getDefaultColors } from ' funnel-graph-js/src/js/graph' ;
@@ -48,6 +53,10 @@ import 'funnel-graph-js/src/scss/main.scss';
48
53
export default {
49
54
name: ' FunnelGraph' ,
50
55
props: {
56
+ animated: {
57
+ type: Boolean ,
58
+ default: false
59
+ },
51
60
width: [String , Number ],
52
61
height: [String , Number ],
53
62
values: Array ,
@@ -64,13 +73,19 @@ export default {
64
73
gradientDirection: {
65
74
type: String ,
66
75
default: ' horizontal'
76
+ },
77
+ displayPercentage: {
78
+ type: Boolean ,
79
+ default: true
67
80
}
68
81
},
69
82
data () {
70
83
return {
71
84
paths: [],
85
+ prevPaths: [], // paths before update, used for animations
72
86
graph: null ,
73
- valueSize: 0
87
+ animationRunning: false ,
88
+ defaultColors: getDefaultColors (10 )
74
89
};
75
90
},
76
91
computed: {
@@ -84,8 +99,8 @@ export default {
84
99
const colorSet = [];
85
100
let gradientCount = 0 ;
86
101
87
- for (let i = 0 ; i < this .valueSize ; i++ ) {
88
- const values = ( this .graph .is2d () ) ? this .getColors [i] : this .getColors ;
102
+ for (let i = 0 ; i < this .paths . length ; i++ ) {
103
+ const values = this .graph .is2d () ? this .getColors [i] : this .getColors ;
89
104
const fillMode = (typeof values === ' string' || values .length === 1 ) ? ' solid' : ' gradient' ;
90
105
if (fillMode === ' gradient' ) gradientCount += 1 ;
91
106
colorSet .push ({
@@ -109,6 +124,11 @@ export default {
109
124
if (this .colors instanceof Array && this .colors .length === 0 ) {
110
125
return getDefaultColors (this .is2d () ? this .values [0 ].length : 2 );
111
126
}
127
+ if (this .colors .length < this .paths .length ) {
128
+ return [... this .colors ].concat (
129
+ [... this .defaultColors ].splice (this .paths .length , this .paths .length - this .colors .length )
130
+ );
131
+ }
112
132
return this .colors ;
113
133
},
114
134
gradientAngle () {
@@ -119,6 +139,9 @@ export default {
119
139
is2d () {
120
140
return this .graph .is2d ();
121
141
},
142
+ percentages () {
143
+ return this .graph .createPercentages ();
144
+ },
122
145
twoDimPercentages () {
123
146
if (! this .is2d ()) {
124
147
return [];
@@ -128,10 +151,66 @@ export default {
128
151
offsetColor (index , length ) {
129
152
return ` ${ Math .round (100 * index / (length - 1 ))} %` ;
130
153
},
154
+ makeAnimations () {
155
+ const interpolators = [];
156
+ const dimensionChanged = this .prevPaths .length !== this .paths .length ;
157
+
158
+ let origin = { x: 0.5 , y: 0.5 };
159
+ if (dimensionChanged) {
160
+ origin = { x: 0 , y: 0.5 };
161
+ if (this .graph .isVertical ()) {
162
+ origin = { x: 1 , y: 1 };
163
+ }
164
+ if (! this .graph .is2d ()) {
165
+ origin = { x: 0 , y: 1 };
166
+ }
167
+ }
168
+
169
+ this .paths .forEach ((path , index ) => {
170
+ let oldPath = this .prevPaths [index] || this .graph .getPathMedian (index);
171
+ if (dimensionChanged) oldPath = this .graph .getPathMedian (index);
172
+ const interpolator = interpolate ([oldPath, path], {
173
+ addPoints: 1 ,
174
+ origin,
175
+ optimize: ' fill' ,
176
+ precision: 1
177
+ });
178
+
179
+ interpolators .push (interpolator);
180
+ });
181
+
182
+ function animate () {
183
+ if (TWEEN .update ()) {
184
+ requestAnimationFrame (animate);
185
+ }
186
+ }
187
+
188
+ const position = { value: 0 };
189
+ const tween = new TWEEN.Tween (position)
190
+ .to ({ value: 1 }, 700 )
191
+ .easing (TWEEN .Easing .Cubic .InOut )
192
+ .onStart (() => {
193
+ this .animationRunning = true ;
194
+ })
195
+ .onUpdate (() => {
196
+ for (let index = 0 ; index < this .paths .length ; index++ ) {
197
+ this .paths [index] = interpolators[index](position .value );
198
+ // eslint-disable-next-line no-underscore-dangle
199
+ this .paths .__ob__ .dep .notify ();
200
+ }
201
+ })
202
+ .onComplete (() => {
203
+ this .animationRunning = false ;
204
+ });
205
+
206
+ if (this .animationRunning === false ) tween .start ();
207
+
208
+ animate ();
209
+ },
131
210
drawPaths () {
211
+ this .prevPaths = this .paths ;
132
212
this .paths = [];
133
213
const definitions = this .graph .getPathDefinitions ();
134
- this .valueSize = definitions .length ;
135
214
136
215
definitions .forEach ((d ) => {
137
216
this .paths .push (d);
@@ -148,11 +227,13 @@ export default {
148
227
}
149
228
});
150
229
this .drawPaths ();
230
+ if (this .animated ) this .makeAnimations ();
151
231
},
152
232
watch: {
153
233
values () {
154
234
this .graph .setValues (this .values );
155
235
this .drawPaths ();
236
+ if (this .animated ) this .makeAnimations ();
156
237
},
157
238
direction () {
158
239
this .graph .setDirection (this .direction )
0 commit comments