# HarmonyOS 基于JSAPI自定义封装渐变圆环进度条组件 **Repository Path**: yango520/compontentCircle ## Basic Information - **Project Name**: HarmonyOS 基于JSAPI自定义封装渐变圆环进度条组件 - **Description**: HarmonyOS 基于JSAPI自定义封装渐变圆环进度条组件 - **Primary Language**: JavaScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2022-01-26 - **Last Updated**: 2022-09-07 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HarmonyOS 基于JSAPI自定义封装渐变圆环进度条组件 ## 前言 圆环进度条组件在开发过程中是经常会用到的组件,比如在loading加载、升级过程,下载过程等等都需要用到。本文是基于HarmonyOS JSPAI开发,使用canvas画布封装的组件。方便直接引入上手使用。 ## 效果展示 ![gif展示](./files/gif1.gif) ## 属性 | 属性名 | 类型 | 默认值 | 作用 | | ---- | ---- | ---- | ---- | | cWidth | Number | 200 | 外环宽度 | | cHeight | Number | 200 | 外环高度 | | staticScale | Number | 4 | 缩放级,值越大,越清晰,渲染压力越大 | | cRate | Number | 0 | 当前进度 | | lineWidth | Number | 20 | 圆环宽度 | | cColor | String | #86C1FF,#2B5BF9 | 进度颜色(必须是hex),当只有一个颜色值时为纯色进度,最多只支持两个颜色,使用半角逗号分开 | | bgColor | String | #e9ebed | 圆环背景颜色 | | text | String | - | 显示的文本 | | textSize | Number | - | 显示的文本字体大小 | 对应组件传入的prop参数 ```javascript props: { // 圆环宽度 cWidth: { type: Number, default: 200, }, // 圆环高度 cHeight: { type: Number, default: 200, }, // 缩放级,值越大,越清晰,渲染压力越大 staticScale:{ type: Number, default: 4, }, // 显示文本 text: { type: String, default: '', }, // 圆环宽度 lineWidth: { type: Number, default: 20 }, // 当前进度 cRate: { type: Number, default: 0 }, // 进度颜色,当只有一个颜色值时为纯色进度,最多只支持两个颜色,使用半角逗号分开 cColor: { type: String, default: '#86C1FF,#2B5BF9' }, // 背景色 bgColor:{ type: String, default: '#e9ebed' }, // 文字大小 textSize: { type: Number, default: 32 } }, ``` ## 调用组件 ``` javascript
``` ## 实现原理 我们知道,在canvas中可以实现线性渐变和径向渐变,但是这些渐变都不够美观并且无法实现根据圆环方向线性渐变。 本文通过将圆环弧切片成若干等分绘制指定的颜色来实现的。 **下面拆分各个步骤** - 创建canvas对象并且设置canvas大小 - 使用canvas的arc() API绘制一个圆充当圆环背景,给lineWidth设置圆环宽度的值 - 计算两个颜色之间的渐变颜色值。确定需要切片的精度,来确定渐变颜色值之间的差级。 - 在原来的背景圆环上,再绘制一个圆弧,圆弧是根据开始位置和结束位置,然后绘制一段圆弧之间的所有切片 ### 1. 初始化canvas 这里需要有个关键点,getContext(contextType, contextAttributes)方法可以传入两个参数 - contextType 上下文类型 可选 2d、webgl - contextAttributes 上下文属性 **注意**:在HarmonyOS 的JSPAI官网文档没有提到这两个属性,但是案例上有看到`const ctx = el.getContext('2d', { antialias: true });`这样一句话。这里似乎跟webAPI的有些区别。 antialias属性是设置是否开启抗锯齿,但是在webAPI中,只有在上下文类型为webgl的时候才有这个属性。 先写个canvas标签 ```html ``` 再初始化canvas对象 ```javascript initCanvas(){ let canvas = this.$refs.canvas; this.ctx = canvas.getContext('2d'); canvas.width = this.cWidth * this.staticScale; canvas.height = this.cHeight * this.staticScale; }, ``` ### 2. 绘制背景圆环 通过canvas的arc(x,y,r,sAngle,eAngle,counterclockwise)方法绘制一个圆 **参数值** | 参数 | 描述 | | :----------------- | :----------------------------------------------------------- | | *x* | 圆的中心的 x 坐标。 | | *y* | 圆的中心的 y 坐标。 | | *r* | 圆的半径。 | | *sAngle* | 起始角,以弧度计(弧的圆形的三点钟位置是 0 度)。 | | *eAngle* | 结束角,以弧度计。 | | *counterclockwise* | 可选。规定应该逆时针还是顺时针绘图。False = 顺时针,true = 逆时针。 | 在canvas绘制圆的其实位置是在x+r的位置开始,完整的圆弧为2*PI。因为我们要在最顶端开始绘制,所以我们的开始位置是1.5*PI,而我们的结束位置就不是2*PI了,而是1.5*PI + 2 * PI,这个才是绘制的完整的一个圆弧。最后 ![image-20220211100642088](./files/image-20220211100642088.png) ```javascript this.ctx.beginPath(); this.ctx.lineCap = "round"; //向线条的每个末端添加圆形线帽 this.ctx.lineWidth = 20; //绘制圆的边框 this.ctx.strokeStyle = '#ff9800'; //绘制边框的颜色 this.ctx.arc(100,100,100,Math.PI * 1.5,(Math.PI * 1.5 * Math.PI * 2)); this.ctx.stroke(); ``` 上面代码我们这里绘制了一个圆心坐标在(100,100),半径为100,边框为20,边框颜色为 #ff9800的圆环 ![image-20220211101933973](./files/image-20220211101933973.png) ### 3. 实现圆弧切片绘制方法 #### 1. 获取两颜色之间的渐变值组 - 首先我们需要把获取到的hex色值转换成rgb三原色值, - 然后通过计算开始颜色和结束颜色总差值来获取每一步的颜色值, - 最后再转换成hex设置 将hex色值转换成rgb三原色值方法 ```javascript // 将hex表示方式转换为rgb表示方式(这里返回rgb数组模式) hexToRgb(sColor){ var reg = /^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$/; sColor = sColor.toLowerCase(); if(sColor && reg.test(sColor)){ if(sColor.length === 4){ var sColorNew = "#"; for(var i=1; i<4; i+=1){ sColorNew += sColor.slice(i,i+1).concat(sColor.slice(i,i+1)); } sColor = sColorNew; } //处理六位的颜色值 var sColorChange = []; for(let i=1; i<7; i+=2){ sColorChange.push(parseInt("0x"+sColor.slice(i,i+2))); } return sColorChange; }else{ return sColor; } }, ``` 通过计算开始颜色和结束颜色总差值来获取每一步的颜色值 ```javascript /** * @description: 封装颜色渐变之间值 * @param {String} startColor 开始颜色hex * @param {Number} endColor 结束颜色hex * @param {Number} step 渐变精度 * @return {Array} */ gradientColor(startColor,endColor,step){ let startRGB = this.hexToRgb(startColor);//转换为rgb数组模式 let endRGB = this.hexToRgb(endColor); let sR = (endRGB[0]-startRGB[0])/step;//总差值 let sG = (endRGB[1]-startRGB[1])/step; let sB = (endRGB[2]-startRGB[2])/step; var colorArr = []; for(var i=0;i
{{text}}
``` ### css文件 ```css .circle-box{ position: relative; } .canvas{ width: 100%; height: 100%; } .text{ position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); z-index: 10; text-align: center; } ``` ## 总结 在开发过程中也遇到了一些坑,比如SDK版本问题:在SDK version7的时候渲染没有问题,但是IDE预览器经常崩溃掉。后来改回SDK6就好了。 以往在开发vue的时候,会直接把canvas对象赋值到data函数里,方便其他方法直接调用,但是在这里却发现不行。最后发现这里data并非是一个函数,而是一个对象,这里还没有深入研究。 后续在使用组件的时候未必一定需要使用text属性,可以使用slot插槽实现多样文本显示。