**
基于UNI.app的小程序端的canvas, 绘制海报–图片更改为圆形,对文字段落进行处理
**
canvas绘制,找准x轴y轴坐标
setFillStyle()设置文本字体颜色,上传下载要记得合法域名检测
保存海报至相册要保证首先获取相册授权,uni.app有介绍如何拉取授权这里就不详细说明(另一篇文章也有实例参考)
代码如下
<template>
<button class="save-result" @click="saveToAlbum">
保存结果
</button>
<view style="width:0px;height:0px;overflow:hidden;">
<canvas
style="width: 750px;height:2150px;"
canvas-id="poster-canvas"
></canvas>
</view>
</template>
<srcipt>
export default{
data(){
return {
detail:{},
score:{},
header:'',
savebtn:false,
}
},
onLoad(option) {
let {product_id,user_id} = option
this.getResult()
},
methods:{
getResult() {
let params = { user_id: this.user_id, product_id: this.product_id };
getResult(params).then((res) => {
this.detail = res;
this.header = this.detail.img_url
this.score = this.detail.score.info
// console.log(this.score);
});
},
async saveToAlbum(){
if(this.savebtn) return false;//确保button按钮一时间仅触发一次
this.savebtn = true;
let ctx = uni.createCanvasContext("poster-canvas");
let canvas = {};
//绘制出海报底板 src地址可以是本地地图也可以是cdn地址
await uni.getImageInfo({
src: "https:baidu.com",
}).then((img) => {
img = img[0] || img[1];
if (img.errMsg == "getImageInfo:ok") {
let { width, height } = img;
canvas = { width, height };
ctx.drawImage(img.path, 0, 0, width, height);
}
}).catch((e) => {
console.log(e);
});
// 把图片裁剪为圆形并绘制出来 img 图片信息 width 宽 height 高 x y 绘制的坐标
// img.width,img.height 实际数字较大,故采用自定义 width height
// radius,diameter 半径,直径
//绘制圆形图片
function circleImage(img,width,height,x,y){
let radius,diameter
//以最短的边为半径绘制圆
if(width > height){
radius = height / 2;
} else {
radius = width / 2;
}
diameter = radius * 2;
ctx.beginPath();
ctx.arc(x+radius, y+radius, radius, 0, Math.PI * 2, false);
ctx.clip();
ctx.drawImage(img.path, x, y, diameter, diameter);
//ctx.restore();
//返回URL地址
//return cxt.toDataURL('image/png');
}
let total = this.detail.score.total;
ctx.font = "42px Arial";
ctx.setFillStyle("#F14F55");
ctx.fillText("相似人数:"+ total, 220, 495);
let word = this.detail.content.content;
dealWords({
ctx: ctx,//画布上下文
fontSize: 32,//字体大小
fillstyle:'#260680',
word: word,//需要处理的文字
maxWidth: 630,//一行文字最大宽度
x: 60,//文字在x轴要显示的位置
y: 705,//文字在y轴要显示的位置
maxLine: 8//文字最多显示的行数
});
// 处理文字段落问题
function dealWords(options) {
ctx.font = options.ctx._font.value;
ctx.setFillStyle(options.fillstyle);
var allRow = Math.ceil(options.ctx.measureText(options.word).width / options.maxWidth);//实际总共能分多少行
var count = allRow >= options.maxLine ? options.maxLine : allRow;//实际能分多少行与设置的最大显示行数比,谁小就用谁做循环次数
var endPos = 0;//当前字符串的截断点
for (var j = 0; j < count; j++) {
var nowStr = options.word.slice(endPos);//当前剩余的字符串
var rowWid = 0;//每一行当前宽度
if (options.ctx.measureText(nowStr).width > options.maxWidth) {//如果当前的字符串宽度大于最大宽度,然后开始截取
for (var m = 0; m < nowStr.length; m++) {
rowWid += options.ctx.measureText(nowStr[m]).width;//当前字符串总宽度
if (rowWid > options.maxWidth) {
if (j === options.maxLine - 1) { //如果是最后一行
options.ctx.fillText(nowStr.slice(0, m - 1) + '...', options.x, options.y + (j + 1) * 50); //(j+1)*36这是每一行的高度
} else {
options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * 50);
}
endPos += m;//下次截断点
break;
}
}
} else {//如果当前的字符串宽度小于最大宽度就直接输出
options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * 50);
}
}
}
ctx.font = "38px Arial";
ctx.setFillStyle("#260680")
//对数据进行循环
this.score.forEach(function(res, index) {
ctx.fillText(res.province_name, 110, 1305 + index * 115);
ctx.fillText(res.num +'人', 525, 1305 + index * 115);
});
//绘制圆形头像
await uni.getImageInfo({
src: this.header,
})
.then((img) => {
if (img[1].errMsg == "getImageInfo:ok") {
let { width, height } = img[1];
circleImage(img[1],322,322,215,56)
}
})
ctx.draw(true, () => {
uni.canvasToTempFilePath(
{
x: 0,
y: 0,
width: canvas.width,
height: canvas.height,
canvasId: "poster-canvas",
fileType: "jpg",
quality: 0.8,
success: (res) => {
this.savebtn = false;
//保存至相册
uni.saveImageToPhotosAlbum({
filePath: res.tempFilePath,
success:(res) =>{
uni.showToast({
title: "保存成功",
duration: 2000,
});
},
fail() {
uni.showToast({
title: "保存失败!",
duration: 2000,
icon: "none",
});
},
});
},
fail: (e) => {
console.log("保存失败", e);
},
complete(){
this.savebtn = false;
uni.hideLoading()
}
},
);
});
},
}
}
</srcipt>
海报效果图
更多内容
求关注,微信公众号-前端程序猿Pro,不至于前端~