canvas画图及圆形的头像

最近在做一个项目,是在mobile网页上生成海报,海报中有用户圆形头像、图标、图片、文字等信息,相对来说也比较复杂的一个海报。

 

问题:

一、画圆形头像时就遇到了圆形头像时被切割。

问题描述:在用canvas画圆形头像时,向画布右侧移动时,右边半个圆被切割了。

原因:给头像的画布位置有限,移出了画布的区域自然就被切割了,一开始用的是fill()去填充,总是会被切割。

 改之前的代码:

img.onload = function () {
        let width = 1.6 * textPx;
        let height = 1.6 * textPx;
        let min = Math.min(width, height)

        let circle = {
          x: Math.floor(min / 2),
          y: Math.floor(min / 2),
          r: Math.floor(min / 2)
        }

        ctx.fillStyle = ctx.createPattern(img, 'no-repeat')
        ctx.beginPath()
        //开始路径画圆,剪切处理
        console.log("r:=====", circle.r)
        ctx.moveTo(0, 0)
        ctx.arc(circle.x, circle.y, circle.r, 0, Math.PI * 2);
        //恢复状态
        ctx.fill();//用这段代码去画圆形头像总是被切割

      }

改之后的代码:

img.onload = function () {
          console.log("timeout doing 小主播头像")
          ctx.save()
          let width = 118;
          let height = 118;
          let min = Math.min(width, height)

          let circle = {
            x: Math.floor(min / 2),
            y: Math.floor(min / 2),
            r: Math.floor(min / 2)
          }

          ctx.fillStyle = ctx.createPattern(img, 'no-repeat')
          ctx.beginPath()
          //开始路径画圆,剪切处理
          ctx.arc(circle.x + 129, circle.y + 87, circle.r, 0, Math.PI * 2, false);


          ctx.clip()
          ctx.drawImage(img, 129, 87, 2 * circle.r, 2 * circle.r)//改成这种方式可以画圆形头像,且不被切割
          

          console.log("dataURL00000:===", canvas.toDataURL('image/jpg'))
          canvas2imgWrap.style.display = 'block'
          _this.dataImgSrc = canvas.toDataURL('image/png')
          if (clientWidth > 375) {
            dataImgWrap.style.marginLeft = 40 + 'px'
          }

          dataImgWrap.setAttribute('width', canvasWidth + 'px');
          dataImgWrap.setAttribute('height', canvasHeight + 'px');

          canvas2imgWrap.setAttribute('width', '100%');
          canvas2imgWrap.setAttribute('height', '100%');
          canvas.style.display = 'none'

        }

二、海报背景图总是会覆盖在文字上。

问题描述:因为图片加载需要时间,文字所需的时间比图片短,导致文字先画在了画布上,背景图后画,这就导致了背景图盖住了文字和其它的图片,导致只能看到部分绘画的图片。

解决方法是写了一个回调,在背景图画完之后再画其它的内容。因为其它内容需要覆盖在背景图片上。

代码如下:

createCanvas() {
      let _this = this;
      let canvas = document.getElementById("canvas_wrap")
      let dataImgWrap = document.getElementById("dataImgWrap")
      let canvas2imgWrap = document.getElementById("canvas2img")
      canvas.style.display = "block"
      let ctx = canvas.getContext("2d");

      let clientWidth = document.documentElement.clientWidth;
      let textPx = clientWidth * 180 / 750
      //根据设计图中的canvas画布的占比进行设置
      let canvasWidth = 375;
      let canvasHeight = 636
      console.log("canvasWidth:", canvasWidth, 'canvasHeight:===', canvasHeight)
      canvas.setAttribute('width', canvasWidth + 'px');
      canvas.setAttribute('height', canvasHeight + 'px');
      /* ctx.fillStyle = '#fff';
      ctx.fillRect(0, 0, canvasWidth, canvasHeight); */

      //canvas背景图
      function drawBg(callback) {
        let bgImg = new Image();
        bgImg.onload = function () {
          // resolve(bgImg)
          let bg = ctx.createPattern(bgImg, 'no-repeat');
          ctx.fillStyle = bg;
          ctx.fillRect(0, 0, canvasWidth, canvasHeight)

          console.log("timeout forward")
        }
        bgImg.src = canvasBg;
        setTimeout(function () {
          (callback && typeof (callback) === "function") && callback();
        }, 1500)
        console.log("timeout after")
      }

      drawBg(function () {
        console.log("timeout doing")

        let img = new Image();
        img.setAttribute('crossOrigin', 'anonymous');
        // img.src = _this.detailData.anchorHeadImg + '?' + (+new Date())
        img.src = localAvatar;  //为什么用本地图片后canvas背景图不显示???
        img.onload = function () {
          console.log("timeout doing 小主播头像")
          ctx.save()
          let width = 118;
          let height = 118;
          let min = Math.min(width, height)

          let circle = {
            x: Math.floor(min / 2),
            y: Math.floor(min / 2),
            r: Math.floor(min / 2)
          }

          ctx.fillStyle = ctx.createPattern(img, 'no-repeat')
          ctx.beginPath()
          //开始路径画圆,剪切处理
          console.log("r:=====", circle.r)
          ctx.arc(circle.x + 129, circle.y + 87, circle.r, 0, Math.PI * 2, false);


          ctx.clip()
          ctx.drawImage(img, 129, 87, 2 * circle.r, 2 * circle.r)
          /* ctx.fillStyle = "#fff"
          ctx.arc(circle.x + 110, circle.y + 90, circle.r + 10, 0, Math.PI * 2, false); */

          console.log("dataURL00000:===", canvas.toDataURL('image/jpg'))
          canvas2imgWrap.style.display = 'block'
          _this.dataImgSrc = canvas.toDataURL('image/png')
          if (clientWidth > 375) {
            dataImgWrap.style.marginLeft = 40 + 'px'
            // canvas2imgWrap.style.marginLeft = 7 + 'px'
          }

          dataImgWrap.setAttribute('width', canvasWidth + 'px');
          dataImgWrap.setAttribute('height', canvasHeight + 'px');

          canvas2imgWrap.setAttribute('width', '100%');
          canvas2imgWrap.setAttribute('height', '100%');
          canvas.style.display = 'none'

        }

        //作品数
        ctx.font = "bold 16px microsoft";
        ctx.fillStyle = "#333";
        ctx.fillText(_this.detailData.workCount + "个", 298, 40)
        ctx.font = "16px microsoft";
        ctx.fillStyle = "#666";
        ctx.fillText("作品数", 298, 65)


        ctx.font = "bold 16px microsoft";
        ctx.fillStyle = "#333";
        ctx.fillText(_this.detailData.workReadAmountCount, 298, 90)
        ctx.font = "16px microsoft";
        ctx.fillStyle = "#666";
        ctx.fillText("人气", 298, 115)

        // ctx.font = 0.4 * textPx;
        ctx.font = "bold 20px microsoft";
        ctx.fillStyle = "#333";
        ctx.fillText("小少年", 157, 250)

        //认证小主播
        let authImg = new Image();
        authImg.src = _this.detailData.anchorIsAuthed === 1 ? posterAuth : '';
        authImg.onload = function () {

          ctx.drawImage(authImg, 137, 260, 100, 24)
          console.log("timeout doing 认证小主播")
        }

        //小主播简介
        ctx.font = "12px microsoft"
        ctx.fillStyle = "#fff";
        // ctx.fillText(_this.detailData.anchorItdc, 165, 100)
        let t = "这里是小主播简介,这里是小主播。简介这里是小主播简介这里是,真的是这样的吗?哈哈哈哈!!小主播简介这里是小主播简介这里是小主播简介这里是小主播简介这里是小主播简介这里是小主播简介这里是小主播简介这里是小主播简介"
        // let t = _this.detailData.anchorItdc
        _this.drawText(ctx, t, 30, 330, 330)



        //二维码
        // console.log("url:=======", this.$nuxt.$route.path)
        let erweimaImg = new Image()
        erweimaImg.setAttribute('crossOrigin', 'anonymous');
        let erweima_URL = config.erweima_url + _this.$nuxt.$route.path

        erweimaImg.onload = function () {
          let erweimaPhoto = document.getElementById("canvasImg")
          ctx.drawImage(erweimaPhoto, 37, 505, 68, 68);

          // console.log("dataURL11111:===", canvas.toDataURL('image/png'))
        }

        console.log("erweimaurl:=======", erweima_URL)

        erweimaImg.src = erweima_URL + '?' + (+new Date())


        //小主播养成计划图片
        let titleImg = new Image();
        titleImg.src = posterTitle;
        titleImg.onload = function () {

          ctx.drawImage(titleImg, 125, 517, 170, 17)
          console.log("timeout doing 养成计划")
        }

        ctx.font = "14px microsoft";
        ctx.fillStyle = "#333";
        ctx.fillText("长按识别二维码", 125, 550)

        //中少网图片
        let logoImg = new Image();
        logoImg.src = posterLogo;
        logoImg.onload = function () {

          ctx.drawImage(logoImg, 97, 610, 180, 21)
          console.log("timeout doing 中少网logo")
        }
      })
    },
    drawText(context, t, x, y, w) {

      var chr = t.split("");
      var temp = "";
      var row = [];

      context.font = "14px microsoft";
      context.fillStyle = "#fff";
      context.textBaseline = "middle";

      for (var a = 0; a < chr.length; a++) {

        if (context.measureText(temp).width < w && context.measureText(temp + (chr[a])).width <= w) {
          temp += chr[a];
        }//context.measureText(text).width  测量文本text的宽度
        else {
          row.push(temp);
          temp = chr[a];
        }
      }
      row.push(temp);

      /* for (var b = 0; b < row.length; b++) {
        context.fillText(row[b], x, y + (b + 1) * 24);//字体20,间隔24。类似行高
      } */

      // 只显示2行,加...
      for (var b = 0; b < 4; b++) {
        var str = row[b];
        if (b == 3) {
          str = str.substring(0, str.length - 1) + '...';
        }
        context.fillText(str, x, y + (b + 1) * 24);
      }
    },

之所以没用promise,是因为本人的promise不是特别熟,看来必须把promise给学精了,加油!!!!

最终效果:

 

参考链接:

https://blog.csdn.net/u012011360/article/details/80169529

https://blog.csdn.net/fxss5201/article/details/79691923 

https://www.cnblogs.com/padding1015/p/9717845.html

https://www.w3school.com.cn/tags/html_ref_canvas.asp

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值