海鲜小程序

index.js 4.7KB

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