微信小程序canvasToTempFilePath:fail fail canvas is empty
如默
撰写于 2024年 09月 10 日

说明

如题,最近在写一个小程序时,canvas报错,canvasToTempFilePath:fail fail canvas is empty,记录一下如何修复

步骤

首先吐槽一句,微信小程序官方文档真的不好,很多东西太旧也不修改,写的很乱,这个问题就是由于使用了错误的传参导致的。

这个报错是canvas为空,可能有几个原因

  1. canvas没有被正确的初始化,没有设置宽度高度;
  2. canvas画布内容没有被绘制
  3. canvasToTempFilePath方法没有正确的调用

本文遇到的问题就是第三个原因,话不多说,附上代码:

  onReady() {
    const query = wx.createSelectorQuery();
    query
      .select("#signCanvas")
      .fields({ node: true, size: true, id: true })
      .exec((res) => {
        const canvas = res[0].node;
        if (!canvas) {
          console.error("Canvas not found");
          return;
        }

        this.canvasId = res[0].id; // 保存 canvasId
        this.ctx = canvas.getContext("2d");
        if (!this.ctx) {
          console.error("Failed to get canvas context");
          return;
        }

        const dpr = wx.getSystemInfoSync().pixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;
        this.ctx.scale(dpr, dpr);

        console.log("Canvas initialized:", canvas);
        console.log("Canvas size:", canvas.width, canvas.height);
        console.log("Canvas ID:", this.canvasId);
        console.log("Canvas initialized, size:", canvas.width, "x", canvas.height);
      });
  },

  startDrawing(e) {
    const { x, y } = e.touches[0];
    this.setData({
      lastPoint: { x, y },
      isDrawing: true,
      hasDrawn: true, // 更新变量
    });
  },

  stopDrawing() {
    this.setData({
      isDrawing: false,
    });
  },

  moveDrawing(e) {
    if (!this.data.isDrawing) return;
    if (!this.ctx) {
      console.error("Canvas context is not initialized");
      return;
    }

    const { x, y } = e.touches[0];
    this.ctx.strokeStyle = this.data.color;
    this.ctx.lineWidth = this.data.thickness;
    this.ctx.lineJoin = "round";
    this.ctx.lineCap = "round";

    this.ctx.beginPath();
    this.ctx.moveTo(this.data.lastPoint.x, this.data.lastPoint.y);
    this.ctx.lineTo(x, y);
    this.ctx.stroke();

    this.setData({
      lastPoint: { x, y },
      hasDrawn: true,
    });
    console.log("Drawing at:", x, y, "with color", this.data.color, "and thickness", this.data.thickness);
  },

  clearCanvas() {
    const query = wx.createSelectorQuery();
    query
      .select("#signCanvas")
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node;
        if (!canvas) {
          console.error("Canvas not found");
          return;
        }

        const ctx = canvas.getContext("2d");
        if (!ctx) {
          console.error("Failed to get canvas context");
          return;
        }

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        this.setData({
          hasDrawn: false, // 清空画布后更新变量
        });

        console.log("Canvas cleared");
      });
  },

  saveSignature() {
    console.log("Attempting to save signature. Canvas ID:", this.canvasId, "Has Drawn:", this.data.hasDrawn);
    if (!this.data.hasDrawn) {
      wx.showToast({
        title: "画布为空",
        icon: "none",
        duration: 2000,
      });
      return;
    }

    const query = wx.createSelectorQuery();
    query.select("#" + this.canvasId)
        .fields({ node: true, size: true })
        .exec((res) => {
            const canvas = res[0].node;
            if (!canvas) {
              console.error("Canvas not found");
              return;
            }

            console.log("Saving canvas with ID:", this.canvasId);

            wx.canvasToTempFilePath({
              canvas: canvas,
              success: (res) => {
                wx.showToast({
                  title: "保存成功",
                  icon: "success",
                  duration: 2000,
                });
                console.log("File saved at:", res.tempFilePath);
              },
              fail: (err) => {
                wx.showToast({
                  title: "保存失败",
                  icon: "none",
                  duration: 2000,
                });
                console.error("Save failed:", err);
              },
            });
        });
},

这是全部代码,其中,wx.canvasToTempFilePath方法新版canvas 2d传参是一个对象,不是字符串,也不是canvasId,官方文档介绍如下图:

canvasToTempFilePath

canvasToTempFilePath

作为对比,我原来的代码如下:

saveSignature() {
    if (!this.data.hasDrawn) {
      wx.showToast({
        title: "画布为空",
        icon: "none",
        duration: 2000,
      });
      return;
    }

    console.log("Saving canvas with ID:", this.canvasId);

    wx.canvasToTempFilePath({
      canvasId: this.canvasId,
      success: (res) => {
        wx.showToast({
          title: "保存成功",
          icon: "success",
          duration: 2000,
        });
        console.log("File saved at:", res.tempFilePath);
        console.log("canvasId", this.canvasId);
      },
      fail: (err) => {
        wx.showToast({
          title: "保存失败",
          icon: "none",
          duration: 2000,
        });
        console.error("Save failed:", err);
      },
    });
  },

原来传参是这样的canvasId: this.canvasId,,其实不需要这个参数,需要的是canvas: canvas,

现在就可以正确保存了

总结

代码里面已经包含了全部的调试语句,根据控制台输出可以判断错误点,请自行判断。

微信小程序canvasToTempFilePath:fail fail canvas is empty

说明

如题,最近在写一个小程序时,canvas报错,canvasToTempFilePath:fail fail canvas is empty,记录一下如何修复

步骤

首先吐槽一句,微信小程序官方文档真的不好,很多东西太旧也不修改,写的很乱,这个问题就是由于使用了错误的传参导致的。

这个报错是canvas为空,可能有几个原因

  1. canvas没有被正确的初始化,没有设置宽度高度;
  2. canvas画布内容没有被绘制
  3. canvasToTempFilePath方法没有正确的调用

本文遇到的问题就是第三个原因,话不多说,附上代码:

  onReady() {
    const query = wx.createSelectorQuery();
    query
      .select("#signCanvas")
      .fields({ node: true, size: true, id: true })
      .exec((res) => {
        const canvas = res[0].node;
        if (!canvas) {
          console.error("Canvas not found");
          return;
        }

        this.canvasId = res[0].id; // 保存 canvasId
        this.ctx = canvas.getContext("2d");
        if (!this.ctx) {
          console.error("Failed to get canvas context");
          return;
        }

        const dpr = wx.getSystemInfoSync().pixelRatio;
        canvas.width = res[0].width * dpr;
        canvas.height = res[0].height * dpr;
        this.ctx.scale(dpr, dpr);

        console.log("Canvas initialized:", canvas);
        console.log("Canvas size:", canvas.width, canvas.height);
        console.log("Canvas ID:", this.canvasId);
        console.log("Canvas initialized, size:", canvas.width, "x", canvas.height);
      });
  },

  startDrawing(e) {
    const { x, y } = e.touches[0];
    this.setData({
      lastPoint: { x, y },
      isDrawing: true,
      hasDrawn: true, // 更新变量
    });
  },

  stopDrawing() {
    this.setData({
      isDrawing: false,
    });
  },

  moveDrawing(e) {
    if (!this.data.isDrawing) return;
    if (!this.ctx) {
      console.error("Canvas context is not initialized");
      return;
    }

    const { x, y } = e.touches[0];
    this.ctx.strokeStyle = this.data.color;
    this.ctx.lineWidth = this.data.thickness;
    this.ctx.lineJoin = "round";
    this.ctx.lineCap = "round";

    this.ctx.beginPath();
    this.ctx.moveTo(this.data.lastPoint.x, this.data.lastPoint.y);
    this.ctx.lineTo(x, y);
    this.ctx.stroke();

    this.setData({
      lastPoint: { x, y },
      hasDrawn: true,
    });
    console.log("Drawing at:", x, y, "with color", this.data.color, "and thickness", this.data.thickness);
  },

  clearCanvas() {
    const query = wx.createSelectorQuery();
    query
      .select("#signCanvas")
      .fields({ node: true, size: true })
      .exec((res) => {
        const canvas = res[0].node;
        if (!canvas) {
          console.error("Canvas not found");
          return;
        }

        const ctx = canvas.getContext("2d");
        if (!ctx) {
          console.error("Failed to get canvas context");
          return;
        }

        ctx.clearRect(0, 0, canvas.width, canvas.height);
        this.setData({
          hasDrawn: false, // 清空画布后更新变量
        });

        console.log("Canvas cleared");
      });
  },

  saveSignature() {
    console.log("Attempting to save signature. Canvas ID:", this.canvasId, "Has Drawn:", this.data.hasDrawn);
    if (!this.data.hasDrawn) {
      wx.showToast({
        title: "画布为空",
        icon: "none",
        duration: 2000,
      });
      return;
    }

    const query = wx.createSelectorQuery();
    query.select("#" + this.canvasId)
        .fields({ node: true, size: true })
        .exec((res) => {
            const canvas = res[0].node;
            if (!canvas) {
              console.error("Canvas not found");
              return;
            }

            console.log("Saving canvas with ID:", this.canvasId);

            wx.canvasToTempFilePath({
              canvas: canvas,
              success: (res) => {
                wx.showToast({
                  title: "保存成功",
                  icon: "success",
                  duration: 2000,
                });
                console.log("File saved at:", res.tempFilePath);
              },
              fail: (err) => {
                wx.showToast({
                  title: "保存失败",
                  icon: "none",
                  duration: 2000,
                });
                console.error("Save failed:", err);
              },
            });
        });
},

这是全部代码,其中,wx.canvasToTempFilePath方法新版canvas 2d传参是一个对象,不是字符串,也不是canvasId,官方文档介绍如下图:

canvasToTempFilePath

canvasToTempFilePath

作为对比,我原来的代码如下:

saveSignature() {
    if (!this.data.hasDrawn) {
      wx.showToast({
        title: "画布为空",
        icon: "none",
        duration: 2000,
      });
      return;
    }

    console.log("Saving canvas with ID:", this.canvasId);

    wx.canvasToTempFilePath({
      canvasId: this.canvasId,
      success: (res) => {
        wx.showToast({
          title: "保存成功",
          icon: "success",
          duration: 2000,
        });
        console.log("File saved at:", res.tempFilePath);
        console.log("canvasId", this.canvasId);
      },
      fail: (err) => {
        wx.showToast({
          title: "保存失败",
          icon: "none",
          duration: 2000,
        });
        console.error("Save failed:", err);
      },
    });
  },

原来传参是这样的canvasId: this.canvasId,,其实不需要这个参数,需要的是canvas: canvas,

现在就可以正确保存了

总结

代码里面已经包含了全部的调试语句,根据控制台输出可以判断错误点,请自行判断。


赞 (0)

猜您想看

  • nvm一个多版本nodejs管理工具

    平时用的nodejs是16版本,项目上用的是14,偶尔还会需要使用最新的18,所以本文记录一下nvm工具使用。

    2022年11月21日
  • Mac OS M2芯片第三方显示器无法调整声音

    Mac mini搭配华为MateView 28寸显示器,系统自带的OSD菜单无法调节音量和亮度,记录一下

    2023年10月19日
  • 科普:如何才能享受200M光纤的网速?

    平时家里的宽带都是几百兆,但是为什么网速不够呢,现在就来一探究竟

    2019年01月28日
  • VScode运行C程序无法输入值

    如题,由于VScode输出是只读状态,所以当程序里有`scanf`这类函数时,程序就无法继续运行,只能重启VScode或者在任务管理器里关闭程序。

    2020年03月04日
  • 迁移Git项目

    之前使用的是GitHub和Gitee,国外的访问速度太慢,国内的又各种限制,所以自己搭建了一个Gitea,用来存放代码,之前的仓库不想丢失log记录等信息,所以需要迁移,特此记录。

    2022年11月29日
  • AOC U28G2U显示器PIP和PBP使用体验

    前两天新换了一个显示器,正好有PIP和PBP功能,试验一下。

    2022年10月16日

评论区(暂无评论)

这里空空如也,快来评论吧~

我要评论

Vaptcha 初始化中...