canvas实现手写板(vue)

<template>
  <div class="signature">
    <!-- 签名 -->
    <div class="canvas">
      <canvas
        id="myCanvas"
        ref="canvas"
        width="600"
        height="600"
        @touchstart="touchStart"
        @touchmove="touchMove"
        @touchend="touchEnd"
        @mousedown="mouseDown"
        @mousemove="mouseMove"
        @mouseup="mouseUp"
      >
        您的浏览器不支持 HTML5 canvas 标签。
      </canvas>
    </div>
    <div
      class="save-btn"
      @click.stop.prevent="commit"
    >提交签名
    </div>
    <div
      class="back-btn"
      @click.stop.prevent="routeGo"
    >
      <i class="icon"></i>
      <span class="label">返回</span>
    </div>
    <div
      class="clear-btn"
      @click.stop.prevent="clear"
    >
      <i class="icon"></i>
      <span class="label">清空</span>
    </div>
  </div>
</template>

<script>
export default {
  data () {
    return {
      // canvasWidth: window.innerWidth,
      // canvasHeight: window.innerHeight,
      canvasImg: '', // 签名图片地址
      ctx: null,
      stage_info: [], // 移动端按下点到屏幕的偏差
      isDown: false,
      points: [],
      startX: 0, // 起始点x坐标
      startY: 0 // 起始点y坐标
    }
  },
  mounted () {
    this.init()
  },
  methods: {
    // 初始化画板
    init () {
      const canvas = this.$refs.canvas
      this.ctx = canvas.getContext('2d')
      this.ctx.strokeStyle = '#000'
      this.stage_info = canvas.getBoundingClientRect()
    },
    // pc
    mouseDown (ev) {
      const e = ev || event
      e.preventDefault()
      this.isDown = true
      const obj = {
        x: e.offsetX,
        y: e.offsetY
      }
      this.startX = obj.x
      this.startY = obj.y
      this.ctx.beginPath()
      this.ctx.moveTo(this.startX, this.startY)
      this.ctx.lineTo(obj.x, obj.y)
      this.ctx.stroke()
      this.ctx.closePath()
      this.points.push(obj)
    },
    mouseMove (ev) {
      const e = ev || event
      e.preventDefault()
      if (this.isDown) {
        const obj = {
          x: e.offsetX,
          y: e.offsetY
        }
        this.ctx.beginPath()
        this.ctx.moveTo(this.startX, this.startY)
        this.ctx.lineTo(obj.x, obj.y)
        this.ctx.stroke()
        this.ctx.closePath()
        this.startY = obj.y
        this.startX = obj.x
        this.points.push(obj)
      }
    },
    mouseUp (ev) {
      const e = ev || event
      e.preventDefault()
      const obj = {
        x: ev.offsetX,
        y: ev.offsetY
      }
      this.ctx.beginPath()
      this.ctx.moveTo(this.startX, this.startY)
      this.ctx.lineTo(obj.x, obj.y)
      this.ctx.stroke()
      this.ctx.closePath()
      this.points.push(obj)
      this.points.push({
        x: -1,
        y: -1
      })
      this.isDown = false
    },
    // mobile
    touchStart (ev) {
      const e = ev || event
      e.preventDefault()
      if (e.touches.length === 1) {
        const obj = {
          x: e.targetTouches[0].clientX - this.stage_info.left,
          y: e.targetTouches[0].clientY - this.stage_info.top
        }
        this.startX = obj.x
        this.startY = obj.y
        this.ctx.beginPath()
        this.ctx.moveTo(this.startX, this.startY)
        this.ctx.lineTo(obj.x, obj.y)
        this.ctx.stroke()
        this.ctx.closePath()
        this.points.push(obj)
      }
    },
    touchMove (ev) {
      const e = ev || event
      e.preventDefault()
      if (e.touches.length === 1) {
        const obj = {
          x: e.targetTouches[0].clientX - this.stage_info.left,
          y: e.targetTouches[0].clientY - this.stage_info.top
        }
        this.ctx.beginPath()
        this.ctx.moveTo(this.startX, this.startY)
        this.ctx.lineTo(obj.x, obj.y)
        this.ctx.stroke()
        this.ctx.closePath()
        this.startX = obj.x
        this.startY = obj.y
        this.points.push(obj)
      }
    },
    touchEnd (ev) {
      const e = ev || event
      e.preventDefault()
      if (e.touches.length === 1) {
        const obj = {
          x: e.targetTouches[0].clientX - this.stage_info.left,
          y: e.targetTouches[0].clientY - this.stage_info.top
        }
        this.startX = obj.x
        this.startY = obj.y
        this.ctx.beginPath()
        this.ctx.moveTo(this.startX, this.startY)
        this.ctx.lineTo(obj.x, obj.y)
        this.ctx.stroke()
        this.ctx.closePath()
        this.points.push(obj)
      }
    },
    // 返回
    routeGo () {
      this.$router.go(-1)
    },
    clear () {
      this.ctx.clearRect(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
      this.points = []
    },
    commit () {
      this.canvasImg = this.$refs.canvas.toDataURL()
      console.log(this.canvasImg)
    }
  }
}
</script>

<style lang="less">
  .signature {
    /*min-height: 100vh;*/
    background: #fff;
    position: relative;

    .canvas {
      font-size: 0;
    }

    .save-btn {
      position: absolute;
      bottom: 0;
      left: 50%;
      z-index: 9;
      margin-top: -20px;
      /*transform: rotate(90deg);*/
      transform-origin: center center;
      font-size: 18px;
      color: #fcfcfc;
      line-height: 25px;
      padding: 8px 43px;
      background: linear-gradient(90deg,
      rgba(57, 115, 230, 1) 0%,
      rgba(57, 115, 230, 1) 100%);
      border-radius: 2px;
    }

    .back-btn {
      position: absolute;
      top: 20px;
      left: 50px;
      z-index: 9;
      transform-origin: left top;
      display: flex;
      flex-direction: column;

      .icon {
        display: inline-block;
        width: 42px;
        height: 42px;
        /*background: url("../../assets/images/signature_back.png") no-repeat center*/
        /*center;*/
        background-size: contain;
      }

      .label {
        font-size: 16px;
        color: #d8d8d8;
        text-align: center;
      }
    }

    .clear-btn {
      position: absolute;
      top: 20px;
      right: 50px;
      z-index: 9;
      transform-origin: left top;
      display: flex;
      flex-direction: column;

      .icon {
        display: inline-block;
        width: 42px;
        height: 42px;
        /*background: url("../../assets/images/signature_clear.png") no-repeat*/
        /*center center;*/
        background-size: contain;
      }

      .label {
        font-size: 16px;
        color: #d8d8d8;
        text-align: center;
      }
    }
  }
</style>
上一篇:ios微信公众号或浏览器滚动露底漏网址闪动无法固定


下一篇:Knight Moves