小程序 canvas 生成海报

141 阅读2分钟
<canvas class="canvas" type="2d" id="cavansId" />
drawCanvas2D(detail) {
    const query = wx.createSelectorQuery();
    query
      .select('#cavansId')
      .fields({ node: true, size: true })
      .exec(async (res) => {
        // console.log(33, res);
        const canvas = res[0].node;
        this.canvas = canvas;
        let ctx = canvas.getContext('2d');

        // 设置整个画布dpr
        const height = 1000 * rpx;
        const dpr = wx.getSystemInfoSync().pixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;
        ctx.scale(dpr, dpr);
        // console.log(1111, canvas.width, canvas.height, dpr);

        // 设置整个画布背景色和宽高
        ctx.fillStyle = '#00c388';
        ctx.fillRect(0, 0, canvas.width, canvas.height);

        // 背景图
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q11.png', 50, 220, 643, 805);

        // 导航条
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q3.png', 122, 275, 506, 70);

        // 助力社区上升1 2 3名
        let url = `https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q${randomRange(8, 10)}.png`;
        await this.drawImageByLoad(canvas, ctx, url, 228, 365, 279, 35);

        // 房价
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q4.png', 130, 460, 105, 102);
        // 户数
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q5.png', 415, 460, 105, 102);
        // 停车位
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q7.png', 130, 600, 105, 102);
        // 绿化率
        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/q6.png', 415, 600, 105, 102);
        // code

        await this.drawImageByLoad(canvas, ctx, 'https://mp.airtu.me/wechatappImg/opendoor/werun/v2/code.jpg', 500, 860, 160, 160);

        ctx.save();

        // 标题:上海市排名
        ctx.fillStyle = '#fff';
        this.setFontSizeByFont(ctx, 35 * rpx);
        ctx.fillText('上海市排名', 80 * rpx, 70 * rpx);

        // 排名
        ctx.font = `normal ${96 * rpx}px dincondensedbold`;
        ctx.fillText(detail.score_rank, 80 * rpx, 170 * rpx);
        const w1 = ctx.measureText(detail.score_rank);

        // 分数
        // this.setFontSizeByFont(ctx, 40 * rpx);
        ctx.font = `normal ${40 * rpx}px dincondensedbold`;
        const a = detail.score.toFixed(0);
        ctx.fillText(`(${a}分)`, (80 + 10) * rpx + w1.width, 170 * rpx); // 10 为 间隙宽度

        // 导航条的文字
        this.setFontSizeByFont(ctx, 32 * rpx);
        const w2 = ctx.measureText(`我已为社区助力${this.step}步`);
        ctx.fillText(`我已为社区助力${this.step}步`, (750 * rpx - w2.width) / 2, 320 * rpx); // 10 为 间隙宽度

        // 标题:房价
        this.setFontSizeByFont(ctx, 24 * rpx);
        ctx.fillStyle = '#000000';
        ctx.fillText('房价(平/元)', 245 * rpx, 490 * rpx);

        ctx.font = `normal ${54 * rpx}px dincondensedbold`;
        ctx.fillStyle = '#184655';
        ctx.fillText(detail.price, 245 * rpx, 545 * rpx);

        // 标题:户数
        this.setFontSizeByFont(ctx, 24 * rpx);
        ctx.fillStyle = '#000000';
        ctx.fillText('户数(户)', 535 * rpx, 490 * rpx);

        ctx.font = `normal ${54 * rpx}px dincondensedbold`;
        ctx.fillStyle = '#184655';
        ctx.fillText(detail.houses, 535 * rpx, 545 * rpx);

        // 标题:停车位
        this.setFontSizeByFont(ctx, 24 * rpx);
        ctx.fillStyle = '#000000';
        ctx.fillText('停车位(个)', 245 * rpx, 620 * rpx);

        ctx.font = `normal ${54 * rpx}px dincondensedbold`;
        ctx.fillStyle = '#184655';
        ctx.fillText(detail.parkings, 245 * rpx, 675 * rpx);

        // 标题:绿化率
        this.setFontSizeByFont(ctx, 24 * rpx);
        ctx.fillStyle = '#000000';
        ctx.fillText('绿化率(%)', 535 * rpx, 620 * rpx);

        ctx.font = `normal ${54 * rpx}px dincondensedbold`;
        ctx.fillStyle = '#184655';
        ctx.fillText(detail.green, 535 * rpx, 675 * rpx);

        // ctx.restore();
      });

    // 背景色
    // ctx.fillStyle = '#00c388';
    // ctx.fillRect(0, 0, 750 * rpx, 1400 * rpx);

    // 绘制排名
    // this.drawGrade();

    // ctx.draw();
  }

  drawImageByLoad(canvas, ctx, url, x, y, w, h) {
    return new Promise((resolve, reject) => {
      // 背景图
      let img = canvas.createImage();
      img.src = url;
      img.onload = () => {
        ctx.drawImage(img, x * rpx, y * rpx, w * rpx, h * rpx); // url x y w h
        resolve();
      };
    });
  }

  setFontSizeByFont(ctx, fontszie) {
    ctx.font = `normal ${fontszie}px Arial, Verdana, Tahoma, Hiragino Sans GB, Microsoft YaHei, SimSun, sans-serif`;
  }

  loadFontFace() {
    return new Promise((resolve, reject) => {
      wx.loadFontFace({
        family: 'dincondensedbold',
        source: 'url("https://airtu.oss-cn-shanghai.aliyuncs.com/font/DINCondensedBold2.ttf")',
        scopes: ['webview', 'native'],
        success: (res) => {
          console.log(res);
          resolve();
        },
        fail: (err) => {
          console.info(err);
          resolve();
        },
      });
    });
  }

  // 获取系统信息
  getSystemInfo() {
    return new Promise((resolve, reject) => {
      wx.getSystemInfo({
        success: (f) => {
          // console.log(24, f);
          rpx = f.windowWidth / 750;
          resolve();
        },
        fail: (err) => {
          resolve();
        },
      });
    });
  }

  // 获取网络图片信息
  getImgInfo(src) {
    return new Promise((resolve, reject) => {
      wx.getImageInfo({
        src,
        success: (res) => {
          resolve(res.path);
        },
        fail: (err) => {
          resolve();
        },
      });
    });
  }

参考文档: 微信小程序canvas官方文档