OpenHarmony-JS封装Canvas组件饼图
时间:2023-03-12 00:36:37
科技观察
更多内容请访问:与华为官方共建的鸿蒙技术社区https://ost.51cto.com前言鸿蒙已提供一个图表组件来满足数据可视化的需求,那么我们如何自定义一个图表组件来实现数据可视化呢?本文将使用canvas自定义一个简单的饼图组件。饼图
首先我们需要创建一个画布,然后我们所有的操作都会在画布上进行。饼图主要由两部分组成,矩形数组表示数据,饼图进行操作。饼图是通过点击下面的绘图按钮同时生成的。使用的数据很简单。ary:[{title:'前端',num:11},{title:'后端',num:8},{title:'全栈',num:5},{title:'老板',num:1},]计算总数,转换弧度drawAngle(){this.ary.map((item,index)=>{this.total+=item.num;});lettotal=this.totalthis.ary.map(function(item,index){letangle=(item.num/total)*Math.PI*2;//计算饼图中每块item对应的弧度.angle=角度;});返回这个。ary},计算得到数据的总数,然后计算出对应的弧度,为在饼图上展示做铺垫。颜色填充randomColor(){//Math.floor(x)返回小于或等于x的最大整数//Math.random()返回一个介于0(含)和256(不含)之间的随机数letr=Math.地板(数学。随机()*256);让g=Math.floor(Math.random()*256);让b=Math.floor(Math.random()*256);return"rgb("+r+","+g+","+b+")";},饼图需要填充颜色,否则就是白板,我这里用随机颜色,刷新即可代码,点击绘图按钮,重新生成的饼图颜色会有所不同。如果您有更好的想法,欢迎交流。生成饼图draw(){if(this.flag==false){this.flag=true;this.el=this.$refs.canvas1;this.ctx=this.el.getContext('2d');//获取图片发布中心this.xCenter=JSON.parse(JSON.stringify(this.el.style.width).replace('px',''))/2;this.yCenter=JSON.parse(JSON.stringify(this.el.style.height).replace('px',''))/2;让angleList=this.drawAngle();让开始=0;//开始倾斜angleList.map((item,index)=>{letend=item.angle+start;//停止倾斜this.end.push(end);this.ctx.beginPath();this.ctx.moveTo(this.xCenter,this.yCenter);this.ctx.arc(this.xCenter,this.yCenter,ARC_RADIUS,start,end);this.ctx.fillStyle=this.randomColor();//填充颜色this.color.push(this.ctx.fillStyle);this.ctx.fill();start=end;//画小石头形状this.drawInfo(index,item.title,this.ctx.fillSt耶);})}else{return}}在绘制饼图之前,首先要确定的是饼图的中心位置。px(像素),在计算之前,需要先对其进行处理,这里我用一个空格代替px,处理完数据后,除以2得到圆心的坐标。遍历之前计算的弧列表,并为每个定义一个起始弧和结束弧。我在最后写了一行start=end来确定每个扇区的起始弧和结束弧。选择填充颜色并画一个圆圈。画一个矩形数组drawInfo(index,text,color){this.ctx.beginPath();//画一个小矩形this.ctx.fillRect(SPACEX,SPACEY*index+SMALL_H,SMALL_W,SMALL_H);this.ctx.font="12px微软雅黑";this.ctx.fillStyle=颜色;this.ctx.textAlign="左";this.ctx.fillText(text,SPACEX*2+SMALL_W,SPACEY*index+SMALL_H*2);},上图是用到的一些常数值。在画圆的方法中调用了矩形数组,所以当画圆按钮被点击时,它会同时出现。选择扇形图select(e){letglobalX=e.touches[0].globalX;//鼠标点击X坐标letglobalY=e.touches[0].globalY;//鼠标点击Y坐标this.mouseRadio=Math.sqrt(Math.pow(globalX-this.xCenter,2)+Math.pow(globalY-this.yCenter,2));//鼠标点击位置的向量坐标letvecX=globalX-this.xCenter;让vecY=globalY-this.yCenter;如果(this.flagTwo==false){this.flagTwo=true;this.end.splice(0,0,0);//在数组的第一个位置添加一个0}//通过向量的点积来计算cosletcos=(vecX*ARC_RADIUS+0*vecY)/(Math.sqrt(vecX*vecX+vecY*vecY)*圆弧半径);让cliAngel=0;//当前点击点的弧度值//以圆心为坐标轴,通过判断y的正负值得到当前点击的弧度值if(globalY>this.yCenter){cliAngel=Math.acos(cos);}else{cliAngel=Math.PI*2-Math.acos(cos);}letangelI=this.countRange(this.end,cliAngel)//当前点击点的弧度值对应数组中的下标console.log("angel:"+angelI);//判断点击是否在半边为ARC_RADIUS的圆内if(this.mouseRadio