基于UNI.app的小程序端的canvas绘图,绘制海报--图片更改为圆形,canvas对文字段落(长文本)进行处理

**

基于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,不至于前端~
在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值