在微信小程序中如何使用canvas绘制天气折线图

免费教程   2024年05月01日 8:13  

今天小编给大家分享一下在微信小程序中如何使用canvas绘制天气折线图的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

折线

效果图:

自定义组件 line-chart

<canvastype="2d"id="line"class="line-class"style="width:{{width}}px;height:{{height}}px"/>Component({externalClasses:['line-class'],properties:{width:String,height:String,data:Array,},observers:{width(){//这里监听width变化重绘canvas//动态传入width好像只能这样了..constquery=this.createSelectorQuery();query.select('#line').fields({node:true,size:true}).exec(res=>{constcanvas=res[0].node;constctx=canvas.getContext('2d');constwidth=res[0].width;//画布宽度constheight=res[0].height;//画布高度console.log(`宽度:${width},高度:${height}`);constdpr=wx.getSystemInfoSync().pixelRatio;canvas.width=width*dpr;canvas.height=height*dpr;ctx.scale(dpr,dpr);//开始绘图this.drawLine(ctx,width,height,this.data.data);});},},methods:{drawLine(ctx,width,height,data){constMax=Math.max(...data);constMin=Math.min(...data);//把canvas的宽度,高度按一定规则平分conststartX=width/(data.length*2),//起始点的横坐标XbaseY=height*0.9,//基线纵坐标YdiffX=width/data.length,diffY=(height*0.7)/(Max-Min);//高度预留0.2写温度ctx.beginPath();ctx.textAlign='center';ctx.font='13pxMicrosoftYaHei';ctx.lineWidth=2;ctx.strokeStyle='#ABDCFF';//画折线图的线data.forEach((item,index)=>{constx=startX+diffX*index,y=baseY-(item-Min)*diffY;ctx.fillText(`${item}°`,x,y-10);ctx.lineTo(x,y);});ctx.stroke();//画折线图背景ctx.lineTo(startX+(data.length-1)*diffX,baseY);//基线终点ctx.lineTo(startX,baseY);//基线起点constlingrad=ctx.createLinearGradient(0,0,0,height*0.7);lingrad.addColorStop(0,'rgba(255,255,255,0.9)');lingrad.addColorStop(1,'rgba(171,220,255,0)');ctx.fillStyle=lingrad;ctx.fill();//画折线图上的小圆点ctx.beginPath();data.forEach((item,index)=>{constx=startX+diffX*index,y=baseY-(item-Min)*diffY;ctx.moveTo(x,y);ctx.arc(x,y,3,0,2*Math.PI);});ctx.fillStyle='#0396FF';ctx.fill();},},});

data 就是温度数组,如 [1, 2, ...]

因为不知道温度数值有多少个,因此这里的 width 动态传入

有个小问题,就是宽度过大的话真机不会显示...

//获取scroll-view的总宽度wx.createSelectorQuery().select('.hourly').boundingClientRect(rect=>{this.setData({scrollWidth:rect.right-rect.left,});}).exec();<viewclass="title">小时概述</view><scroll-viewscroll-xscroll-yclass="scroll"show-scrollbar="{{false}}"enhanced="{{true}}"><viewclass="hourly"><viewwx:for="{{time}}"wx:key="index">{{item}}</view></view><line-chartline-class="line"width="{{scrollWidth}}"height="100"data="{{temp}}"/></scroll-view>

这里写 scroll-x 和 scroll-y,要不会出现绝对定位偏移的问题,也不知道为什么

.scroll{position:relative;height:150px;width:100%;}.hourly{display:flex;height:150px;position:absolute;top:0;}.hourly>view{min-width:3.5em;text-align:center;}.line{//折线图绝对定位到底部position:absolute;bottom:0;}

这里使用绝对定位其实是想模拟墨迹天气这种折线图和每一天在一个块内的效果,所以 hourly 要和 scroll-view 等高,canvas 需要定位一下

主要是不知道墨迹天气怎么实现的,只能暂时这样

三阶贝塞尔曲线

效果图

emmm,好像并不怎么圆滑

计算控制点

首先写一个点类

classPoint{constructor(x,y){this.x=x;this.y=y;}}

也就是使用 bezierCurveTo 的时候最后一个点是下一个点,前两个是控制点

浓缩一下就是

这里的 a 和 b 可以是任意正数

因此定义一个计算某点的控制点 A 和 B 的方法

/***计算当前点的贝塞尔曲线控制点*@param{Point}previousPoint:前一个点*@param{Point}currentPoint:当前点*@param{Point}nextPoint1:下一个点*@param{Point}nextPoint2:下下个点*@param{Number}scale:系数*/calcBezierControlPoints(previousPoint,currentPoint,nextPoint1,nextPoint2,scale=0.25){letx=currentPoint.x+scale*(nextPoint1.x-previousPoint.x);lety=currentPoint.y+scale*(nextPoint1.y-previousPoint.y);constcontrolPointA=newPoint(x,y);//控制点Ax=nextPoint1.x-scale*(nextPoint2.x-currentPoint.x);y=nextPoint1.y-scale*(nextPoint2.y-currentPoint.y);constcontrolPointB=newPoint(x,y);//控制点Breturn{controlPointA,controlPointB};}

这里 scale 就是 a 和 b,不过将它们的取值相等

但是第一个点没有 previousPoint,倒数第二个点没有 nextPoint2

因此当点是第一个的时候,使用 currentPoint 代替 previousPoint

当倒数第二个点的时候,使用 nextPoint1 代替 nextPoint2

至于最后一个点,不需要做任何事,因为 bezierCurveTo 第三个参数就是下一个点,只需要提供坐标就能连起来,不需要计算控制点

因此绘制三阶贝塞尔曲线的方法:

/***绘制贝塞尔曲线*ctx.bezierCurveTo(控制点1,控制点2,当前点);*/drawBezierLine(ctx,data,options){const{startX,diffX,baseY,diffY,Min}=options;ctx.beginPath();//先移动到第一个点ctx.moveTo(startX,baseY-(data[0]-Min)*diffY);data.forEach((e,i)=>{letcurPoint,prePoint,nextPoint1,nextPoint2,x,y;//当前点x=startX+diffX*i;y=baseY-(e-Min)*diffY;curPoint=newPoint(x,y);//前一个点x=startX+diffX*(i-1);y=baseY-(data[i-1]-Min)*diffY;prePoint=newPoint(x,y);//下一个点x=startX+diffX*(i+1);y=baseY-(data[i+1]-Min)*diffY;nextPoint1=newPoint(x,y);//下下个点x=startX+diffX*(i+2);y=baseY-(data[i+2]-Min)*diffY;nextPoint2=newPoint(x,y);if(i===0){//如果是第一个点,则前一个点用当前点代替prePoint=curPoint;}elseif(i===data.length-2){//如果是倒数第二个点,则下下个点用下一个点代替nextPoint2=nextPoint1;}elseif(i===data.length-1){//最后一个点直接退出return;}const{controlPointA,controlPointB}=this.calcBezierControlPoints(prePoint,curPoint,nextPoint1,nextPoint2);ctx.bezierCurveTo(controlPointA.x,controlPointA.y,controlPointB.x,controlPointB.y,nextPoint1.x,nextPoint1.y);});ctx.stroke();},

以上就是“在微信小程序中如何使用canvas绘制天气折线图”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

域名注册
购买VPS主机

您或许对下面这些文章有兴趣:                    本月吐槽辛苦排行榜

看贴要回贴有N种理由!看帖不回贴的后果你懂得的!


评论内容 (*必填):
(Ctrl + Enter提交)   

部落快速搜索栏

各类专题梳理

网站导航栏

X
返回顶部