文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

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

2023-06-29 03:33

关注

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

折线

效果图:

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

自定义组件 line-chart

<canvas type="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 好像只能这样了..      const query = this.createSelectorQuery();      query        .select('#line')        .fields({ node: true, size: true })        .exec(res => {          const canvas = res[0].node;          const ctx = canvas.getContext('2d');          const width = res[0].width; // 画布宽度          const height = res[0].height; // 画布高度          console.log(`宽度: ${width}, 高度: ${height}`);          const dpr = 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) {      const Max = Math.max(...data);      const Min = Math.min(...data);      // 把 canvas 的宽度, 高度按一定规则平分      const startX = width / (data.length * 2), // 起始点的横坐标 X        baseY = height * 0.9, // 基线纵坐标 Y        diffX = width / data.length,        diffY = (height * 0.7) / (Max - Min); // 高度预留 0.2 写温度      ctx.beginPath();      ctx.textAlign = 'center';      ctx.font = '13px Microsoft YaHei';      ctx.lineWidth = 2;      ctx.strokeStyle = '#ABDCFF';      // 画折线图的线      data.forEach((item, index) => {        const x = 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); // 基线起点      const lingrad = 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) => {        const x = 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();
<view class="title">小时概述</view><scroll-view scroll-x scroll-y class="scroll" show-scrollbar="{{false}}" enhanced="{{true}}">    <view class="hourly">      <view wx:for="{{time}}" wx:key="index">{{item}}</view>    </view>    <line-chart line-class="line" width="{{scrollWidth}}" height="100" data="{{temp}}" /></scroll-view>

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

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

.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 需要定位一下

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

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

三阶贝塞尔曲线

效果图

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

emmm,好像并不怎么圆滑

计算控制点

首先写一个点类

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

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

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

浓缩一下就是

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

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

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

calcBezierControlPoints(  previousPoint,  currentPoint,  nextPoint1,  nextPoint2,  scale = 0.25) {  let x = currentPoint.x + scale * (nextPoint1.x - previousPoint.x);  let y = currentPoint.y + scale * (nextPoint1.y - previousPoint.y);  const controlPointA = new Point(x, y); // 控制点 A  x = nextPoint1.x - scale * (nextPoint2.x - currentPoint.x);  y = nextPoint1.y - scale * (nextPoint2.y - currentPoint.y);  const controlPointB = new Point(x, y); // 控制点 B  return { controlPointA, controlPointB };}

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

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

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

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

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

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

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

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) => {    let curPoint, prePoint, nextPoint1, nextPoint2, x, y;    // 当前点    x = startX + diffX * i;    y = baseY - (e - Min) * diffY;    curPoint = new Point(x, y);    // 前一个点    x = startX + diffX * (i - 1);    y = baseY - (data[i - 1] - Min) * diffY;    prePoint = new Point(x, y);    // 下一个点    x = startX + diffX * (i + 1);    y = baseY - (data[i + 1] - Min) * diffY;    nextPoint1 = new Point(x, y);    // 下下个点    x = startX + diffX * (i + 2);    y = baseY - (data[i + 2] - Min) * diffY;    nextPoint2 = new Point(x, y);    if (i === 0) {      // 如果是第一个点, 则前一个点用当前点代替      prePoint = curPoint;    } else if (i === data.length - 2) {      // 如果是倒数第二个点, 则下下个点用下一个点代替      nextPoint2 = nextPoint1;    } else if (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绘制天气折线图”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯