微信小程序使用canvas绘制海报

在使用自定义组件绘制海报时,一定要传第二个参数this,不然绘制不成功。
所有网络图片都需要通过wx.downloadFile下载下来,如果是本地图片则不需要下载,本示例采用组件方式

在这里插入图片描述
目录结构
在这里插入图片描述
组件canvas

<view class="web" catchtouchmove='stopMove' wx:if="{{isShow}}">
    <view class="foot" animation="{{animation}}">
        <view class="foot-list">
            <button class="" hover-class="none" open-type="share">
                <view class="iconfont icon-weixin wx" ></view>
                <view class="title">分享给朋友</view>
            </button>
            <view class="" bindtap='creatPosters'>
                <view class="iconfont icon-ico goods-icon"></view>
                <view class="title">生成商品海报</view>
            </view>
            
        </view>
        <view class="cancel" bindtap='cancel'>关闭</view>
    </view>
</view>
<canvas  
    canvas-id="myCanvas"
    style="width:{{screen_width*375+'px'}}; height:{{screen_height-100+'px'}}"
 ></canvas>
 <!-- 海报展示 -->
 <view class="posters-content"  catchtouchmove='stopMove' wx:if="{{posters}}">
     <view class="poster-warpp">
        <view class="posters-img">
            <image class="posters"
             style="width:{{screen_width*375+180+'rpx !important'}};height:{{screen_height+150+'rpx'}}"  
             src="{{posters}}" 
             mode='aspectFill'
             bindtap='preview'
            />
        </view>
        <button
            class="save" 
            open-type="openSetting" 
            wx:if="{{isShare}}"
            bindopensetting='openSetting'
        >
        	保存图片
        </button>
        <view class="save"wx:else catchtap="save">保存图片</view>
        <view class="call-off" catchtap="callOff">取消保存</view>
     </view>
</view>

组件样式

@import '../../app.wxss';
.web{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.7);
}
.foot{
    width: 100%;
    height: 300rpx;
    background: #f3f1f2;
    position: absolute;
    left: 0;
    bottom: -100%;
}
.foot-list{
    height: 200rpx;
    display: flex;
    align-items: center;
    justify-content: space-around;
}
.wx{
    color: #50b674;
    font-size: 60rpx;
    text-align: center;
    
}
button{
    line-height: unset;
    background: transparent;
    padding: 0;
    margin: 0;
}
.button-hover{
    color: transparent !important;
    background: transparent !important;
}
button::after{
    display: none;
}
.title{
    font-size: 26rpx;
    color: #333;
    margin-top: 20rpx;
}
.goods-icon{
    color: #3c7cfc;
    font-size: 60rpx;
    text-align: center;
}
.cancel{
    width: 100%;
    height: 100rpx;
    text-align: center;
    line-height: 100rpx;
    font-size: 32rpx;
    color: #333;
    background: #fff;
}
canvas{
    position: fixed;
    bottom: -100%;
}
.posters-content{
    position: fixed;
    width: 100%;
    left: 0;
    top: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: 100;
}
.poster-warpp{
    position: absolute;
    top: 50%;
    left: 50%;
    transform:translate(-50%,-50%);
    -webkit-transform:translate(-50%,-50%);
    -moz-transform:translate(-50%,-50%);
    -ms-transform:translate(-50%,-50%);
    -o-transform:translate(-50%,-50%);
    padding: 60rpx 24rpx 30rpx 24rpx;
    background: #fff;
}

.posters-img{
    display: block;
    width: 550rpx;
    margin: auto;
    background: #fff;
    height: 635rpx;
    overflow: hidden;
    opacity: 1;
    text-align: center;
}
.save{
    font-size: 32rpx;
    color: #fff;
    background: #3c7cfc;
    text-align: center;
    height: 80rpx;
    line-height: 80rpx;
    margin-top: 30rpx;
    border-radius: 10rpx;
    -webkit-border-radius: 10rpx;
    -moz-border-radius: 10rpx;
    -ms-border-radius: 10rpx;
    -o-border-radius: 10rpx;
}
.call-off{
    font-size: 28rpx;
    color: #7f7f7f;
    margin-top: 20rpx;
    text-align: center;
}
//引入生成canvas方法
import detailCanvas from '../../utils/shareCanvas.js';
Component({
  /**
   * 组件的属性列表
   */
  properties: {
    detailImg:{
      type:String
    },
    codeImg:{
      type:String
    },
    title:{
      type:String
    },
    content:{
      type:String
    },
    price:{
      type:String
    },
    action:{
      type:String
    }
  },
  lifetimes:{
    ready:function(){
    //  获取当前手机的宽高
      wx.getSystemInfo({
        success: (res)=>{
          this.setData({
            screen_width: res.windowWidth/375,
            screen_height: res.windowHeight
         })
        },
        
      });
     
    }
  },
 
  /**
   * 组件的初始数据
   */
  data: {
    isShow:false,
    animation:'',
    screen_width:'',
    screen_height:'',
    posters:'',
    isShare:false
  },

组件的方法列表,Promise.all方法可以在所有图片完成加载之后再触发回调,这样就可以避免其中图片没有加载完成就开始绘制canvas

  methods: {
  //禁止页面滑动
    stopMove(){},
    cancel(){
      this.setData({
        isShow:false
      })
      this.creatAnimation("-100%");
    },
    showWeb(){
      this.setData({
        isShow:true
      })
      this.creatAnimation(0);
    },
    //取消保存
    callOff(){
      this.setData({
        posters:''
      })
    },
    creatPosters(){
      wx.showLoading({
        title: '绘制中',
        mask: true,
      });
      let that = this;
      let detailImg = this.properties.detailImg;
      let title = this.properties.title;
      let codeImg = this.properties.codeImg;
      let price = this.properties.price;
      let content = this.properties.content;
      let action = this.properties.action;
      Promise.all([
        this.getCode(detailImg),
        this.getCode(codeImg),
      ])
      .then(res=>{
          let sWidth = this.data.screen_width;
          let sHeight = this.data.screen_height;
          let code = res[1].tempFilePath;
          let img = res[0].tempFilePath;
        detailCanvas(that,sWidth,sHeight,img,code,title,action,price,content,function(res){
          wx.hideLoading();
          that.setData({
            posters:res,
            isShow:false
          });
          that.creatAnimation("-100%");
        });
      })
    },
    //弹窗动画效果
    creatAnimation(num){
     let animation= wx.createAnimation({
        duration:200,
        timingFunction:'ease-in'
      })
      animation.bottom(num).step();
      this.setData({
        animation:animation.export()
      })
    },
    //把网路图片下载成本地图片
    getCode(img){
      return new Promise((resolve,reject)=>{
        wx.downloadFile({
          url: img,
          success: (res) => {
            resolve(res)
          }
        })
      })
      
    },
     //保存图片
     save(){
       let posters = this.data.posters;
       wx.saveImageToPhotosAlbum({
        filePath: posters,
        success: (res)=>{
          console.log(res)
          wx.showToast({
            title:'保存成功',
            icon:'success'
          })
          this.setData({
            posters:''
          })
        },
        fail: (err)=>{
          console.log(err)
          wx.showToast({
            title: '请授权保存图片',
            icon: 'none',
          });
          this.setData({
            isShare:true
          })
        },
      });
     },
     openSetting(e){
       if(e.detail.authSetting['scope.writePhotosAlbum']){
        this.setData({
          isShare:false
        })
       }
     },
     preview(){
       let posters = this.data.posters;
       wx.previewImage({
         current: posters,
         urls: [posters],
       });
     },
  }
})

创建shareCanvas.js方法,绘制canvas,canvas使用的单位是px所以在获取手机屏幕宽度时,进行像素转换,做兼容处理res.windowWidth/375,以iphone6为例,下面变量中的sWidth也就是转换之后的像素。小程序canvas支持画布绘制完成之后的回调cxt.draw(false,callback);必须在draw的callback后执行,才能调用起图片预览,展示等功能

export default function detailCanvas(that,sWidth,sHeight,imgUrl,codeImg,title,action,price,content,callback){
    let rpx = sWidth;
    const cxt = wx.createCanvasContext('myCanvas',that);
    cxt.save();
    cxt.setFillStyle('#fff')
    cxt.fillRect(0, 0, sWidth*375, sHeight-100);
    //商品图片
    let detailImgHeight = (sWidth*375)*9/16;
    cxt.drawImage(imgUrl,0,0,sWidth*375,detailImgHeight);
    //二维码
    cxt.drawImage(codeImg,(sWidth*375-110*rpx),310*rpx,100*rpx,100*rpx);
    cxt.restore();
    //标题
    cxt.setFontSize(18);
    cxt.setFillStyle('#333333');
    if(title.length>19){
        title=title.slice(0,18)+"...";
    }
    cxt.fillText(title,10*rpx,240*rpx);
    //价格
    if(price){
        cxt.setFontSize(20);
        cxt.setFillStyle("#eb164c");
        cxt.fillText('¥'+price,10*rpx,280*rpx);
    }
    //副标题
    if(content){
        if(content.length>19){
            content=content.slice(0,18)+"...";
        }
        cxt.setFontSize(20);
        cxt.setFillStyle("#eb164c");
        cxt.fillText(content,10*rpx,280*rpx);
    }
    cxt.setStrokeStyle('#ddd')
    cxt.strokeRect(0,300*rpx,sWidth*375,0.1)
    cxt.setFillStyle('#292929');
    cxt.setFontSize('12');
    cxt.fillText('微信扫码或长按保存图片',10*rpx,350*rpx);
    cxt.fillText(action|| '微信小程序商城',10*rpx,370*rpx);
    cxt.draw(false,()=>{
        wx.canvasToTempFilePath({
            x: 0,
            y: 0,
            canvasId:"myCanvas",
            fileType: 'png',
            success: (res)=>{
                callback(res.tempFilePath)
            },
           
        }, that);
    });
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值