index.js 5.0 KB

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