thor-circular-progress.nvue 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. <template>
  2. <view class="tui-circular-container" :style="{ width: diam + 'px', height: (height || diam) + 'px' }">
  3. <gcanvas :ref="progressCanvasId" :style="{ width: diam + 'px', height: (height || diam) + 'px' }"></gcanvas>
  4. <slot></slot>
  5. </view>
  6. </template>
  7. <script>
  8. //nuve 专用
  9. import {
  10. enable,
  11. WeexBridge
  12. } from './gcanvas/index.js';
  13. export default {
  14. name: 'thorCircularProgress',
  15. props: {
  16. /*
  17. 传值需使用rpx进行转换保证各终端兼容
  18. px = rpx / 750 * uni.getSystemInfoSync().windowWidth
  19. 圆形进度条(画布)宽度,直径 [px]
  20. */
  21. diam: {
  22. type: Number,
  23. default: 60
  24. },
  25. //圆形进度条(画布)高度,默认取diam值[当画半弧时可传值,height有值时则取height]
  26. height: {
  27. type: Number,
  28. default: 60
  29. },
  30. //进度条线条宽度[px]
  31. lineWidth: {
  32. type: Number,
  33. default: 4
  34. },
  35. /*
  36. 线条的端点样式
  37. butt:向线条的每个末端添加平直的边缘
  38. round 向线条的每个末端添加圆形线帽
  39. square 向线条的每个末端添加正方形线帽
  40. */
  41. lineCap: {
  42. type: String,
  43. default: 'round'
  44. },
  45. //圆环进度字体大小 [px]
  46. fontSize: {
  47. type: Number,
  48. default: 26
  49. },
  50. //圆环进度字体颜色
  51. fontColor: {
  52. type: String,
  53. default: '#16b999'
  54. },
  55. //是否显示进度文字
  56. fontShow: {
  57. type: Boolean,
  58. default: true
  59. },
  60. /*
  61. 自定义显示文字[默认为空,显示百分比,fontShow=true时生效]
  62. 可以使用 slot自定义显示内容
  63. */
  64. percentText: {
  65. type: String,
  66. default: ''
  67. },
  68. //进度条颜色
  69. progressColor: {
  70. type: String,
  71. default: '#16b999'
  72. },
  73. //起始弧度,单位弧度
  74. sAngle: {
  75. type: Number,
  76. default: -Math.PI / 2
  77. },
  78. //指定弧度的方向是逆时针还是顺时针。默认是false,即顺时针
  79. counterclockwise: {
  80. type: Boolean,
  81. default: false
  82. },
  83. //进度百分比 [10% 传值 10]
  84. percentage: {
  85. type: Number,
  86. default: 0
  87. },
  88. //进度百分比缩放倍数[使用半弧为100%时,则可传2]
  89. multiple: {
  90. type: Number,
  91. default: 1
  92. },
  93. //动画执行时间[单位毫秒,低于50无动画]
  94. duration: {
  95. type: Number,
  96. default: 800
  97. },
  98. //backwards: 动画从头播;forwards:动画从上次结束点接着播
  99. activeMode: {
  100. type: String,
  101. default: 'backwards'
  102. }
  103. },
  104. computed: {
  105. canvasChange() {
  106. return `${this.diam},${this.height},${this.lineWidth}`;
  107. }
  108. },
  109. watch: {
  110. percentage(val) {
  111. this.initDraw();
  112. },
  113. canvasChange() {
  114. this.initDraw(true);
  115. }
  116. },
  117. data() {
  118. return {
  119. progressCanvasId: this.getCanvasId(),
  120. progressContext: null,
  121. canvasObj: null,
  122. //起始百分比
  123. startPercentage: 0,
  124. // dpi
  125. pixelRatio: uni.getSystemInfoSync().pixelRatio
  126. };
  127. },
  128. mounted() {
  129. this.initDraw(true);
  130. },
  131. methods: {
  132. //初始化绘制
  133. initDraw(init) {
  134. let start = this.activeMode === 'backwards' ? 0 : this.startPercentage;
  135. this.drawProgressCircular(start);
  136. },
  137. //进度圆环
  138. drawProgressCircular(startPercentage) {
  139. let ctx = this.progressContext;
  140. if (!ctx) {
  141. let ganvas = this.$refs[this.progressCanvasId];
  142. /*通过元素引用获取canvas对象*/
  143. this.canvasObj = enable(ganvas, {
  144. bridge: WeexBridge
  145. });
  146. /*获取绘图所需的上下文,目前不支持3d*/
  147. ctx = this.canvasObj.getContext('2d');
  148. this.progressContext = ctx;
  149. }
  150. ctx.setLineWidth(this.lineWidth);
  151. ctx.setStrokeStyle(this.progressColor);
  152. let time = this.duration / this.percentage;
  153. startPercentage = this.duration < 50 ? this.percentage - 1 : startPercentage;
  154. startPercentage++;
  155. if (startPercentage > this.percentage) {
  156. return false;
  157. }
  158. if (this.fontShow) {
  159. ctx.setFontSize(this.fontSize);
  160. ctx.setFillStyle(this.fontColor);
  161. ctx.setTextAlign('center');
  162. ctx.setTextBaseline('middle');
  163. let percentage = this.percentText;
  164. if (!percentage) {
  165. percentage = this.counterclockwise ? 100 - startPercentage * this.multiple : startPercentage * this
  166. .multiple;
  167. percentage = `${percentage}%`;
  168. }
  169. let radius = this.diam / 2;
  170. ctx.fillText(percentage, radius, radius);
  171. }
  172. let eAngle = ((2 * Math.PI) / 100) * startPercentage + this.sAngle;
  173. this.drawArc(ctx, eAngle);
  174. setTimeout(() => {
  175. this.startPercentage = startPercentage;
  176. this.drawProgressCircular(startPercentage);
  177. this.$emit('change', {
  178. percentage: startPercentage
  179. });
  180. }, time);
  181. },
  182. //创建弧线
  183. drawArc(ctx, eAngle) {
  184. ctx.setLineCap(this.lineCap);
  185. ctx.beginPath();
  186. let radius = this.diam / 2; //x=y
  187. ctx.arc(radius, radius, radius - this.lineWidth, this.sAngle, eAngle, this.counterclockwise);
  188. ctx.stroke();
  189. ctx.draw();
  190. },
  191. //生成canvasId
  192. getCanvasId() {
  193. let uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
  194. return (c === 'x' ? (Math.random() * 16) | 0 : 'r&0x3' | '0x8').toString(16);
  195. });
  196. return uuid;
  197. }
  198. }
  199. };
  200. </script>
  201. <style scoped>
  202. .tui-circular-container {
  203. position: relative;
  204. }
  205. </style>