代码
<template><view><canvas canvas-id="canvas" class="canvas-c"></canvas><!-- <h1>999</h1> --></view>
</template><script>export default {name: 'sharePos',props: {// 绘制图片的尺寸// imageSize: {// type: Object,// default: () => {}// },// canvas绘制的数据canvasData: {type: Array,default: () => []},},data() {return {// 屏幕宽度screenWidth: 0,// canvas画布的宽度width: 0,// canvas画布的高度height: 0,// 当前图片放大倍数 - 清晰度count: 2,pxWid: 1};},mounted() {this.initCanvasUnitToRpx();},watch: {// // 监听是否开始绘制// isDraw: async function(newVal) {// console.log('newVAL',newVal)// if(newVal) {// this.getSystemInfo();// }// }},methods: {initCanvasUnitToRpx() {uni.getSystemInfo({success: res => {// 获取屏幕宽度 计算出 适配的单位换算let wid = res.windowWidth / 375;this.pxWid = wid// this.width = this.imageSize.width * this.count;// this.height = this.imageSize.height * this.count;const {ceil} = Math;let renderList =this.canvasData.map(ele => {let info = {};if (ele.type == 'rect') {console.log('ele----------------', ele);let {x,y,width,height,radian_1,radian_2,radian_3,radian_4} = ele.attr;console.log('999999999999999', x, y, width, height, radian_1, radian_2,radian_3, radian_4);info.x = ceil(x * wid);info.y = ceil(y * wid);info.width = ceil(width * wid);info.height = ceil(height * wid);info.radian_1 = ceil(radian_1 * wid);info.radian_2 = ceil(radian_2 * wid);info.radian_3 = ceil(radian_3 * wid);info.radian_4 = ceil(radian_4 * wid);console.log('background*---99999rect', info);}if (ele.type == 'image') {let {x,y,width,height,radian_1,radian_2,radian_3,radian_4} = ele.attr;info.x = ceil(x * wid);info.y = ceil(y * wid);info.width = ceil(width * wid);info.height = ceil(height * wid);info.radian_1 = ceil(radian_1 * wid);info.radian_2 = ceil(radian_2 * wid);info.radian_3 = ceil(radian_3 * wid);info.radian_4 = ceil(radian_4 * wid);console.log('background*---99999', info);}if (ele.type == 'text') {let {x,y,fontSize,height,fontH,maxW,rowCount} = ele.attr;console.log('66666666666666', x, y, fontSize, height, fontH, maxW,rowCount);info.x = ceil(x * wid);info.y = ceil(y * wid);info.fontSize = ceil(fontSize * wid) + 'px';info.fontH = ceil(fontH * wid);info.maxW = ceil(maxW * wid);// info.rowCount = parseInt(rowCount * wid) >= 1 ? parseInt(rowCount *// wid) : 1;console.log('textInfo', info);}let result = {};result.type = ele.type;let resultAttr = {...ele.attr,...info};result.attr = resultAttr;return result;});console.log('renderList', renderList);this.getImageByCanvasData(renderList);}});},/*** 通过数据绘制图片* @param {array} data canvas绘制的数组* 格式:每一项的数据* { type: 'rect', attr: { color: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }* { type: 'image', attr: { image: '', x, y, width, height, radian_1, radian_2, radian_3, radian_4 } }* { type: 'text', attr: { text: '', x, y, color, size, weight, writingMode } }* */async getImageByCanvasData(data) {console.log('99999', data);// 获取canvas上下文对象const context = uni.createCanvasContext('canvas', this);// 清空画布// context.clearRect(0, 0, this.width * this.count, this.height * this.count);for (const item of data) {// 判断类型if (item.type === 'rect') {// 绘制圆边矩形this.drawRoundRectangular(context,item.attr.color,item.attr.x,item.attr.y,item.attr.width,item.attr.height,item.attr.radian_1,item.attr.radian_2,item.attr.radian_3,item.attr.radian_4);} else if (item.type === 'image' && item.attr.image) {// 绘制圆边图片await this.drawRoundImageToCanvas(context,item.attr.image,item.attr.x,item.attr.y,item.attr.width,item.attr.height,item.attr.radian_1,item.attr.radian_2,item.attr.radian_3,item.attr.radian_4);} else if (item.type === 'text' && item.attr.text) {console.log('text', item);// 绘制文本this.drawMoreText(context,item.attr.text,item.attr.color,item.attr.align,item.attr.x,item.attr.y,item.attr.fontStyle,item.attr.fontVariant,item.attr.fontWeight,item.attr.fontSize,item.attr.fontFamily,item.attr.fontH,item.attr.maxW,item.attr.rowCount);} }// 绘制图片context.draw(false, () => {uni.canvasToTempFilePath({canvasId: 'canvas',x: 0,y: 0,width: this.width,height: this.height,destWidth: this.width,height: this.height,success: res => {this.$emit('generateImageSuccessful', res.tempFilePath);}},this);});},/*** 绘制文本* @param {string} context Canvase的实例* @param {string} text 文本内容* @param {number} x 矩形的x坐标* @param {number} y 矩形的y坐标* @param {number} color 文本颜色* @param {number} size 字体的大小* @param {string} weight 字体的粗细* @param {string} writingMode 字体的排列方式 - initial 水平 tb 垂直* */drawTextToCanvas(context, text, x, y, color = '#000', size = 16, weight = '400', writingMode = 'initial') {context.fillStyle = color;context.font = `normal ${weight} ${size}px sans-serif`;if (writingMode === 'tb') {const temp = text.split('');for (let i = 0; i < temp.length; i++) {context.fillText(temp[i], x, i * size + y);}} else {// 判断是否有换行符const temp = text.split('\n');for (let i = 0; i < temp.length; i++) {context.fillText(temp[i], x, i * size + y + i * size * 0.2); // i * size * 0.2 增加换行的间距}}},drawMoreText(ctx, text, color, align, x, y, fontStyle, fontVariant, fontWeight, fontSize, fontFamily, fontH,maxW, rowCount) {/*** 绘制文本** text 文本* color 文字颜色* align 对其方式* x 横坐标* y 纵坐标* fontStyle 规定字体样式* fontVariant 规定字体变体* fontWeight 规定字体的粗细* fontSize 规定字号和行高,以像素计。* fontFamily 规定字体系列* fontH, 行高maxW, 最大宽度rowCount 最多几行* */console.log('drawMoreText000000000000', ctx, text, color, align, x, y, fontStyle, fontVariant, fontWeight,fontSize, fontFamily, fontH, maxW, rowCount);ctx.textAlign = align; //对其方式 left 左 center居中ctx.fillStyle = color; //filstyle 文本颜色ctx.font = `${fontStyle} ${fontVariant} ${fontWeight} ${fontSize} ${fontFamily}`; //字体样式// 以上代码在fillText执行前调用 否则无效// 文本处理let strArr = text.split("");let row = [];let temp = "";for (let i = 0; i < strArr.length; i++) {if (ctx.measureText(temp).width < maxW) {temp += strArr[i];} else {i--; //这里添加了i-- 是为了防止字符丢失,效果图中有对比row.push(temp);temp = "";}}row.push(temp); // row有多少项则就有多少行//如果数组长度大于2,现在只需要显示两行则只截取前两项,把第二行结尾设置成'...'console.log("row8888888888888888888888888", row)if (row.length > rowCount) {let rowCut = row.slice(0, rowCount);console.log("rowCut", rowCut, rowCount)let rowPart = rowCutlet test = "";let empty = [];for (let i = 0; i < rowPart.length; i++) {if (ctx.measureText(test).width < maxW) {test += rowPart[i];} else {break;}}empty.push(test);let group = empty[0] + "..." //这里只显示两行,超出的用...表示rowCut.splice(rowCount - 1, 1, group);row = rowCut;}console.log('row111111111111111111111', row);// 把文本绘制到画布中for (let i = 0; i < row.length; i++) {// 一次渲染一行if (align == 'center') {ctx.fillText(row[i], Math.ceil(maxW / 2 + x), y + i * fontH, maxW); //字体文案和坐标// 文字 最大宽度 } else if (align == 'left') {ctx.fillText(row[i], x, y + i * fontH, maxW);}else if (align=='right'){// ctx.textAlign ="right"//align 为right 时 x 表示靠右的距离ctx.fillText(row[i],375*this.pxWid-x, y + i * fontH, maxW);}}// 保存当前画布状态ctx.save();// 将之前在绘图上下文中的描述(路径、变形、样式)画到 canvas 中。// ctx.draw()// }, 20)console.log('pppppppppppppppppppp0000');},/*** 绘制圆边矩形* @param {string} context Canvase的实例* @param {string} color 填充的颜色* @param {number} x 矩形的x坐标* @param {number} y 矩形的y坐标* @param {number} width 矩形的宽度* @param {number} height 矩形的高度* @param {number} height 图片的高度* @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部* @param {number} radian_2 弧度大小 - radian_2 右下 的弧度* @param {number} radian_3 弧度大小 - radian_3 左下 的弧度* @param {number} radian_4 弧度大小 - radian_4 左上 的弧度* */drawRoundRectangular(context, color, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {context.save();this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);context.setFillStyle(color);context.fill();context.restore();},/*** 绘制圆角图片* @param {string} context Canvase的实例* @param {string} image 图片地址* @param {number} x 图片的x坐标* @param {number} y 图片的y坐标* @param {number} width 图片的宽度* @param {number} height 图片的高度* @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部* @param {number} radian_2 弧度大小 - radian_2 右下 的弧度* @param {number} radian_3 弧度大小 - radian_3 左下 的弧度* @param {number} radian_4 弧度大小 - radian_4 左上 的弧度* */async drawRoundImageToCanvas(context, image, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {context.save();console.log('9888888888888888888888', context, image, x, y, width, height, radian_1, radian_2,radian_3, radian_4);this.drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4);context.drawImage(await this.handleNetworkImgaeTransferTempImage(image), x, y, width, height);context.restore();},/*** 绘制圆边路径* @param {string} context Canvase的实例* @param {number} x 图片的x坐标* @param {number} y 图片的y坐标* @param {number} width 图片的宽度* @param {number} height 图片的高度* @param {number} radian_1 弧度大小 - radian_1 右上 的弧度, 1个参数代表全部* @param {number} radian_2 弧度大小 - radian_2 右下 的弧度* @param {number} radian_3 弧度大小 - radian_3 左下 的弧度* @param {number} radian_4 弧度大小 - radian_4 左上 的弧度* */drawRoundPath(context, x, y, width, height, radian_1, radian_2, radian_3, radian_4) {// 设置弧度radian_2 = radian_2 === -1 ? radian_1 : radian_2;radian_3 = radian_3 === -1 ? radian_1 : radian_3;radian_4 = radian_4 === -1 ? radian_1 : radian_4;console.log('988888888888888888888899999drawRoundPath', context, x, y, width, height, radian_1, radian_2,radian_3, radian_4);// 创建路径 - 绘制带圆边的矩形context.beginPath();context.moveTo(x + radian_2 / 2 + 4, y);context.arcTo(x + width, y, x + width, y + height, radian_1);context.arcTo(x + width, y + height, x, y + height, radian_2);context.arcTo(x, y + height, x, y, radian_3);context.arcTo(x, y, x + width, y, radian_4);// 关闭路径 - 结束绘制// context.closePath();context.strokeStyle = "rgba(255,0,0)";// context.lineWidth = -1;context.globalAlpha = 0context.stroke(); //描边context.clip();context.globalAlpha = 1},/** 将网络图片变成临时图片 */handleNetworkImgaeTransferTempImage(url) {return new Promise(resolve => {if (url.indexOf('http') === 0) {/* uni.downloadFile({url,success: res => {resolve(res.tempFilePath);}}); */uni.getImageInfo({src: url,success: (res)=> {resolve(res.path);}});// this.$ImgTask.imgTempFilePath['xxxxx']// this.$ImgTask.imgTempFilePath['xxxxx']=res.data;} else {resolve(url);}});}}};
</script><style scoped lang="scss">.canvas-c {height: 1200rpx;width:750rpx;margin: 0 auto;}
</style>
数据 canvasData
let imgUrlBg = 'https://img1.baidu.com/it/u=1426516032,2216512802&fm=253&fmt=auto&app=138&f=JPEG?w=730&h=405';let imgUrl1 = 'https://img2.baidu.com/it/u=3022038635,4257685721&fm=253&fmt=auto&app=138&f=PNG?w=500&h=500';let imgUrl2 = 'https://img0.baidu.com/it/u=4027294468,2844812981&fm=253&fmt=auto&app=138&f=JPEG?w=800&h=500';let imgUrl3 = 'https://img2.baidu.com/it/u=404036556,908612011&fm=253&fmt=auto&app=138&f=JPEG?w=480&h=800';let list = [
{type: 'image',attr: {image: imgUrlBg,x: 0,y: 0,width: 375,height: 800,radian_1: 0,radian_2:0,radian_3: 0,radian_4: 0}},// { type: 'rect', attr: { color: '#f0f', x: 0, y: 0, width: 375, height: 667, radian_1: 16, radian_2: 16, radian_3: 16, radian_4: 16 } },{type: 'rect',attr: {color: '#0ff',x: 0,y: 150,width: 375,height: 667,radian_1: 16,radian_2: 16,radian_3: 16,radian_4: 16}},{type: 'image',attr: {image: imgUrl2,x: 117.5,y: 80,width: 140,height: 140,radian_1: 16,radian_2: 16,radian_3: 24,radian_4: 16}},// { type: 'text', attr: { text: '略略大魔王', x: 100, y: 100, color: '#fff', size: 20, weight: '500', writingMode: 'tb' } },{type: 'text',attr: {text: '一马当先',color: '#000',align: 'center',x: 0,y: 260,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'bold',fontSize: 24,fontFamily: 'arial',fontH: 20,maxW: 375,rowCount: 1}},{type: 'text',attr: {text: '欢迎来到万马世界',color: '#000',align: 'center',x: 10,y: 290,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'normal',fontSize: 16,fontFamily: 'arial',fontH: 20,maxW: 375,rowCount: 1}},{type: 'text',attr: {text: '--成就奖励--',color: '#000',align: 'center',x: 10,y: 320,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'bold',fontSize: 14,fontFamily: 'arial',fontH: 20,maxW: 375,rowCount: 1}},// { type: 'rect', attr: { color: '#fff', x: 0, y: 340, width: 375, height: 120, radian_1: 16, radian_2: 16, radian_3: 16, radian_4: 16 } },{type: 'rect',attr: {color: '#fff',x: 0,y: 350,width: 375,height: 120,radian_1: 16,radian_2: 16,radian_3: 16,radian_4: 16}},{type: 'text',attr: {text: '--成就奖励--',color: '#000',align: 'center',x: 10,y: 320,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'bold',fontSize: 14,fontFamily: 'arial',fontH: 20,maxW: 375,rowCount: 1}},{type: 'image',attr: {image: imgUrl1,x: 10,y: 370,width: 80,height: 80,radian_1: 0,radian_2: 0,radian_3: 0,radian_4: 0}},{type: 'text',attr: {text: '用户的你昵称',color: '#000',align: 'left',x: 100,y: 390,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'normal',fontSize: 16,fontFamily: 'arial',fontH: 20,maxW: 300,rowCount: 1}},{type: 'text',attr: {text: '累计达成了89个成就',color: '#000',align: 'left',x: 100,y: 420,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'normal',fontSize: 16,fontFamily: 'arial',fontH: 20,maxW: 300,rowCount: 1}},{type: 'image',attr: {image: imgUrl3,x: 220,y: 500,width: 80,height: 80,radian_1: 5,radian_2: 5,radian_3: 5,radian_4: 5}},{type: 'text',attr: {text: '欢迎来到万马世界欢迎来到万马世界欢迎',color: '#f00',align: 'right',// left 左 center居中 right 右x: 20,y: 20,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'normal',fontSize: 16,fontFamily: 'arial',fontH: 20,maxW:200,rowCount: 3}},{type: 'text',attr: {text: '我是谁的谁啊999999999999999999999999999',color: '#f00',align: 'right',x: 0,//align 为right 时 x 表示靠右的距离y: 560,fontStyle: 'normal',fontVariant: 'normal',fontWeight: 'normal',fontSize: 16,fontFamily: 'arial',fontH: 20,maxW:100,rowCount: 3,}},
];
export default list