欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

小程序,js的canvas绘制方法封装

程序员文章站 2022-05-30 09:26:17
...

小程序绘制

1.wxml结构
<view id='canvas_box' class='canvas_box'>
	<canvas canvas-id="canvas_cover" class="canvas_cover" ></canvas>
</view>
2. //引入base64.js  
   const base64 = require('../../utils/base64.js')
   //创建base64.js文件,复制下面代码,保存
    const fsm = wx.getFileSystemManager();
	function base64src(base64data, cb) {
	  const [, format, bodyData] = /data:image\/(\w+);base64,(.*)/.exec(base64data) || [];
	  if (!format) {
	    return (new Error('ERROR_BASE64SRC_PARSE'));
	  }
	  const filePath = `${wx.env.USER_DATA_PATH}/${new Date().getTime()}.${format}`;
	  const buffer = wx.base64ToArrayBuffer(bodyData);
	  fsm.writeFile({
	    filePath,
	    data: buffer,
	    encoding: 'binary',
	    success() {
	      setTimeout(() => {
	        fsm.removeSavedFile({
	          filePath
	        })
	      },100);
	      cb(filePath);
	    },
	    fail() {
	      return (new Error('ERROR_BASE64SRC_WRITE'));
	    },
	  });
	};

export { base64src };

3.//封装方法
buildBossImg: function (download) {
      let self = this;
      new Promise((resolve,reject)=>{ 
        // 排行数据 
        let self = this;
        let value = wx.getStorageSync('userType'); // !!value?1:2 3-18都展示所有
        statisticsService.getStatisticalRank({
          businessId: self.data.businessId,
          taskId: self.data.taskId,
          sort: 1,
          type: 0,
          pageIndex: 1,
          pageSize: 3
        }, (err, res) => {
          res.data.employeeList.forEach((item) => { //字数长度处理
            if (item.name){
              item.name = item.name.length > 4 ? item.name.substring(0, 4) : item.name;
            }
            if (item.nickname){
              item.nickname = item.nickname.length > 4 ? item.nickname.substring(0, 4) : item.nickname;
            }
          })
          res.data.customerList.forEach((item) => {
            if (item.nickname){
              item.nickname = item.nickname.length > 4 ? item.nickname.substring(0, 4) : item.nickname
            }
          })
          self.setData({
            rankList: res.data
          })
          resolve(self.data.rankList)
        })
      }).then((result)=>{
        wx.createSelectorQuery().in(this).select('.canvas_box').fields({
          size: true
        }, (box) => {
          console.log('开始绘图',box);
          let rate = box.width / 580,
            employeeList = result.employeeList,
            customerList = result.customerList,
            paintData = self.data.paintData;
          let
            qrcodeInfo = {
              source: null,
              size: {
                width: 75,
                height: 75
              }
            };
          const ctx = wx.createCanvasContext('canvas_cover', this);
          //绘制文字超出打点
          function fillText(ctx, str, fontSize, color, x, y) {
            ctx.setTextBaseline('top');
            ctx.setFontSize(fontSize);
            ctx.setFillStyle(color);
            // ctx.fillText(str, x, y);

            let maxWidth = box.width - x,
              maxLength = Math.floor(maxWidth / fontSize);

            if (str.length <= maxLength) {
              ctx.fillText(str, x, y, maxWidth);
            } else {
              ctx.fillText(str.substring(0, maxLength - 3) + '...', x, y, maxWidth);
            }
          }

          Promise.all([
            new Promise((resolve, reject) => {
              //图片转换
              wx.getImageInfo({
                src: 'https://xxx.cn/beta/00000000-0000-0000-0000-000000000000/KMA/miniapp/canvas-bg.png',
                success: resolve,
                fail: reject
              })
              // resolve('/images/report_img2.png');
            }),
            new Promise((resolve, reject) => { //转发标识接口
              activityService.getforwardKey(option, (err, res) => {
                if (!!res && res.status == 0) {
                  self.data.myforwardKey = res.data.forwardKey;
                  self.data.rootUserId = res.data.rootUserId;
                }
                resolve(null);
              });
            }).then((res)=>{
              return new Promise((resolve,reject)=>{  //活动详情接口
                activityService.activityInfo(self.data.taskId, (err, res) => {
                  if (err) return self.errMessage(err);
                  if (res.status !== 0) return self.errMessage(res.message);
                  self.setData({
                    h5Info: res.data,
                    type: res.data.manuscriptType
                  })
                  resolve(res.data)
                });
              })
            }).then((result)=>{
               return new Promise((resolve,reject)=>{  //绘制二维码
                 var id = self.data.taskId;
                 let _url = result.url;
                 _url = self.data.h5Info.manuscriptType == 3 ? _url.replace('//', '$').split('/')[0].replace('$', '//') + '/article?id=' + self.data.h5Info.relationId : _url;
                 console.log("转发id", self.data.myforwardKey, "url", `${_url}?rootUserId=${self.data.rootUserId}&forwardKey=${self.data.myforwardKey}`)
                 //请求获取二维码接口
                 activityService.creatQrcode(JSON.stringify({
                   "width": 430,
                   "type": 'link',
                   "id": id,
                   "src": `${_url}?rootUserId=${self.data.rootUserId}&forwardKey=${self.data.myforwardKey}`
                 }), function (err, res) {
                   if (res.status == 0) {
                     base64.base64src(res.data.file, res => {
                       console.log(res) // 返回图片地址,直接赋值到image标签即可
                       wx.getImageInfo({
                         src: res,
                         success: resolve,
                         fail: reject
                       })
                     });
                   }
                 })
               })
            })

          ]).then((result) => {
            qrcodeInfo.source = result[1];
            ctx.drawImage(result[0].path, 0, 0, 580 * rate, 534 * rate); //绘制背景
            // 绘制小程序码
            ctx.drawImage(qrcodeInfo.source.path, 21 * rate, 130 * rate, qrcodeInfo.size.width, qrcodeInfo.size.width);
            fillText(ctx, '扫码参加本活动', 20 * rate, '#B1BFCD', 25 * rate, 280 * rate);
            fillText(ctx, '累计总获客', 20 * rate, '#3C4A55', 243 * rate, 31 * rate);
            ctx.setFontSize(40 * rate);
            let target_left = ctx.measureText(String(utils.convertJoinCount(paintData.userCount))).width / 2,
              textWidth = target_left.toFixed(1);
            console.log("字体宽度", target_left, "222", textWidth, "计算", (box.width / 2) - textWidth)
            fillText(ctx, `${utils.convertJoinCount(paintData.userCount)}`, 40 * rate, '#24D0C6', (box.width / 2) - textWidth, 56 * rate);

            fillText(ctx, '总投入', 20 * rate, '#B1BFCD', 190 * rate, 150 * rate);
            fillText(ctx, `¥${utils.convertJoinCount(paintData.totalInvestment)}`, 20 * rate, '#FA766B', 290 * rate, 150 * rate);
            fillText(ctx, '总转发', 20 * rate, '#B1BFCD', 395 * rate, 150 * rate);
            fillText(ctx, `${utils.convertJoinCount(paintData.totalForwardCount)}`, 20 * rate, 'rgba(36,208,198,1)', 490 * rate, 150 * rate);

            fillText(ctx, '总浏览', 20 * rate, '#B1BFCD', 190 * rate, 195 * rate);
            fillText(ctx, `${utils.convertJoinCount(paintData.totalBrowseCount)}`, 20 * rate, 'rgba(36,208,198,1)', 310 * rate, 195 * rate);
            fillText(ctx, '总客户', 20 * rate, '#B1BFCD', 395 * rate, 195 * rate);
            fillText(ctx, `${utils.convertJoinCount(paintData.totalUserCount)}`, 20 * rate, 'rgba(36,208,198,1)', 490 * rate, 195 * rate);

            fillText(ctx, '总浏览时长', 20 * rate, '#B1BFCD', 190 * rate, 240 * rate);
            fillText(ctx, `${(paintData.totalAccessTimeCount)}min`, 20 * rate, 'rgba(36,208,198,1)', 300 * rate, 240 * rate);
            fillText(ctx, '总预约', 20 * rate, '#B1BFCD', 395 * rate, 240 * rate);
            fillText(ctx, `${utils.convertJoinCount(paintData.totalServiceCount)}`, 20 * rate, 'rgba(36,208,198,1)', 490 * rate, 240 * rate);

            fillText(ctx, '员工排行', 21 * rate, '#3C4A55', 40 * rate, 330 * rate);
            fillText(ctx, '客户排行', 21 * rate, '#3C4A55', 310 * rate, 330 * rate);
            // 员工排行
            fillText(ctx, `${!!employeeList[0] ? (employeeList[0].name || employeeList[0].nickname) : '暂无'}`, 21 * rate, '#3C4A55', 95 * rate, 385 * rate);
            fillText(ctx, `${!!employeeList[0] ? utils.convertJoinCount(employeeList[0].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 195 * rate, 385 * rate);

            fillText(ctx, `${!!employeeList[1] ? (employeeList[1].name || employeeList[1].nickname) : '暂无'}`, 21 * rate, '#3C4A55', 95 * rate, 432 * rate);
            fillText(ctx, `${!!employeeList[1] ? utils.convertJoinCount(employeeList[1].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 195 * rate, 432 * rate);

            fillText(ctx, `${!!employeeList[2] ? (employeeList[2].name || employeeList[2].nickname) : '暂无'}`, 21 * rate, '#3C4A55', 95 * rate, 479 * rate);
            fillText(ctx, `${!!employeeList[2] ? utils.convertJoinCount(employeeList[2].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 195 * rate, 479 * rate);
            // 客户排行
            fillText(ctx, `${!!customerList[0] ? customerList[0].nickname : '暂无'}`, 21 * rate, '#3C4A55', 360 * rate, 385 * rate);
            fillText(ctx, `${!!customerList[0] ? utils.convertJoinCount(customerList[0].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 465 * rate, 385 * rate);

            fillText(ctx, `${!!customerList[1] ? customerList[1].nickname : '暂无'}`, 21 * rate, '#3C4A55', 360 * rate, 434 * rate);
            fillText(ctx, `${!!customerList[1] ? utils.convertJoinCount(customerList[1].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 465 * rate, 434 * rate);

            fillText(ctx, `${!!customerList[2] ? customerList[2].nickname : '暂无'}`, 21 * rate, '#3C4A55', 360 * rate, 481 * rate);
            fillText(ctx, `${!!customerList[2] ? utils.convertJoinCount(customerList[2].marketingForce) + '分' : '0分'}`, 21 * rate, '#F68411', 465 * rate, 481 * rate);

            ctx.draw(true, setTimeout(() => {
              self.saveImage();
            }, 1000));
          })
        }).exec();
      })
      
    },
    //canvas导出为图片
    saveImage: function() {
      let self = this;
      wx.createSelectorQuery().in(this).select('.canvas_box').fields({
        size: true
      }, (box) => {
        wx.canvasToTempFilePath({
          fileType: "png",
          destWidth: box.width * 6,
          destHeight: box.height * 6,
          canvasId: 'canvas_cover',
          success: (res) => {
            self.data.imgSrc = res.tempFilePath;
            wx.hideLoading();
          }
        }, self)

      }).exec();
    },
    // 下载图片
    downloadImg: function() {
      let self = this;
      wx.showLoading({
        title: '图片下载中'
      });
      wx.saveImageToPhotosAlbum({
        filePath: self.data.imgSrc,
        success: (res) => {
          self.setData({
            coverSaveStatus: 1 
          });
          wx.hideLoading();
          wx.showToast({
            title: "图片下载成功"
          })
        },
        fail: (err) => {
          wx.hideLoading();
          utils.toast.fail({
            title: "图片下载失败"
          });
          console.error("图片下载失败", err);
          self.setData({
            coverSaveStatus: 2
          });
        }
      }, self);
    }

效果
小程序,js的canvas绘制方法封装
js绘制海报

function IEVersion() {
	//取得浏览器的userAgent字符串
	var userAgent = navigator.userAgent;
	//判断是否IE浏览器
	var isIE = userAgent.indexOf("compatible") > -1 && userAgent.indexOf("MSIE") > -1;
	if (isIE) {
		var reIE = new RegExp("MSIE (\\d+\\.\\d+);");
		reIE.test(userAgent);
		var fIEVersion = parseFloat(RegExp["$1"]);
		if (fIEVersion < 10 || !isSupportPlaceholder()) {
			return true;
		}
	} else {
		return false;
	}
}

let createPoster = (json, callback) => {
	if(IEVersion()){
		callback('');
		return false;
	} 
	let posterWrap = $('<div></div>');
	let str = `<canvas id="poster_canvas" width="320" height="615" style="position:absolute;top:0;left:0;z-index:-10;background-color:red;"></canvas><div id="poster_qrcode"></div>`;
	posterWrap.html(str);
	$("body").append(posterWrap);

	let canvas = posterWrap.find('#poster_canvas')[0];
	let ctx = canvas.getContext('2d');

	let img = new Image();
	img.setAttribute('crossOrigin', 'anonymous');
	img.imageSmoothingEnabled = false; //抗锯齿
	img.src = json.cover;

	img.onload = (a)=> {
		var timer = setInterval(function(){
			if(img.complete) {
				let cover_H = (img.height / img.width * 375);
				// ctx.drawImage(img,0,0,250 * 1.5,cover_H);
				// clearInterval(timer);
				let ratio = window.devicePixelRatio || 1,  //获取设备像素比
					oldWidth = canvas.width,
				    oldHeight = canvas.height;
				canvas.width = oldWidth * ratio;
				canvas.height = oldHeight * ratio;

				canvas.style.width = oldWidth + 'px';
				canvas.style.height = oldHeight + 'px';
				ctx.scale(ratio, ratio);
				if(img.width > 320){ //大于默认尺寸则进行裁剪
					ctx.drawImage(img,img.width/2 - 100, 0, img.width, img.height,0,0,img.width, img.height);
				}else{
					ctx.drawImage(img,0,0,img.width, img.height);					
				}
				clearInterval(timer);

				ctx.rect(0,335 * 1.5,250 * 1.5,80 * 1.5);
				ctx.fillStyle="#ffffff";
				ctx.fill();
			
				new QRCode(posterWrap.find('#poster_qrcode')[0], {
					text: '自定义',
					width: 60*1.5,
					height: 60*1.5,
					colorDark: "#000000",
					colorLight: "#ffffff",
					correctLevel: QRCode.CorrectLevel.H
				});
				
				// 绘制标题、描述
				ctx.font = "400 16px Arial"; //设置字体
				ctx.textBaseline = 'top'; //在绘制文本时使用的当前文本基线
				ctx.fillStyle="#000000";
				if(ctx.measureText(json.name).width > 210 ){
					let maxLength = Math.floor(210 / ctx.measureText('啊').width);
					json.name = json.name.substring(0, maxLength-2) + '...';
				}
				ctx.fillText (json.name, 13 * 1.5, 355 * 1.5, 150 * 1.5);
				
				ctx.font = "400 14px Arial"; //设置字体
				ctx.textBaseline = 'top'; //在绘制文本时使用的当前文本基线
				ctx.fillStyle="#999999";
				ctx.fillText ('长按识别二维码有惊喜', 12 * 1.5, 375 * 1.5, 150 * 1.5);
				
				//绘制二维码
				posterWrap.find('#poster_qrcode').find('img').on('load', function(){
					ctx.drawImage(posterWrap.find('#poster_qrcode').find('img')[0],145 * 1.5,343 * 1.5,60 * 1.5,60 * 1.5);

					api.request("uploadImageForBase64", { base64Files: [{ content: canvas.toDataURL('image/png') }] }, result => {
						posterWrap.remove();
						callback(result.status == 0 ? result.data[0].file : "");
					});
				})
			}
		},50);
	}	
		
}