一個canvas簽名組件 vant框架

不多說,直接上代碼(vant只是一個遮罩,自己看情況)

https://github.com/toKnowMore/sign-canvas

<template>
  <div class="sign-canvas">
    <van-overlay :show="show" @click="hideCanvas">
      <div class="wrapper" @click.stop>
        <div ref="canvasHw" class="overlay-content">
          <div class="overlay-title">請簽名</div>
          <canvas
            ref="canvas"
            canvas-id="signCanvas"
            @touchstart="touchStart"
            @touchmove="touchMove"
            @touchend="touchEnd"
            @mousedown="mouseDown"
            @mousemove="mouseMove"
            @mouseup="mouseUp"/>
          <div class="contents-buttons">
            <div v-show="isCheat !== 1" class="contents-button" @click="cancleSign">取消</div>
            <div v-show="isCheat !== 1" class="contents-button" @click="clearCanvas">清除</div>
            <div class="contents-button" @click="saveCanvas">確定</div>
          </div>
        </div>
      </div>
    </van-overlay>
  </div>
</template>

<script>
var canvas = null
var canvasTxt = null
var points = []
export default {
  name: 'SignCanvas',
  props: {
    show: {
      type: Boolean,
      default: false
    },
    isCheat: {
      type: Number,
      default: 0
    }
  },
  data() {
    return {
      client: {},
      startX: 0,
      startY: 0,
      moveY: 0,
      moveX: 0,
      isDown: false
    }
  },
  mounted() {
    this.initCanvas()
  },
  methods: {
    hideCanvas() {
      if (this.isCheat === 1) {
        return
      } else {
        this.show = false
      }
    },
    initCanvas() {
      canvas = this.$refs.canvas// 指定canvas
      canvas.width = window.screen.availWidth - 80
      canvas.height = 300
      canvasTxt = canvas.getContext('2d')// 設置2D渲染區域
      canvasTxt.lineWidth = 3 // 設置線的寬度
      canvasTxt.lineCap = 'round'
      canvasTxt.lineJoin = 'round'
    },
    // mobile
    touchStart(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        this.startX = obj.x
        this.startY = obj.y
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.closePath()
        canvasTxt.stroke()
        points.push(obj)
      }
    },
    touchMove(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        this.startX = obj.x
        this.startY = obj.y
        points.push(obj)
      }
    },
    touchEnd(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
      }
    },
    // pc
    mouseDown(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        this.startX = obj.x
        this.startY = obj.y
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
        this.isDown = true
      }
    },
    mouseMove(ev) {
      ev = ev || event
      ev.preventDefault()
      if (this.isDown) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        this.startY = obj.y
        this.startX = obj.x
        points.push(obj)
      }
    },
    mouseUp(ev) {
      ev = ev || event
      ev.preventDefault()
      if (ev.touches.length === 1) {
        const obj = {
          x: ev.touches[0].pageX - canvas.offsetLeft,
          y: ev.touches[0].pageY - canvas.offsetTop
        }
        canvasTxt.beginPath()
        canvasTxt.moveTo(this.startX, this.startY)
        canvasTxt.lineTo(obj.x, obj.y)
        canvasTxt.stroke()
        canvasTxt.closePath()
        points.push(obj)
        points.push({ x: -1, y: -1 })
        this.isDown = false
      }
    },
    cancleSign() {
      this.clearCanvas()
      this.$emit('cancle')
    },
    // 重寫
    clearCanvas() {
      canvasTxt.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
      points = []
      this.$emit('clear')
    },
    // 確定簽名
    async saveCanvas() {
      const file = {}
      file.type = 'image/png'
      file.name = 'sign.png'
      file.content = this.$refs.canvas.toDataURL()
      const imgFile = await this.dataURLToBlob(file)
      this.$emit('save', imgFile)
    },
    dataURLToBlob(file) {
      var arr = file.content.split(',')
      const bstr = atob(arr[1])
      let n = bstr.length
      const u8arr = new Uint8Array(n)
      while (n--) {
        u8arr[n] = bstr.charCodeAt(n)
      }
      return new File([u8arr], file.name, {
        type: file.type
      })
    }
  }
}
</script>

<style scoped lang="scss">
.wrapper {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  padding: 0 40px;
}

.overlay-content {
  border: 1px solid #ededed;
  background-color: white;
  border-radius: 20px;
  width: 100%;
  .contents-signCanvas {
    width: 100%;
    height: 200px;
  }
  .overlay-title {
    text-align: center;
    font-size: 16px;
    padding: 10px 0;
    font-weight: bold;
    border-bottom: 1px solid #ededed;
  }
  .contents-buttons {
    display: flex;
    justify-content: space-between;
    padding: 5px 0;
    border-top: 1px solid #ededed;
    .contents-button {
      padding: 10px 0;
      text-align: center;
      flex: 1;
      font-size: 15px;
      color: rgba(37, 127, 255, 1);
    }
  }
}
</style>

引用

import signCanvas from '@/components/signCanvas'
export default {
  components: {
    modalNumbers,
    signCanvas
  },
  filters: {
    isPass: function(val) {
      switch (val) {
        case 0:
          return '通過'
        case 1:
          return '未通過'
        default:
          break
      }
    },
    questionType(val) {
      switch (val) {
        case 0:
          return '單選題'
        case 1:
          return '多選題'
        case 2:
          return '是非題'
        default:
          break
      }
    }
  },
  data() {
    return {
    	showCanvas: false,
    }
  },
  created(e) {},
  mounted() {},
  methods: {
    cancleCanvas() {
      this.showCanvas = false
      console.log('取消畫布')
    },

    clearCanvas() {
      console.log('清除畫布')
    },

    saveCanvas(file) {
      this.$toast.loading()
      var formData = new FormData()
      formData.append('file', file)
      uploadFile(formData).then(response => {
        this.$toast.clear()
        this.$set(this.submitExamEdit, 'signImg', response.data)
        this.showCanvas = false
        this.sendSubmitData()
      }).catch(() => {
        this.$toast.clear()
      })
    }
  }
}
</script>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章