小程序
小游戏
企业微信
微信支付
扫描小程序码分享
- 当前 Bug 的表现(可附上截图)
- 预期表现
- 复现路径
- 提供一个最简复现 Demo
ctx.draw(false, () => {
drawed.call(this);
});
ctx.draw(true, () => {
4 个回答
加粗
标红
插入代码
插入链接
插入图片
上传视频
第二次draw的时候如果延时1ms以上就会有回调,测试发现1ms的时候让然不一定有回调,代码片段:https://developers.weixin.qq.com/s/Mj5Jtamm7g4A
你好,麻烦通过点击下方“反馈信息”按钮,提供出现问题的。
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));
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;
tempArr.push(word);
tempWidth = w + tempWidth + 1;
if (tempArr.length > 0) {
const textWidth = textArr.length > 1 ? pxMW : ctx.measureText(text).width;
const textHeight = textArr.length * pxLH;
return { textArr, textWidth, textHeight };
function drawed() {
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: {
value: 500,
layers: {
type: Array,
value: [],
background: {
type: Object,
value: null,
data: {
imageUrl: null,
attached() {
background,
layers,
// 创建canvas的绘图上下文
const ctx = wx.createCanvasContext('draw-canvas', this);
// 背景图片
if (background) {
imageResource,
dx = 0,
dy = 0,
dWidth = width,
dHeight = height,
color,
} = background;
// 背景颜色
if (color) {
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') {
// 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;
// 边框
// 保存绘图上下文
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') {
border,
const [pxdx, pxdy, pxdWidth, pxdHeight, pxdRadius] =
[px(dx), px(dy), px(dWidth), px(dHeight), px(radius)];
if (radius) {
ctx.drawImage(imageResource, pxdx, pxdy, pxdWidth, pxdHeight);
console.log('-------');
console.log('=======');
第二次draw回调不执行,加了定时勉强可以实现,但是同时绘制多张图片总不能一直加setTimeout...,有大牛帮看下么?
setTimeout(() => {
}, 1000);
麻烦提供出现问题的机型和微信版本,以及能复现问题的简单代码片段(https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html)
抽取了一个自定义组件,代码不好剥离,贴上了js实现方法。
不需要很复杂的,只要能复现问题就可以了
https://developers.weixin.qq.com/s/mZBW0TmT753L
劳烦看下是不是小程序的bug.....
canvas还不允许在swiper中使用哈:https://developers.weixin.qq.com/miniprogram/dev/component/native-component.html
能来个代码片段吗?可能是bug,也可能是你写法的问题呢
抽取了一个自定义组件,代码不好剥离,贴上了js实现方法,感谢🙏
你是连续 draw两次吗?
是的,有什么问题吗?
只是不理解这是什么场景。。需要连续draw。。这么写可以吗?
关注后,可在微信内接收相应的重要提醒。
请使用微信扫描二维码关注 “微信开放社区” 公众号
第二次draw的时候如果延时1ms以上就会有回调,测试发现1ms的时候让然不一定有回调,代码片段:https://developers.weixin.qq.com/s/Mj5Jtamm7g4A
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);
麻烦提供出现问题的机型和微信版本,以及能复现问题的简单代码片段(https://developers.weixin.qq.com/miniprogram/dev/devtools/minicode.html)
抽取了一个自定义组件,代码不好剥离,贴上了js实现方法。
不需要很复杂的,只要能复现问题就可以了
https://developers.weixin.qq.com/s/mZBW0TmT753L
劳烦看下是不是小程序的bug.....
canvas还不允许在swiper中使用哈:https://developers.weixin.qq.com/miniprogram/dev/component/native-component.html
能来个代码片段吗?可能是bug,也可能是你写法的问题呢
抽取了一个自定义组件,代码不好剥离,贴上了js实现方法,感谢🙏
你是连续 draw两次吗?
是的,有什么问题吗?
只是不理解这是什么场景。。需要连续draw。。这么写可以吗?
ctx.draw(false, () => {
console.log('-------');
drawed.call(this);
ctx.draw(true, () => {
console.log('=======');
drawed.call(this);
});
});
https://developers.weixin.qq.com/s/mZBW0TmT753L