- <view>
- <canvas canvas-id="canvas" class="canvas-c">canvas>
-
- view>
-
- <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 = rowCut
- let 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 = 0
- context.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>
- 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