Maison  >  Article  >  Applet WeChat  >  Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans l'applet WeChat (avec code)

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans l'applet WeChat (avec code)

青灯夜游
青灯夜游avant
2022-02-11 19:59:168058parcourir

Comment dessiner un graphique linéaire météo dans l'applet WeChat ? L'article suivant vous expliquera comment utiliser Canvas pour dessiner un graphique linéaire météo dans l'applet WeChat et utiliser une courbe de Bézier de troisième ordre pour ajuster les points de température afin de les rendre lisses et d'avoir une couleur d'arrière-plan au bas de la courbe. . J'espère utile pour tout le monde !

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans l'applet WeChat (avec code)

Polyline

Rendu :

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

Graphique linéaire des composants personnalisés

<canvas type="2d" id="line" class="line-class" style="width:{{width}}px;height:{{height}}px" />
Component({
  externalClasses: [&#39;line-class&#39;],
  properties: {
    width: String,
    height: String,
    data: Array,
  },
  observers: {
    width() {
      // 这里监听 width 变化重绘 canvas
      // 动态传入 width 好像只能这样了..
      const query = this.createSelectorQuery();
      query
        .select(&#39;#line&#39;)
        .fields({ node: true, size: true })
        .exec(res => {
          const canvas = res[0].node;
          const ctx = canvas.getContext(&#39;2d&#39;);
          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 = &#39;center&#39;;
      ctx.font = &#39;13px Microsoft YaHei&#39;;
      ctx.lineWidth = 2;
      ctx.strokeStyle = &#39;#ABDCFF&#39;;

      // 画折线图的线
      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, &#39;rgba(255,255,255,0.9)&#39;);
      lingrad.addColorStop(1, &#39;rgba(171,220,255,0)&#39;);
      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 = &#39;#0396FF&#39;;
      ctx.fill();
    },
  },
});

les données sont le tableau de température, tel que [1, 2, ...]

parce que non Nous savons combien il y a de valeurs de température, donc la largeur ici est transmise dynamiquement

Il y a un petit problème, c'est-à-dire que si la largeur est trop grande, la vraie machine ne l'affichera pas...

 // 获取 scroll-view 的总宽度
 wx.createSelectorQuery()
      .select(&#39;.hourly&#39;)
      .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>

Écrivez scroll-x et scroll-y ici, sinon il y a un problème de décalage de positionnement absolu, et je ne sais pas pourquoi

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

.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;
}

Le positionnement absolu utilisé ici est en fait pour simuler l'effet d'un graphique linéaire comme Moji La météo et chaque jour dans un bloc, donc toutes les heures doivent être combinées avec une vue par défilement, etc. En hauteur, la toile doit être positionnée

Principalement parce que je ne sais pas comment obtenir Moji Weather, donc je ne peux le faire que temporairement

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

Courbe de Bézier du troisième ordre

Rendu

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

emmm, on dirait que ce n'est pas pareil Pas très lisse

Calculer les points de contrôle

Écrivez d'abord une classe de points

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

Outil de dessin de courbe de Bézier sur toile (karlew.com)

http://wx.karlew.com/canvas/bezier/

Grâce au site Web ci-dessus, vous pouvez connaître la signification de chaque paramètre du troisième ordre Courbe de Bézier

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

C'est-à-dire que lors de l'utilisation de bezierCurveTo, le dernier point est le point suivant et les deux premiers sont des points de contrôle

Calcul des points de contrôle Référence : Méthode de détermination des points de contrôle de la courbe de Bézier - Bibliothèque Baidu

https://wenku.baidu.com/view/c790f8d46bec0975f565e211.html

Condensé, il est

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

où a et b peuvent être arbitraires Nombre positif

Définissez donc une méthode pour calculer les points de contrôle A et B de un certain point

/**
 * 计算当前点的贝塞尔曲线控制点
 * @param {Point} previousPoint: 前一个点
 * @param {Point} currentPoint: 当前点
 * @param {Point} nextPoint1: 下一个点
 * @param {Point} nextPoint2: 下下个点
 * @param {Number} scale: 系数
 */
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 };
}

où l'échelle est a et b, mais rendez leurs valeurs égales

mais le premier point n'a pas de point précédent, et l'avant-dernier point Il n'y a pas de point suivant2

Donc, lorsque le point est le premier, utilisez currentPoint au lieu de previousPoint

Lorsqu'il s'agit de l'avant-dernier point, utilisez nextPoint1 au lieu de nextPoint2

Vous apprendre étape par étape à utiliser Canvas pour dessiner un graphique linéaire météo dans lapplet WeChat (avec code)

Quant au dernier point, vous n'avez rien à faire, car le troisième paramètre de bezierCurveTo est le point suivant. Il vous suffit de fournir des coordonnées pour vous connecter. Il n'est pas nécessaire de calculer des points de contrôle. Ainsi, la méthode pour tracer une courbe de Bézier du troisième ordre :

/**
 * 绘制贝塞尔曲线
 * 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) => {
    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();
},

[Recommandations d'apprentissage associées :

Tutoriel de développement de mini-programmes

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer