Use canvas to share two-dimensional code on the H5 page of the small program. The effect as shown below can be saved and scanned

General idea: Canvas is used for drawing. In order to save time, the fixed part is drawn with the background image, only the TWO-DIMENSIONAL code and the display picture and title. After drawing, call uni.canvastotempFilepath to turn it into a picture display

1. Component invocation: use ref to call the corresponding canvas drawing method inside the component, and pass in relevant parameters including name, route, display picture, etc.

 <SharePoster v-if='showposter' ref='poster' @close='close'/>

<script>
  import SharePoster from "@/components/share/shareposter.vue"
  export default {
    components: {
       SharePoster,
    },
   methods: {handleShare(item){
          this.showposter=true
          if(this.showvote){
            this.showvote=false
          }
          this.$nextTick(() = > {
         this.$refs.poster.drawposter(item.name, `/pagesMore/voluntary/video/player? schoolId=${item.id}`,item.cover)
          })
        },
   }
 </script>
Copy the code

2. The component template places the Canvas container and assigns the ID, width, height, etc. Use isComplete to control whether to display the canvas or the image generated by the last call to Uni.canvastotempFilepath

<div class="poster-wrapper" @click="closePoster($event)">
      <div class='poster-content'>
          <canvas canvas-id="qrcode"
            v-if="qrShow"
            :style="{opacity: 0, position: 'absolute', top: '-1000px'}"
          ></canvas>
          <canvas
            canvas-id="poster"
            :style="{ width: cansWidth + 'px', height: cansHeight + 'px' ,opacity: 0, }"
            v-if='! iscomplete'
          ></canvas>
          <image
            v-if="iscomplete"
            :style="{ width: cansWidth + 'px', height: cansHeight + 'px' }"
            :src="tempFilePath"
            @longpress="longpress"
          ></image>
      </div>
  </div>
Copy the code

3. Set parameters in data

 data() {
      return {
          bgImg:'https://cdn.img.up678.com/ueditor/upload/image/20211130/1638258070231028289.png'.// Canvas background image
          cansWidth:288.// Canvas width
          cansHeight:410.// Canvas height
          projectImgWidth:223.// Show the width of the image in the middle
          projectImgHeight:167.// Show the height of the image in the middle
          qrShow:true.// Two-dimensional canvas
          qrData: null.// Code data
          tempFilePath:' '.// Generate graph path
          iscomplete:false.// Whether to generate a picture}},Copy the code

4. Call uni.createCanvasContext during the Created life cycle to create a Canvas instance and pass in the canvas container ID within the template

created(){
      this.ctx = uni.createCanvasContext('poster'.this)},Copy the code

5. Call corresponding methods to draw shared works

   // Draw shared works
      async drawposter(name='The Most Beautiful University scene in Chongqing',url,projectImg){
           uni.showLoading({
             title: "Loading...".mask: true
           })
           // Generate a QR code
          await this.createQrcode(url)
          / / the background
          await this.drawWebImg({
            url: this.bgImg,
            x: 0.y: 0.width: this.cansWidth, height: this.cansHeight
          })
          / / display figure
          await this.drawWebImg({
            url: projectImg,
            x: 33.y: 90.width: this.projectImgWidth, height: this.projectImgHeight
          })
          await this.drawText({
            text: name,
            x: 15.y: 285.color: '#241D4A'.size: 15.bold: true.center: true.shadowObj: {x: '0'.y: '4'.z: '4'.color: 'rgba (173,77,0,0.22)'}})// Draw a qr code
          await this.drawQrcode()
          // Convert to image
          this.tempFilePath = await this.saveCans()
          this.iscomplete = true
          uni.hideLoading()
      },
Copy the code

6. DrawImage method: note that the first parameter of this.ctx. DrawImage method cannot be used to display network images

  drawWebImg(conf) {
        return new Promise((resolve, reject) = > {
          uni.downloadFile({
            url: conf.url,
            success: (res) = > {
              this.ctx.drawImage(res.tempFilePath, conf.x, conf.y, conf.width? conf.width:"", conf.height? conf.height:"")
              this.ctx.draw(true.() = > {
                resolve()
              })
            },
            fail: err= > {
              reject(err)
            }
          })
        })
      },
Copy the code

7. Draw text titles

 drawText(conf) {
        return new Promise((resolve, reject) = > {
          this.ctx.restore()
          this.ctx.setFillStyle(conf.color)
          if(conf.bold) this.ctx.font = `normal bold ${conf.size}px sans-serif`
          this.ctx.setFontSize(conf.size)
          if(conf.shadowObj) {
            // this.ctx.shadowOffsetX = conf.shadowObj.x
            // this.ctx.shadowOffsetY = conf.shadowObj.y
            // this.ctx.shadowOffsetZ = conf.shadowObj.z
            // this.ctx.shadowColor = conf.shadowObj.color
          }
          let x = conf.x
          conf.text=this.fittingString(this.ctx,conf.text,280)
          if(conf.center) {
            let len = this.ctx.measureText(conf.text)
            x = this.cansWidth / 2 - len.width / 2 + 2
          }

          this.ctx.fillText(conf.text, x, conf.y)
          this.ctx.draw(true.() = > {
            this.ctx.save()
            resolve()
          })
        })
      },
// Text header overflow hide processing
fittingString(_ctx, str, maxWidth) {
            let strWidth = _ctx.measureText(str).width;
            const ellipsis = '... ';
            const ellipsisWidth = _ctx.measureText(ellipsis).width;
            if (strWidth <= maxWidth || maxWidth <= ellipsisWidth) {
              return str;
            } else {
              var len = str.length;
              while (strWidth >= maxWidth - ellipsisWidth && len-- > 0) {
                str = str.slice(0, len);
                strWidth = _ctx.measureText(str).width;
              }
              returnstr + ellipsis; }},Copy the code

8. Generate a QR code

      createQrcode(qrcodeUrl) {
        // console.log(window.location.origin)
        const config={host:window.location.origin}
        return new Promise((resolve, reject) = > {
          let url = `${config.host}${qrcodeUrl}`
          // if(url.indexOf('? ') === -1) url = url + '? sh=1'
          // else url = url + '&sh=1'
          try{
            new qrCode({
              canvasId: 'qrcode'.usingComponents: true.context: this.// correctLevel: 3,
              text: url,
              size: 130.cbResult: (res) = > {
                this.qrShow = false
                this.qrData = res
                resolve()
              }
            })
          } catch (err) {
            reject(err)
          }
        })
      },
Copy the code

9. Draw the QR code. This. qrData is the generated QR code resource

  drawQrcode(conf = { x: 185, y: 335, width: 100, height: 50}) {
        return new Promise((resolve, reject) = > {
          this.ctx.drawImage(this.qrData, conf.x, conf.y, conf.width, conf.height)
          this.ctx.draw(true.() = > {
            resolve()
          })
        })
      },
Copy the code

10. Convert canvas contents into images and display them. On H5, tempFilePath is base64

// canvs => images
      saveCans() {
        return new Promise((resolve, reject) = > {
          uni.canvasToTempFilePath({
            x:0.y:0.canvasId: 'poster'.success: (res) = > {
              resolve(res.tempFilePath)
            },
            fail: (err) = > {
              uni.hideLoading()
              reject(err)
            }
          }, this)})},Copy the code

11. All code of the component

<template>
  <div class="poster-wrapper" @click="closePoster($event)">
      <div class='poster-content'>
          <canvas canvas-id="qrcode"
            v-if="qrShow"
            :style="{opacity: 0, position: 'absolute', top: '-1000px'}"
          ></canvas>
          <canvas
            canvas-id="poster"
            :style="{ width: cansWidth + 'px', height: cansHeight + 'px' ,opacity: 0, }"
            v-if='! iscomplete'
          ></canvas>
          <image
            v-if="iscomplete"
            :style="{ width: cansWidth + 'px', height: cansHeight + 'px' }"
            :src="tempFilePath"
            @longpress="longpress"
          ></image>
      </div>
  </div>
</template>

<script>
  import qrCode from '@/utils/wxqrcode.js'
  export default {
    data() {
      return {
          bgImg:'https://cdn.img.up678.com/ueditor/upload/image/20211130/1638258070231028289.png'.// Canvas background image
          cansWidth:288.// Canvas width
          cansHeight:410.// Canvas height
          projectImgWidth:223.// Show the width of the image in the middle
          projectImgHeight:167.// Show the height of the image in the middle
          schoolImgWidth:110.// The middle shows the width of the college
          schoolImgHeight:110.// Show the height of the university in the middle
          qrShow:true.// Two-dimensional canvas
          qrData: null.// Code data
          tempFilePath:' '.// Generate graph path
          iscomplete:false.// Whether to generate a picture}},created(){
      this.ctx = uni.createCanvasContext('poster'.this)},methods: {closePoster(e) {
        if(e.target.id === e.currentTarget.id) {
          / / close
          this.$emit('close')}},// Draw shared works
      async drawposter(name='The Most Beautiful University scene in Chongqing',url,projectImg){
           uni.showLoading({
             title: "Loading...".mask: true
           })
          await this.createQrcode(url)
          / / the background
          await this.drawWebImg({
            url: this.bgImg,
            x: 0.y: 0.width: this.cansWidth, height: this.cansHeight
          })
          / / display figure
          await this.drawWebImg({
            url: projectImg,
            x: 33.y: 90.width: this.projectImgWidth, height: this.projectImgHeight
          })
          await this.drawText({
            text: name,
            x: 15.y: 285.color: '#241D4A'.size: 15.bold: true.center: true.shadowObj: {x: '0'.y: '4'.z: '4'.color: 'rgba (173,77,0,0.22)'}})/ / qr code
          await this.drawQrcode()
          this.tempFilePath = await this.saveCans()
          this.iscomplete = true
          uni.hideLoading()
      },
      // Draw share school
      async drawposterschool(name,url,schoolImg){
           uni.showLoading({
             title: "Loading...".mask: true
           })
          await this.createQrcode(url)
          / / the background
          await this.drawWebImg({
            url: this.bgImg,
            x: 0.y: 0.width: this.cansWidth, height: this.cansHeight
          })
          / / display figure
          await this.drawSchoolImg({
            url: schoolImg,
            x: 90.y: 120.width: this.schoolImgWidth, height: this.schoolImgHeight
          })
          await this.drawText({
            text: name,
            x: 15.y: 285.color: '#241D4A'.size: 15.bold: true.center: true.shadowObj: {x: '0'.y: '4'.z: '4'.color: 'rgba (173,77,0,0.22)'}})/ / qr code
          await this.drawQrcode()
          this.tempFilePath = await this.saveCans()
          this.iscomplete = true
          uni.hideLoading()
      },
      drawWebImg(conf) {
        return new Promise((resolve, reject) = > {
          uni.downloadFile({
            url: conf.url,
            success: (res) = > {
              this.ctx.drawImage(res.tempFilePath, conf.x, conf.y, conf.width? conf.width:"", conf.height? conf.height:"")
              this.ctx.draw(true.() = > {
                resolve()
              })
            },
            fail: err= > {
              reject(err)
            }
          })
        })
      },
      drawSchoolImg(conf) {
        return new Promise((resolve, reject) = > {
          uni.downloadFile({
            url: conf.url,
            success: (res) = > {
              this.ctx.save()
              this.ctx.beginPath()
              this.ctx.arc(135.170.70.0.2 * Math.PI)
              // this.ctx.setFillStyle('blue')
              // this.ctx.fill()
              this.ctx.clip();
               this.ctx.drawImage(res.tempFilePath, conf.x, conf.y, conf.width, conf.height)
               this.ctx.restore()
              this.ctx.draw(true.() = > {
                resolve()
              })
            },
            fail: err= > {
              reject(err)
            }
          })
        })
      },
      drawText(conf) {
        return new Promise((resolve, reject) = > {
          this.ctx.restore()
          this.ctx.setFillStyle(conf.color)
          if(conf.bold) this.ctx.font = `normal bold ${conf.size}px sans-serif`
          this.ctx.setFontSize(conf.size)
          if(conf.shadowObj) {
            // this.ctx.shadowOffsetX = conf.shadowObj.x
            // this.ctx.shadowOffsetY = conf.shadowObj.y
            // this.ctx.shadowOffsetZ = conf.shadowObj.z
            // this.ctx.shadowColor = conf.shadowObj.color
          }
          let x = conf.x
          conf.text=this.fittingString(this.ctx,conf.text,280)
          if(conf.center) {
            let len = this.ctx.measureText(conf.text)
            x = this.cansWidth / 2 - len.width / 2 + 2
          }

          this.ctx.fillText(conf.text, x, conf.y)
          this.ctx.draw(true.() = > {
            this.ctx.save()
            resolve()
          })
        })
      },
       fittingString(_ctx, str, maxWidth) {
            let strWidth = _ctx.measureText(str).width;
            const ellipsis = '... ';
            const ellipsisWidth = _ctx.measureText(ellipsis).width;
            if (strWidth <= maxWidth || maxWidth <= ellipsisWidth) {
              return str;
            } else {
              var len = str.length;
              while (strWidth >= maxWidth - ellipsisWidth && len-- > 0) {
                str = str.slice(0, len);
                strWidth = _ctx.measureText(str).width;
              }
              returnstr + ellipsis; }},// Draw the qr code
      drawQrcode(conf = { x: 185, y: 335, width: 100, height: 50}) {
        return new Promise((resolve, reject) = > {
          this.ctx.drawImage(this.qrData, conf.x, conf.y, conf.width, conf.height)
          this.ctx.draw(true.() = > {
            resolve()
          })
        })
      },
      // Generate a QR code
      createQrcode(qrcodeUrl) {
        // console.log(window.location.origin)
        const config={host:window.location.origin}
        return new Promise((resolve, reject) = > {
          let url = `${config.host}${qrcodeUrl}`
          // if(url.indexOf('? ') === -1) url = url + '? sh=1'
          // else url = url + '&sh=1'
          try{
            new qrCode({
              canvasId: 'qrcode'.usingComponents: true.context: this.// correctLevel: 3,
              text: url,
              size: 130.cbResult: (res) = > {
                this.qrShow = false
                this.qrData = res
                resolve()
              }
            })
          } catch (err) {
            reject(err)
          }
        })
      },
      // canvs => images
      saveCans() {
        return new Promise((resolve, reject) = > {
          uni.canvasToTempFilePath({
            x:0.y:0.canvasId: 'poster'.success: (res) = > {
              resolve(res.tempFilePath)
            },
            fail: (err) = > {
              uni.hideLoading()
              reject(err)
            }
          }, this)})},}}</script>

<style lang="stylus" scoped>
  .poster-wrapper{
    width 100vw
    height 100vh
    position fixed
    background rgba(0.0.0.4)
    left 0
    top 0
    text-align center
    z-index 99999
    .poster-content{
      position absolute
      top 50%
      left 50%
      transform translate(-50%, -50%)}}</style>

Copy the code