uniapp使用canvas画海报
文章将介绍canvas的基本使用,提供各种形状,canvas画网络图片、二维码,保存图片到手机的方法。
dom部分
<canvas
style="width: 100vw; height: 500px; margin: 0 auto"
:style="{ height: 1267 * rpx + 'px' }"
canvas-id="Canvas"
id="CanvasId"
></canvas>
<view class="sharePosterBtn">
<view class="sharePosterBtn1" @click="saveImage">保存图片</view>
<button open-type="share" class="sharePosterBtn2">名片转发</button>
</view>
画图的方法
async drawCanvas() {
uni.showLoading({
title: "加载中",
});
let res = uni.getSystemInfoSync();
let rpx = res.screenWidth / 750;
let ctx = uni.createCanvasContext("Canvas", this);
let phone = "../../static/shouji.png";
let email = "../../static/youxiang2.png";
let location = "../../static/daohangdizhi.png";
let infoRes = await api("businessCardInfo", {
params: {
staff_id: this.staff_id
}
});
if (infoRes.code == 0) {
this.company_info = infoRes.data.company_info;
this.staff_info = infoRes.data.staff_info;
this.template_info = infoRes.data.template_info;
}
console.log(infoRes, "海报详情");
let avatar = await this.getImage(this.staff_info.avatar.full_url)
let Qrcode = await this.getQrCode()
this.drawRoundedRect(
ctx,
0 * rpx,
0 * rpx,
750 * rpx,
846 * rpx,
0 * rpx,
true,
"#5C606A"
);
ctx.setFontSize(34 * rpx);
ctx.setFillStyle("#ffffff");
ctx.fillText( "HI,很高兴认识您", 38 * rpx, 110 * rpx);
ctx.setFontSize(34 * rpx);
ctx.setFillStyle("#ffffff");
ctx.fillText( "这是我的名片。", 38 * rpx, 176 * rpx);
// 二维码
this.drawRoundedRect(
ctx,
556 * rpx,
74 * rpx,
160 * rpx,
160 * rpx,
24 * rpx,
true,
"#ffffff"
);
ctx.drawImage(Qrcode, 564 * rpx, 84 * rpx, 140 * rpx, 140 * rpx);
// this.circleImgOne(ctx, firmLogo, 560 * rpx,84 * rpx ,24 * rpx, 160 * rpx, 160 * rpx)
// 标语 上白线
this.drawRoundedRect(
ctx,
32 * rpx,
294 * rpx,
688 * rpx,
12 * rpx,
0 * rpx,
true,
"#ffffff"
);
//标语 左边
ctx.setFontSize(66 * rpx);
ctx.setFillStyle("#ffffff");
ctx.fillText("#", 50 * rpx, 464 * rpx);
// 介绍 及 换行处理
ctx.setFontSize(46 * rpx);
ctx.setFillStyle("#ffffff");
let textResult = this.breakLinesForCanvas(
ctx,
this.template_info.params.title,
510 * rpx,
46 * rpx
);
textResult.map((item,index)=>{
index += index * 70
ctx.fillText(item, 122 * rpx, (415 + index) * rpx)
})
//标语 右边
ctx.setFontSize(66 * rpx);
ctx.setFillStyle("#ffffff");
ctx.fillText("#", 670 * rpx, 464 * rpx);
// 标语 下白线
this.drawRoundedRect(
ctx,
32 * rpx,
570 * rpx,
688 * rpx,
12 * rpx,
0 * rpx,
true,
"#ffffff"
);
ctx.setFontSize(30 * rpx);
ctx.setFillStyle("#ffffff");
ctx.fillText(this.company_info.name, 484 * rpx, 685 * rpx);
// 中间白框
this.drawRoundedRect(
ctx,
0 * rpx,
710 * rpx,
750 * rpx,
526 * rpx, //436+90 填充了底部的footer
0 * rpx,
true,
"#5C606A"
);
this.drawRoundedRect(
ctx,
0 * rpx,
710 * rpx,
750 * rpx,
436 * rpx,
60 * rpx,
true,
"#ffffff"
);
// // 头像
this.drawRoundedRect(
ctx,
46 * rpx,
686 * rpx,
166 * rpx,
166 * rpx,
82 * rpx,
true,
"#ffffff"
);
this.circleImgOne(ctx, avatar, 50 * rpx,690 * rpx ,80 * rpx, 160 * rpx, 160 * rpx)
ctx.setFontSize(36 * rpx);
ctx.setFillStyle("#5C606A");
this.textBold(ctx, this.staff_info.name, 230 * rpx, 782 * rpx);
ctx.setFontSize(26 * rpx);
ctx.setFillStyle("#5C606A");
ctx.fillText(this.staff_info.department_name, 230 * rpx, 835 * rpx);
ctx.setFontSize(26 * rpx);
ctx.setFillStyle("#5C606A");
ctx.fillText(this.staff_info.position, 370 * rpx, 835 * rpx);
// 分割线
this.drawRoundedRect(
ctx,
0 * rpx,
890 * rpx,
750 * rpx,
1 * rpx,
0 * rpx,
true,
"#E9E9E9"
);
ctx.drawImage(phone, 46 * rpx, 945 * rpx, 25 * rpx, 36 * rpx);
ctx.drawImage(email, 46 * rpx, 1010 * rpx, 35 * rpx, 22 * rpx);
ctx.drawImage(location, 46 * rpx, 1060 * rpx, 28 * rpx, 36 * rpx);
ctx.setFontSize(30 * rpx);
ctx.setFillStyle("#5C606A");
ctx.fillText(this.staff_info.phone, 110 * rpx, 970 * rpx);
ctx.setFontSize(30 * rpx);
ctx.setFillStyle("#5C606A");
ctx.fillText(this.staff_info.email, 110 * rpx, 1025 * rpx);
ctx.setFontSize(30 * rpx);
ctx.setFillStyle("#5C606A");
ctx.fillText(
this.company_info.name,
110 * rpx,
1086 * rpx
);
ctx.setFontSize(20 * rpx);
ctx.setFillStyle("#737885");
ctx.fillText("一步云智能营销系统", 34 * rpx, 1206 * rpx);
ctx.setFontSize(20 * rpx);
ctx.setFillStyle("#737885");
ctx.fillText("step technology cloud", 462 * rpx, 1206 * rpx);
ctx.clip();
ctx.restore();
ctx.draw();
uni.hideLoading();
}
画各种形状的方法
圆角矩形
/**
* 绘制圆角矩形
* @param {*} ctx CanvasContext
* @param {*} x x轴 坐标
* @param {*} y y轴 坐标
* @param {*} width 宽
* @param {*} height 高
* @param {*} r r 圆角
* @param {boolean} fill 是否填充颜色
*/
drawRoundedRect(ctx, x, y, width, height, r, fill, fillColor) {
ctx.beginPath();
ctx.arc(x + r, y + r, r, Math.PI, (Math.PI * 3) / 2);
ctx.lineTo(width - r + x, y);
ctx.arc(width - r + x, r + y, r, (Math.PI * 3) / 2, Math.PI * 2);
ctx.lineTo(width + x, height + y - r);
ctx.arc(width - r + x, height - r + y, r, 0, (Math.PI * 1) / 2);
ctx.lineTo(r + x, height + y);
ctx.arc(r + x, height - r + y, r, (Math.PI * 1) / 2, Math.PI);
ctx.closePath();
if (fill) {
ctx.fillStyle = fillColor;
ctx.fill();
}
},
圆形
// 绘制圆形
circle(ctx, img, x, y, r) {
ctx.save();
let d = r * 2;
let cx = x + r;
let cy = y + r;
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.setFillStyle("#FFFFFF");
ctx.fill();
ctx.restore();
},
圆形图片
// 绘制圆形图片
circleImgOne(ctx, img, x, y, r, width, height) {
ctx.save();
ctx.beginPath();
let cx = x + r;
let cy = y + r;
ctx.arc(cx, cy, r, 0, 2 * Math.PI);
ctx.clip();
ctx.drawImage(img, x, y, width, height);
ctx.restore();
},
文本换行
/**
* canvas 文本换行计算
* @param {*} context CanvasContext
* @param {string} text 文本
* @param {number} width 内容宽度
* @param {font} font 字体(字体大小会影响宽)
*/
breakLinesForCanvas(context, text, width, font) {
const findBreakPoint = (text, width, context) => {
var min = 0;
var max = text.length - 1;
while (min <= max) {
var middle = Math.floor((min + max) / 2);
var middleWidth = context.measureText(text.substr(0, middle)).width;
var oneCharWiderThanMiddleWidth = context.measureText(
text.substr(0, middle + 1)
).width;
if (middleWidth <= width && oneCharWiderThanMiddleWidth > width) {
return middle;
}
if (middleWidth < width) {
min = middle + 1;
} else {
max = middle - 1;
}
}
return -1;
}
var result = [];
var textArray = text.split("\r\n");
for (let i = 0; i < textArray.length; i++) {
let item = textArray[i];
var breakPoint = 0;
while ((breakPoint = findBreakPoint(item, width, context)) !== -1) {
result.push(item.substr(0, breakPoint));
item = item.substr(breakPoint);
}
if (item) {
result.push(item);
}
}
return result;
},
字体加粗
// 字体加粗
textBold(ctx, v, x, y, width = "") {
ctx.fillText(v, x, y, width);
ctx.fillText(v, x + 0.5, y, width);
},
canvas画网络图片
使用网络图片需要先使用uni.downloadFile下载才能在canvas中渲染
getImage(url){
return new Promise((resolve,reject)=>{
uni.downloadFile({
url,
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath)
}
}
});
})
},
然后在绘图方法中使用await,使先获取到图片再进行canvas绘制
let avatar = await this.getImage(this.staff_info.avatar.full_url)
canvas画二维码
渲染二维码也一样需要使用uni.downloadFile,带上token获取二维码
getQrCode(){
const token = uni.getStorageSync("token");
return new Promise((resolve,reject)=>{
uni.downloadFile({
url: `https://wxopen.hzyibu.cn/xcx/crm.Card/staffCardQrcode?staff_id=${this.staff_id}`,
header: {
token
},
success: (res) => {
if (res.statusCode === 200) {
resolve(res.tempFilePath)
}
}
});
})
},
在绘图方法中使用await使先获取到二维码后再进行canvas绘制
let Qrcode = await this.getQrCode()
保存图片
saveImage() {
uni.canvasToTempFilePath({
canvasId: "Canvas",
success: function (res) {
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success: function () {
uni.showToast({
title: "保存成功!",
icon: "none",
});
},
});
},
});
},