Sanakey
2020-08-13 d98d05000c3d14e1f12a7754ebeea11ec1fa0f0b
提交 | 用户 | age
d98d05 1 import { VantComponent } from '../common/component';
S 2 import { isObj } from '../common/utils';
3 import { BLUE, WHITE } from '../common/color';
4 function format(rate) {
5   return Math.min(Math.max(rate, 0), 100);
6 }
7 const PERIMETER = 2 * Math.PI;
8 const BEGIN_ANGLE = -Math.PI / 2;
9 const STEP = 1;
10 VantComponent({
11   props: {
12     text: String,
13     lineCap: {
14       type: String,
15       value: 'round',
16     },
17     value: {
18       type: Number,
19       value: 0,
20       observer: 'reRender',
21     },
22     speed: {
23       type: Number,
24       value: 50,
25     },
26     size: {
27       type: Number,
28       value: 100,
29     },
30     fill: String,
31     layerColor: {
32       type: String,
33       value: WHITE,
34     },
35     color: {
36       type: [String, Object],
37       value: BLUE,
38       observer: 'setHoverColor',
39     },
40     type: {
41       type: String,
42       value: '',
43     },
44     strokeWidth: {
45       type: Number,
46       value: 4,
47     },
48     clockwise: {
49       type: Boolean,
50       value: true,
51     },
52   },
53   data: {
54     hoverColor: BLUE,
55   },
56   methods: {
57     getContext() {
58       if (!this.ctx) {
59         this.ctx = wx.createCanvasContext('van-circle', this);
60       }
61       return this.ctx;
62     },
63     setHoverColor() {
64       const { color, size, type } = this.data;
65       const context = type ? this.getContext(type) : this.getContext();
66       let hoverColor = color;
67       if (isObj(color)) {
68         const LinearColor = context.createLinearGradient(size, 0, 0, 0);
69         Object.keys(color)
70           .sort((a, b) => parseFloat(a) - parseFloat(b))
71           .map((key) =>
72             LinearColor.addColorStop(parseFloat(key) / 100, color[key])
73           );
74         hoverColor = LinearColor;
75       }
76       this.setData({ hoverColor });
77     },
78     presetCanvas(context, strokeStyle, beginAngle, endAngle, fill) {
79       const { strokeWidth, lineCap, clockwise, size } = this.data;
80       const position = size / 2;
81       const radius = position - strokeWidth / 2;
82       context.setStrokeStyle(strokeStyle);
83       context.setLineWidth(strokeWidth);
84       context.setLineCap(lineCap);
85       context.beginPath();
86       context.arc(position, position, radius, beginAngle, endAngle, !clockwise);
87       context.stroke();
88       if (fill) {
89         context.setFillStyle(fill);
90         context.fill();
91       }
92     },
93     renderLayerCircle(context) {
94       const { layerColor, fill } = this.data;
95       this.presetCanvas(context, layerColor, 0, PERIMETER, fill);
96     },
97     renderHoverCircle(context, formatValue) {
98       const { clockwise, hoverColor } = this.data;
99       // 结束角度
100       const progress = PERIMETER * (formatValue / 100);
101       const endAngle = clockwise
102         ? BEGIN_ANGLE + progress
103         : 3 * Math.PI - (BEGIN_ANGLE + progress);
104       this.presetCanvas(context, hoverColor, BEGIN_ANGLE, endAngle);
105     },
106     drawCircle(currentValue) {
107       const { size, type } = this.data;
108       const context = type ? this.getContext(type) : this.getContext();
109       context.clearRect(0, 0, size, size);
110       this.renderLayerCircle(context);
111       const formatValue = format(currentValue);
112       if (formatValue !== 0) {
113         this.renderHoverCircle(context, formatValue);
114       }
115       context.draw();
116     },
117     reRender() {
118       // tofector 动画暂时没有想到好的解决方案
119       const { value, speed } = this.data;
120       if (speed <= 0 || speed > 1000) {
121         this.drawCircle(value);
122         return;
123       }
124       this.clearInterval();
125       this.currentValue = this.currentValue || 0;
126       this.interval = setInterval(() => {
127         if (this.currentValue !== value) {
128           if (this.currentValue < value) {
129             this.currentValue += STEP;
130           } else {
131             this.currentValue -= STEP;
132           }
133           this.drawCircle(this.currentValue);
134         } else {
135           this.clearInterval();
136         }
137       }, 1000 / speed);
138     },
139     clearInterval() {
140       if (this.interval) {
141         clearInterval(this.interval);
142         this.interval = null;
143       }
144     },
145   },
146   created() {
147     const { value } = this.data;
148     this.currentValue = value;
149     this.drawCircle(value);
150   },
151   destroyed() {
152     this.ctx = null;
153     this.clearInterval();
154   },
155 });