uniapp好用的canvas插件分享

本文介绍了在uniapp开发中,一个实用的canvas处理工具库canvasUtils.js,通过示例展示了如何利用这个插件进行图形绘制、图像处理等操作,帮助开发者提升canvas开发效率。
摘要由CSDN通过智能技术生成

canvasUtils.js

/**
 * 绘制矩形
 * 参数:cxt、x坐标、y坐标、宽度、高度、圆角、颜色
 */
function fillRoundRect(cxt, x, y, width, height, radius, fillColor) {
    console.log(cxt,'fillRoundRect')
    //圆的直径必然要小于矩形的宽高
    if (2 * radius > width || 2 * radius > height) {
        return false;
    }
    cxt.save();
    cxt.translate(x, y);
    //绘制圆角矩形的各个边
    drawRoundRectPath(cxt, width, height, radius);
    cxt.fillStyle = fillColor || '#000'; //若是给定了值就用给定的值否则给予默认值
    cxt.fill();
    cxt.restore();
}
// 绘制矩形各个边过程
function drawRoundRectPath(cxt, width, height, radius) {
    cxt.beginPath(0);
    //从右下角顺时针绘制,弧度从0到1/2PI
    cxt.arc(width - radius, height - radius, radius, 0, Math.PI / 2);
    //矩形下边线
    cxt.lineTo(radius, height);
    //左下角圆弧,弧度从1/2PI到PI
    cxt.arc(radius, height - radius, radius, Math.PI / 2, Math.PI);
    //矩形左边线
    cxt.lineTo(0, radius);
    //左上角圆弧,弧度从PI到3/2PI
    cxt.arc(radius, radius, radius, Math.PI, (Math.PI * 3) / 2);
    //上边线
    cxt.lineTo(width - radius, 0);
    //右上角圆弧
    cxt.arc(width - radius, radius, radius, (Math.PI * 3) / 2, Math.PI * 2);
    //右边线
    cxt.lineTo(width, height - radius);
    cxt.closePath();
}
/**
 * 绘制矩形边框
 * 参数:cxt、x坐标、y坐标、宽度、高度、圆角、border颜色
 */
function roundRectBorder(cxt, x, y, w, h, r,borderWidth) {
    if (w < 2 * r) r = w / 2;
    if (h < 2 * r) r = h / 2;
    cxt.beginPath();
    cxt.moveTo(x+r, y);
    cxt.arcTo(x+w, y, x+w, y+h, r);
    cxt.arcTo(x+w, y+h, x, y+h, r);
    cxt.arcTo(x, y+h, x, y, r);
    cxt.arcTo(x, y, x+w, y, r);
    cxt.closePath();
    cxt.lineWidth = borderWidth
}
//加载图片
function getImageInfo(image) {
    return new Promise((req, rj) => {
        // #ifndef APP-PLUS
        uni.getImageInfo({
            src: image,
            success: function(res) {
                req(res)
            },
        });
        // #endif
        // #ifdef APP-PLUS
        if(uni.getSystemInfoSync().platform == 'ios'){
            uni.downloadFile({
            	url: image,
            	success: (res) => {
                    res.path = res.tempFilePath
                    req(res)
                },
            })
        }else{
            uni.getImageInfo({
                src: image,
                success: function(res) {
                    req(res)
                },
            });
        }
        // #endif
    })
}

/**
 * 绘制圆形头像
 * 参数:cxt、图标路径path、x坐标、y坐标、宽度、高度
 */
function drawCircular(ctx, url, x, y, width, height) {
    //画圆形头像
    var avatarurl_width = width;
    var avatarurl_heigth = height;
    var avatarurl_x = x;
    var avatarurl_y = y;
    ctx.save();
    ctx.beginPath();
    ctx.arc(avatarurl_width / 2 + avatarurl_x, avatarurl_heigth / 2 + avatarurl_y, avatarurl_width / 2, 0, Math.PI * 2, false);
    ctx.clip();
    ctx.drawImage(url, avatarurl_x, avatarurl_y, avatarurl_width, avatarurl_heigth);
    ctx.restore();
}

/*
 * 绘制图片cover
 * t:cxt;
 * e:图片属性(通过getImageInfo获取)
 * s:x坐标
 * o:y坐标
 * i:绘制图片宽度
 * a:绘制图片高度
 */
function drawImgCover(t, e, s, o, i, a) {
    console.log(e,'drawImgCover')
    if (e.width / e.height >= i / a) {
        var r = e.height,
            n = Math.ceil(i / a * r);
        t.drawImage(e.path, (e.width - n) / 2, 0, n, e.height, s, o, i, a)
    } else {
        var c = e.width,
            l = Math.ceil(a / i * c);
        t.drawImage(e.path, 0, (e.height - l) / 2, e.width, l, s, o, i, a)
    }
}

/*
 * 文本自定义换行
 * family = " 'PingFang SC',tahoma,arial,'helvetica neue','hiragino sans gb','microsoft yahei',sans-serif";
 * var options = {
				font:"22px" + family,  字体大小
				ctx:ctx,          uni.createCanvasContext('firstCanvas')
				word:"文字",      文字
				maxWidth:750,     最大宽度
				maxLine:2,        最大行数
				x:100,            x坐标
				y:100,            y坐标
				l_h:40            行高
			}
 * callback 自定义函数
 */
function dealWords(options, callback) {
    options.ctx.font = options.font; //设置字体
    callback && callback();
    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) * options.l_h); //(j+1)*18这是每一行的高度        
                    } else {
                        options.ctx.fillText(nowStr.slice(0, m), options.x, options.y + (j + 1) * options.l_h);
                    }
                    endPos += m; //下次截断点
                    break;
                }
            }
        } else { //如果当前的字符串宽度小于最大宽度就直接输出
            options.ctx.fillText(nowStr.slice(0), options.x, options.y + (j + 1) * options.l_h);
        }
    }
}
/*
 * 绘制圆角按钮
 * ctx:createCanvasContext
 * color:背景颜色;
 * x:x坐标
 * y:y坐标
 * width:宽
 * height:高
 * radius:圆角
 * text:文字
 * fontColor:文字颜色
 * textAlign: left/center/right
 */
function drawButton(ctx, color, x, y, width, height, radius, text, fontColor, textAlign) { 
    //分为4条直线4个圆角绘制
    ctx.beginPath();
    ctx.fillStyle = color;
    ctx.moveTo(x + radius, y);
    ctx.lineTo(x + width - radius, y);
    ctx.arc(x + width - radius, y + radius, radius, Math.PI * 3 / 2, Math.PI * 2);
    ctx.lineTo(x + width, y + height - radius);
    ctx.arc(x + width - radius, y + height - radius, radius, Math.PI, Math.PI / 2);
    ctx.lineTo(x + radius, y + height);
    ctx.arc(x + radius, y + height - radius, radius, Math.PI / 2, Math.PI);
    ctx.lineTo(x, y + radius);
    ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 3 / 2);
    ctx.fill();
    ctx.closePath();

    ctx.beginPath();
    ctx.fillStyle = fontColor;
    // ctx.font = 'normal bold 12px sans-serif';
    ctx.setTextAlign(textAlign)
    ctx.textBaseline = "middle";
    ctx.fillText(text, x + width / 2, y + height / 2);
}

export default {
    fillRoundRect:fillRoundRect, //绘制矩形
    roundRectBorder:roundRectBorder,//绘制矩形+边框
    getImageInfo:getImageInfo, //加载图片
    drawCircular:drawCircular, //绘制圆形头像
    drawImgCover:drawImgCover, //绘制图片cover
    dealWords:dealWords, //文本自定义换行
    drawButton:drawButton, //绘制圆角按钮
}

示例

 <canvas canvas-id="myctx" :style="{ width: posterObj.width + 'px', height: posterObj.height + 'px'}" disable-scroll></canvas>
  import canvasUtils from '@/utils/canvasUtils.js'; // 加载万能绘制方法
data() {
return {
 posterObj: {
          show: false,
          height: 500,
          width: 380,
          qcCode:""
        },
        }
     }
methods:{
     savePoster() {
        uni.canvasToTempFilePath({
          canvasId: 'myctx',
          success: (res) =>{
            console.log(res.tempFilePath)
            uni.saveImageToPhotosAlbum({//保存图片到系统相册。
            	filePath: res.tempFilePath,//图片文件路径
            	success: function() {
            		uni.showToast({
            			title: '海报保存成功',
            			icon: 'none',
            		});
            	},
            	fail: function(e) {
            		console.log(e);
            		uni.showToast({
            			title: '海报保存失败',
            			icon: 'none',
            		});
            	}
            });
          }
        })
      },
      async createPosterObj() {
        const ctx = uni.createCanvasContext("myctx", this)
        let family = " 'PingFang SC',tahoma,arial,'helvetica neue','hiragino sans gb','microsoft yahei',sans-serif";
        console.log("item", this.item);
        canvasUtils.fillRoundRect(ctx, 0, 0, this.posterObj.width, this.posterObj.height, 5, "#db5e62")
        canvasUtils.fillRoundRect(ctx, 15, 15, this.posterObj.width - 30, this.posterObj.height - 140, 5, "#FFFFFF")


        ctx.setFillStyle('#db5e62')
        ctx.font = "24px" + family
        ctx.fillText(this.item.categoryName, 30, 60)

        let avatarUrl = await canvasUtils.getImageInfo(this.$store.getters.userInfo.avatarUrl)

        canvasUtils.drawCircular(ctx, avatarUrl.path, this.posterObj.width - 100, 30, 60, 60)


        ctx.setFillStyle('#000000')
        var options = {
          font: "15px" + family, //设置字体
          ctx: ctx,
          word: this.$store.getters.userInfo.nickName, //文本
          maxWidth: 100, //最大宽度
          maxLine: 1, //最大行数--超出省略
          x: this.posterObj.width - 120, //x坐标
          y: 100, //y坐标
          l_h: 10 //行高
        }
        canvasUtils.dealWords(options)

        ctx.setFillStyle('#4c4c4c')
        ctx.font = "12px" + family
        ctx.fillText(this.item.createTime, 30, 90)

        ctx.setFillStyle('#ccb45a')
        ctx.font = "16px" + family
        ctx.fillText("标题:", 30, 130)

        ctx.fillText("内容:", 30, 160)
        ctx.setFillStyle('#000000')
        options = {
          font: "16px" + family, //设置字体
          ctx: ctx,
          word: this.item.postName, //文本
          maxWidth: 200, //最大宽度
          maxLine: 1, //最大行数--超出省略
          x: 80, //x坐标
          y: 120, //y坐标
          l_h: 10 //行高
        }
        canvasUtils.dealWords(options)

        options = {
          font: "17px" + family, //设置字体
          ctx: ctx,
          word: this.item.content, //文本
          maxWidth: 200, //最大宽度
          maxLine: 6, //最大行数--超出省略
          x: 30, //x坐标
          y: 180, //y坐标
          l_h: 10 //行高
        }
        canvasUtils.dealWords(options)
        if (this.item.imgUrls && this.item.imgUrls.length > 0) {
          let img = await canvasUtils.getImageInfo(this.item.imgUrls[0])

          canvasUtils.drawImgCover(ctx, img, 30, this.posterObj.height - 230, 100, 100)
        }
        let logo = await canvasUtils.getImageInfo(
          "xxxx.png")

        canvasUtils.drawImgCover(ctx, logo, 20, this.posterObj.height - 120, 80, 80)

        let qrcode = await canvasUtils.getImageInfo(this.posterObj.qcCode)
        canvasUtils.drawImgCover(ctx, qrcode, this.posterObj.width - 100, this.posterObj.height - 120, 80, 80)


        ctx.setFillStyle('#ffffff')
        ctx.font = "14px" + family
        ctx.fillText('xxx ', 30, this.posterObj.height - 20)
        ctx.fillText('长按查看详情 ', this.posterObj.width - 100, this.posterObj.height - 20)
        ctx.draw()
      },
      getQrCode() {
        let path = this.path
        createWxMaCode({
           page:path
        }).then(res=>{
          this.posterObj.qcCode = res
          console.log(res);

          this.createPosterObj()
        })

      },
      doCreateQr() {
        if (!this.$store.getters.userInfo) {
          uni.$u.toast('请先登录')
          return
        }
        this.posterObj.show = true
        if(this.posterObj.qcCode) {
          this.createPosterObj()
        } else {
         this.getQrCode()
        }

      },
  
}
  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

这次最后一次熬夜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值