微信小程序之canvas

1,747 阅读2分钟

学习微信canvas笔记,封装了一些实用小方法,希望能帮到大家。

初始化canvas

initCanvas(){
  let ctx = wx.createCanvasContext('canvas-id',this);  //组件内需要传this
  this.data.ctx = ctx;
  /*  
   * 绘制操作/引入函数
  */
  console.log('初始化canvas');
  ctx.draw();
},

移动端自适应 (iphone7设计图 750*1334)

rem(px){
    let width = wx.getSystemInfoSync().windowWidth;
    let rem = width/375 * px;
    return rem;
}

绘制矩形(是否填充)

/*  
 * opt.x / opt.y : x,y是矩形的起点;
 * opt.w / opt.h : w,h是矩形的宽高;
 * opt.color : 颜色 -- #ffffff
 * opt.opacity : 透明度 -- 1
 * opt.fill : 是否填充 -- false
*/
drawRect(opt={}){
      opt.color = opt.color || '#ffffff';
      let ctx = this.data.ctx; 
      ctx.save();
      ctx.setGlobalAlpha(opt.opacity || 1); //设置透明度
      ctx.rect(opt.x,opt.y,opt.w,opt.h);
      if( opt.fill ){
        ctx.setFillStyle( opt.color );
        ctx.fill()
      }else{
        ctx.setStrokeStyle( opt.color )
        ctx.stroke()
      }
      ctx.restore(); //恢复之前保存的绘图上下文
},

绘制换行文字

/*  
 * opt : Object
 * opt.text / opt.x / opt.y 绘制文字的内容和坐标
 * opt.align : 用于设置文字的对齐 -- left(可选值 'left''center''right')
 * opt.base : 用于设置文字的水平对齐 -- top (可选值 'top''bottom''middle''normal')
 * opt.color : 字体颜色 -- #333333
 * opt.size : 字体大小 -- 16
 * opt.maxWidth : 文字最大宽度
 * opt.lineHeight : 行高 -- 1
 * opt.opacity : 透明度 -- 1
 * opt.isParagraph : 段落模式 -- false 
 * 扩展中...
 * return : 文本的高度 = 行数*行高*字体大小 
*/
drawWrapText( opt={} ){
  console.log(opt)
  let ctx = this.data.ctx;
  ctx.save();
  ctx.beginPath(); //开始绘制
  ctx.setFillStyle(opt.color || '#333333' );
  opt.x = opt.x || 0;
  opt.y = opt.y || 0;
  opt.size = opt.size || 16;
  ctx.setFontSize( opt.size );
  ctx.setTextAlign(opt.align || 'left' );
  ctx.setTextBaseline(opt.base || 'top' );
  ctx.setGlobalAlpha(opt.opacity || 1);
  let isParagraph = opt.isParagraph || false , //是否开始段落模式
      _x = isParagraph ? opt.x + opt.size * 2 : opt.x , //文本首行x偏移量
      line_count = 0 , //行数 
      lineHeight = opt.lineHeight || 1; //行高
  const metrics = ctx.measureText(opt.text); //测量文本尺寸信息,目前仅返回文本宽度。同步接口。
  if( !opt.maxWidth || ( metrics.width <= opt.maxWidth ) ){
    ctx.fillText(opt.text, _x , opt.y ,opt.maxWidth || '');
    line_count++;
  }else {
    // 超过最大宽度,进行换行操作
    opt.text = opt.text.replace(/\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g,""); // 去掉emoji
    let paragraphArr = opt.text.split("\n"); //拆分段落
    for( let i=0, len = paragraphArr.length; i < len; i++ ){
      let paragraph = paragraphArr[i],  //段落
          text = '', //绘制文字
          count = 0; //段落行数 ,临时存储
      for( let j=0, _len = paragraph.length; j < _len; j++ ){
        text += paragraph[j];
        let maxWidth = opt.maxWidth - (count==0? _x-opt.x : 0)
        if( ctx.measureText( text ).width >= maxWidth ){
          //换行
          ctx.fillText( text , count==0? _x : opt.x , opt.y + opt.size * lineHeight * line_count ,maxWidth);
          line_count++;
          count++;
          text = '';
        }
        if( j == _len -1 && text != '' ){
          ctx.fillText( text , opt.x , opt.y + opt.size * lineHeight * line_count ,maxWidth);
          line_count++;
          count++;
          text = '';
        }
      }
    }
  }
  ctx.closePath();
  ctx.restore(); //恢复之前保存的绘图上下文
  console.log('文本的高度 = 行数*行高*字体大小 = ', line_count * lineHeight * opt.size )
  return line_count * lineHeight * opt.size;
},

图片绘制(缩放裁剪/圆形)

/* 
 * 注意:图片需用wx.getImageInfo()处理
 * opt : Object
 * opt.imageResource   所要绘制的图片资源
 * opt.dx   图像的左上角在目标canvas上 X 轴的位置
 * opt.dy   图像的左上角在目标canvas上 Y 轴的位置
 * opt.dWidth   在目标画布上绘制图像的宽度,允许对绘制的图像进行缩放
 * opt.dHeight  在目标画布上绘制图像的高度,允许对绘制的图像进行缩放
 * opt.image  图片信息 wx.getImageInfo()
 * opt.clip  缩放裁剪图片
 * opt.align  clip为true有效:缩放图片位置  leftTop(左上默认)/center(居中)
 * opt.arc 圆形图片
*/
drawImage( opt={} ){
  let ctx = this.data.ctx;
  ctx.save();
  ctx.beginPath(); //开始绘制
  if( opt.arc || opt.clip ){
    if(opt.arc){
      // 画圆 x,y,r 
      ctx.arc(opt.dWidth / 2 + opt.dx, opt.dHeight / 2 + opt.dy, opt.dWidth / 2, 0, Math.PI * 2, false);
    }else if( opt.clip ){
      // 缩放裁剪图片 
      ctx.rect(opt.dx,opt.dy,opt.dWidth,opt.dHeight);
      // dw/w = dh/h -> dw = dh/h*w 
      //                dh = dw/w*h 
      if( opt.image.width/opt.dWidth <= opt.image.height/opt.dHeight ){
        let h = opt.dWidth/opt.image.width*opt.image.height;
        if( opt.align == 'center' ){
          opt.dy = -( h - opt.dHeight )/2 + opt.dy;
        }
        opt.dHeight = h
        console.log(1,'width <= height',opt.dHeight);
      }else if( opt.image.width/opt.dWidth > opt.image.height/opt.dHeight ){
        let w = opt.dHeight/opt.image.height*opt.image.width;
        if( opt.align == 'center' ){
          opt.dx = -( w - opt.dWidth )/2 + opt.dx;
        }
        opt.dWidth = w;
        console.log(2,'height > width',opt.dHeight);
      }
    }
    ctx.clip();//剪切某个区域,之后的绘图都会被限制在剪切的区域内,ctx.restore()恢复
  }
  ctx.drawImage(opt.imageResource,opt.dx, opt.dy, opt.dWidth, opt.dHeight,opt.sx, opt.sy, opt.sWidth, opt.sHeight);// 推进去图片,必须是https图片
  ctx.restore(); //恢复之前保存的绘图上下文
},

未完待续...

如需转载,烦请注明出处:juejin.cn/post/684490…