收藏
回答

Canvas 第二次draw回调失效,图片不显示

框架类型 问题类型 API/组件名称 终端类型 微信版本 基础库版本
小程序 Bug CanvasContext.draw 客户端 6.5.3 2.0.0

- 当前 Bug 的表现(可附上截图)


- 预期表现


- 复现路径


- 提供一个最简复现 Demo

ctx.draw(false, () => {

drawed.call(this);

});


ctx.draw(true, () => {

drawed.call(this);

});


回答关注问题邀请回答
收藏

4 个回答

  • Rimifon
    Rimifon
    2018-11-24

    第二次draw的时候如果延时1ms以上就会有回调,测试发现1ms的时候让然不一定有回调,代码片段:https://developers.weixin.qq.com/s/Mj5Jtamm7g4A

    2018-11-24
    有用
    回复
  • 格桑梅朵
    格桑梅朵
    2018-11-12

    const {

        windowWidth,

        pixelRatio,

    } = wx.getSystemInfoSync();


    const px = (n) => {

        if (typeof n === 'undefined') return void 0;

        if (!n) return 0;

        return parseInt(n, 10) / 750 * windowWidth;

    }

    const fillColor = (ctx, start, end, colorStop, shape) => {

        let grd = null;


        if (shape === 'Radial') {

            const [x, y, r] = start;

            grd = ctx.createCircularGradient(...[px(x), px(y), px(r)]);

        } else {

            const [x0, y0, x1, y1] = start;

            grd = ctx.createLinearGradient(...[px(x0), px(y0), px(x1), px(y1)]);

        }

        colorStop.forEach((cs) => {

            grd.addColorStop(...cs);

        });

        ctx.setFillStyle(grd);


        const [x, y, widht, height] = end;

        ctx.fillRect(...[px(x), px(y), px(widht), px(height)]);

    };


    const formatBorder = (border) => {

        if (!border) return [0, 'rgba(0,0,0,0)'];

        const borderArr = border.split(' ');

        borderArr[0] = px(borderArr[0]);

        if (!borderArr[1]) borderArr[1] = 'rgba(0,0,0,0)';

        return borderArr;

    }


    const formatPadding = (padding) => {

        let paddingArr = [];

        if (typeof padding === 'number') {

            paddingArr.length = 4;

            paddingArr.fill(px(padding));

        } else {

            paddingArr = padding.split(' ').map(p => px(p));

        }

        return paddingArr;

    }


    const formatText = (ctx, text, pxMW, pxLH) => {

        const textArr = [];

        let tempArr = [];

        let tempWidth = 0;

        text.split('').forEach(word => {

            const w = ctx.measureText(word).width;


            if (tempWidth + w > pxMW) {

                textArr.push(tempArr.join(''));

                tempArr = [word];

                tempWidth = 0;

            } else {

                tempArr.push(word);

                tempWidth = w + tempWidth + 1;

            }

        });

        if (tempArr.length > 0) {

            textArr.push(tempArr.join(''));

        }

        const textWidth = textArr.length > 1 ? pxMW : ctx.measureText(text).width;

        const textHeight = textArr.length * pxLH;

        return { textArr, textWidth, textHeight };

    }


    function drawed() {

        const {

            width,

            height,

        } = this.data;


        const self = this;

        // 输出的图片的宽度和高度

        const destWidth = px(width) * pixelRatio;

        const destHeight = px(height) * pixelRatio;

        wx.canvasToTempFilePath({

            destWidth,

            destHeight,

            canvasId: 'draw-canvas',

            success(res) {

                self.setData({

                    imageUrl: res.tempFilePath,

                });

                // 微信小程序自定义事件

                self.triggerEvent('toTempFile', res);

            },

        }, this);

    }


    Component({

        properties: {

            width: {

                type: Number,

                value: 750,

            },

            height: {

                type: Number,

                value: 500,

            },

            layers: {

                type: Array,

                value: [],

            },

            background: {

                type: Object,

                value: null,

            },

        },


        data: {

            imageUrl: null,

        },


        attached() {

            const {

                background,

                layers,

                width,

                height,

            } = this.data;

            // 创建canvas的绘图上下文

            const ctx = wx.createCanvasContext('draw-canvas', this);

            // 背景图片

            if (background) {

                const {

                    imageResource,

                    dx = 0,

                    dy = 0,

                    dWidth = width,

                    dHeight = height,

                    color,

                } = background;

                // 背景颜色

                if (color) {

                    const {

                        start,

                        end,

                        colorStop,

                        shape = 'Linear',

                    } = color;

                    fillColor(ctx, start, end, colorStop, shape);

                }

                // ctx.drawImage()绘制图像到画布

                // imageResource所有绘制的图片资源

                imageResource && ctx.drawImage(imageResource, px(dx), px(dy), px(dWidth), px(dHeight));

            }


            // 图层

            layers.forEach((layer) => {

                if (layer.type === 'text') {

                    const {

                        // textBaseline = 'top',

                        textAlign = 'left',

                        fontSize = 32,

                        text = '',

                        x = 0,

                        y = 0,

                        color = '#000',

                        lineHeight = 44,

                        maxWidth = width,

                        border = '0',

                        radius = 0,

                        padding = 0,

                        bgColor = null,

                        maxLine = 0,

                    } = layer;

                    const pxx = px(x);

                    const pxy = px(y);

                    const pxFS = px(fontSize);

                    const pxLH = px(lineHeight);

                    const pxMW = px(maxWidth);

                    const pxRadius = px(radius);

                    ctx.setFontSize(pxFS);


                    // border

                    const [pxbw, bc] = formatBorder(border);

                    // padding 上右下左

                    const [pt, pr, pb, pl] = formatPadding(padding);


                    let {textArr, textWidth, textHeight} = formatText(ctx, text, pxMW, pxLH);

                    // console.log(textArr, maxLine, textWidth);

                    if (maxLine) {

                        const overLine = textArr.length > maxLine;

                        textArr.length = maxLine;

                        if (overLine) {

                            const strArr = textArr[maxLine - 1].split('');

                            strArr.splice((strArr.length - 2), 2, '...', '...');

                            textArr.splice(maxLine - 1, 1, strArr.join(''));

                        }

                    }


                    // 真实宽高

                    const realWidth = textWidth + pl + pr;

                    const realHeight = textHeight + pt + pb;


                    let realX = pxx - pl;

                    let realY = pxy - pt;

                    if (textAlign === 'right') {

                        realX = pxx - pl - textWidth;

                        realY = pxy - pt;

                    } else if (textAlign === 'center') {

                        realX = pxx - pl - textWidth / 2;

                        realY = pxy - pt;

                    }


                    // 边框

                    // 保存绘图上下文

                    ctx.save();

                    ctx.setStrokeStyle(bc);

                    if (bgColor) {

                        ctx.setFillStyle(bgColor);

                        ctx.fillRect(realX, realY, realWidth, realHeight);

                    }

                    ctx.stroke();

                    // 恢复之前保存的绘图上下文

                    ctx.restore();


                    ctx.setFillStyle(color);

                    ctx.setTextBaseline('top');

                    ctx.setTextAlign(textAlign);

                    textArr.forEach((str, i) => {

                        ctx.fillText(str, pxx, pxy + i * pxLH, pxMW);

                    });

                }


                if (layer.type === 'image') {

                    const {

                        imageResource,

                        dx = 0,

                        dy = 0,

                        radius = 0,

                        dWidth = width,

                        dHeight = height,

                        border,

                    } = layer;

                    const [pxbw, bc] = formatBorder(border);

                    const [pxdx, pxdy, pxdWidth, pxdHeight, pxdRadius] =

                        [px(dx), px(dy), px(dWidth), px(dHeight), px(radius)];


                    if (radius) {

                        // 保存绘图上下文

                        ctx.save();

                        ctx.setStrokeStyle(bc);

                        // ctx.drawImage()绘制图像到画布

                        ctx.drawImage(imageResource, pxdx, pxdy, pxdWidth, pxdHeight);

                        // 恢复之前保存的绘图上下文

                        ctx.restore();

                    } else {

                        // 保存绘图上下文

                        ctx.save();

                        ctx.drawImage(imageResource, pxdx, pxdy, pxdWidth, pxdHeight);

                        // 恢复之前保存的绘图上下文

                        ctx.restore();

                    }

                }

            });

            ctx.draw(false, () => {

                console.log('-------');

                drawed.call(this);

            });

            ctx.draw(true, () => {

                console.log('=======');

                drawed.call(this);

            });

    第二次draw回调不执行,加了定时勉强可以实现,但是同时绘制多张图片总不能一直加setTimeout...,有大牛帮看下么?

    setTimeout(() => {

            console.log('=======');

            drawed.call(this);

    }, 1000);



    2018-11-12
    有用
    回复
  • 灵芝
    灵芝
    2018-11-07

    麻烦提供出现问题的机型和微信版本,以及能复现问题的简单代码片段https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html

    2018-11-07
    有用
    回复 6
    查看更多(1)
  • 卢霄霄
    卢霄霄
    2018-11-07

    能来个代码片段吗?可能是bug,也可能是你写法的问题呢

    2018-11-07
    有用
    回复 11
    • 格桑梅朵
      格桑梅朵
      2018-11-12

      抽取了一个自定义组件,代码不好剥离,贴上了js实现方法,感谢🙏


      2018-11-12
      回复
    • 卢霄霄
      卢霄霄
      2018-11-12回复格桑梅朵

      你是连续 draw两次吗?

      2018-11-12
      回复
    • 格桑梅朵
      格桑梅朵
      2018-11-13回复卢霄霄

      是的,有什么问题吗?

      2018-11-13
      回复
    • 卢霄霄
      卢霄霄
      2018-11-13回复格桑梅朵

      只是不理解这是什么场景。。需要连续draw。。这么写可以吗?

      ctx.draw(false, () => {

      console.log('-------');

      drawed.call(this);

      ctx.draw(true, () => {

      console.log('=======');

      drawed.call(this);

      });

      });

      2018-11-13
      回复
    • 格桑梅朵
      格桑梅朵
      2018-11-13回复卢霄霄

      https://developers.weixin.qq.com/s/mZBW0TmT753L

      2018-11-13
      回复
    查看更多(6)
登录 后发表内容