<template>
  <canvas ref="canvas" @mousedown="mouseDown" @mousemove="mouseMove" @mouseup="mouseUp"
  @touchstart="touchStart" @touchmove="touchMove" @touchend="touchEnd"></canvas>
</template>

<script>
export default {
  props: {
    value: {
      type: String
    },
    width: {
      type: Number,
      default: 800
    },
    height: {
      type: Number,
      default: 300
    },
    lineWidth: {
      type: Number,
      default: 4
    },
    lineColor: {
      type: String,
      default: '#000000'
    },
    bgColor: {
      type: String,
      default: ''
    },
    isCrop: {
      type: Boolean,
      default: false
    },
    isClearBgColor: {
      type: Boolean,
      default: true
    },
    format: {
      type: String,
      default: 'image/png'
    },
    quality: {
      type: Number,
      default: 1
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data () {
    return {
      hasDrew: false,
      resultImg: '',
      points: [],
      canvasTxt: null,
      startX: 0,
      startY: 0,
      isDrawing: false,
      sratio: 1
    }
  },
  computed: {
    ratio () {
      return this.height / this.width
    },
    stageInfo () {
      return this.$refs.canvas.getBoundingClientRect()
    },
    myBg () {
      return this.bgColor ? this.bgColor : 'rgba(255, 255, 255, 0)'
    }
  },
  watch: {
    'myBg': function (newVal) {
      this.$refs.canvas.style.background = newVal
    },
    isDrawing() {
      // 每次绘制结束 触发一次change事件
      this.$emit('change')
    },
    value(val) {
      // 判断当前是否已经绘制 
      this.$_init()
    },
    width(val) {
      this.$_resizeHandler()
    },
    height(val) {
      this.$_resizeHandler()
    }
  },
  beforeMount () {
    window.addEventListener('resize', this.$_resizeHandler)
  },
  beforeDestroy () {
    window.removeEventListener('resize', this.$_resizeHandler)
  },
  mounted () {
    const canvas = this.$refs.canvas
    canvas.height = this.height
    canvas.width = this.width
    canvas.style.background = this.myBg
    this.$_resizeHandler()
    // 在画板以外松开鼠标后冻结画笔
    document.onmouseup = () => {
      this.isDrawing = false
    }
    this.$_init()
  },
  methods: {
    $_init() {
      if(this.value && !this.hasDrew) { 
            // 绘制
            const this_ = this 
            const image = new Image();
            image.onload = function() {
              // 将图片绘制到画布上
              this_.canvasTxt.drawImage(image, 0, 0);
            };
            image.src = this.value;
      } 
        
       
    },
    $_resizeHandler () {
      const canvas = this.$refs.canvas
      canvas.style.width = this.width + "px"
      const realw = parseFloat(window.getComputedStyle(canvas).width)
      canvas.style.height = this.height + "px";
      this.canvasTxt = canvas.getContext('2d')

      console.log('canvas.style' , canvas.style.width , canvas.style.height)
      // this.canvasTxt.scale(1 * this.sratio, 1 * this.sratio)
      // this.sratio = realw / this.width
      // this.canvasTxt.scale(1 / this.sratio, 1 / this.sratio)
    },
    // pc
    mouseDown (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      this.isDrawing = true
      this.hasDrew = true
      let obj = {
        x: e.offsetX,
        y: e.offsetY
      }
      this.drawStart(obj)
    },
    mouseMove (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      if (this.isDrawing) {
        let obj = {
          x: e.offsetX,
          y: e.offsetY
        }
        this.drawMove(obj)
      }
    },
    mouseUp (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      let obj = {
        x: e.offsetX,
        y: e.offsetY
      }
      this.drawEnd(obj)
      this.isDrawing = false
    },
    // mobile
    touchStart (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      this.hasDrew = true
      if (e.touches.length === 1) {
        let obj = {
          x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
          y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
        }
        this.drawStart(obj)
      }
    },
    touchMove (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      if (e.touches.length === 1) {
        let obj = {
          x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
          y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
        }
        this.drawMove(obj)
      }
    },
    touchEnd (e) {
      if(this.disabled) return
      e = e || event
      e.preventDefault()
      if (e.touches.length === 1) {
        let obj = {
          x: e.targetTouches[0].clientX - this.$refs.canvas.getBoundingClientRect().left,
          y: e.targetTouches[0].clientY - this.$refs.canvas.getBoundingClientRect().top
        }
        this.drawEnd(obj)
      }
    },
    // 绘制
    drawStart (obj) {
      if(this.disabled) return
      this.startX = obj.x
      this.startY = obj.y
      this.canvasTxt.beginPath()
      this.canvasTxt.moveTo(this.startX, this.startY)
      this.canvasTxt.lineTo(obj.x, obj.y)
      this.canvasTxt.lineCap = 'round'
      this.canvasTxt.lineJoin = 'round'
      this.canvasTxt.lineWidth = this.lineWidth * this.sratio
      this.canvasTxt.stroke()
      this.canvasTxt.closePath()
      this.points.push(obj)
    },
    drawMove (obj) {
      if(this.disabled) return
      this.canvasTxt.beginPath()
      this.canvasTxt.moveTo(this.startX, this.startY)
      this.canvasTxt.lineTo(obj.x, obj.y)
      this.canvasTxt.strokeStyle = this.lineColor
      this.canvasTxt.lineWidth = this.lineWidth * this.sratio
      this.canvasTxt.lineCap = 'round'
      this.canvasTxt.lineJoin = 'round'
      this.canvasTxt.stroke()
      this.canvasTxt.closePath()
      this.startY = obj.y
      this.startX = obj.x
      this.points.push(obj)
    },
    drawEnd (obj) {
      if(this.disabled) return
      this.canvasTxt.beginPath()
      this.canvasTxt.moveTo(this.startX, this.startY)
      this.canvasTxt.lineTo(obj.x, obj.y)
      this.canvasTxt.lineCap = 'round'
      this.canvasTxt.lineJoin = 'round'
      this.canvasTxt.stroke()
      this.canvasTxt.closePath()
      this.points.push(obj)
      this.points.push({x: -1, y: -1})
    },
    // 操作
    generate (options) {
      let imgFormat = options && options.format ? options.format: this.format
      let imgQuality = options && options.quality ? options.quality: this.quality
      const pm =  new Promise((resolve, reject) => {
        if (!this.hasDrew) {
          reject(`Warning: Not Signned!`)
          return
        }
        console.log('this.$refs.canvas.width, this.$refs.canvas.height' , this.$refs.canvas.width, this.$refs.canvas.height)
        var resImgData = this.canvasTxt.getImageData(0, 0, this.$refs.canvas.width, this.$refs.canvas.height)
        this.canvasTxt.globalCompositeOperation = "destination-over"
        this.canvasTxt.fillStyle = this.myBg
        this.canvasTxt.fillRect(0,0,this.$refs.canvas.width ,this.$refs.canvas.height)
        this.resultImg = this.$refs.canvas.toDataURL(imgFormat, imgQuality)
        var resultImg = this.resultImg
        this.canvasTxt.clearRect(0, 0, this.$refs.canvas.width ,this.$refs.canvas.height)
        this.canvasTxt.putImageData(resImgData, 0, 0)
        this.canvasTxt.globalCompositeOperation = "source-over"
        if (this.isCrop) {
          const crop_area = this.getCropArea(resImgData.data)
          var crop_canvas = document.createElement('canvas')
          const crop_ctx = crop_canvas.getContext('2d')
          crop_canvas.width = crop_area[2] - crop_area[0]
          crop_canvas.height = crop_area[3] - crop_area[1]
          const crop_imgData = this.canvasTxt.getImageData(...crop_area)
          crop_ctx.globalCompositeOperation = "destination-over"
          crop_ctx.putImageData(crop_imgData, 0, 0)
          crop_ctx.fillStyle = this.myBg
          crop_ctx.fillRect(0, 0, crop_canvas.width , crop_canvas.height)
          resultImg = crop_canvas.toDataURL(imgFormat, imgQuality)
          crop_canvas = null
        }
        resolve(resultImg)
      })
      return pm
    },
    reset () {
      this.canvasTxt.clearRect(
        0,
        0,
        this.$refs.canvas.width,
        this.$refs.canvas.height
      )
      if (this.isClearBgColor) {
        this.$emit('update:bgColor', '')
        this.$refs.canvas.style.background = 'rgba(255, 255, 255, 0)'
      }
      this.points = []
      this.hasDrew = false
      this.resultImg = ''
    },
    getCropArea (imgData) {
      var topX = this.$refs.canvas.width; var btmX = 0; var topY = this.$refs.canvas.height; var btnY = 0
      for (var i = 0; i < this.$refs.canvas.width; i++) {
        for (var j = 0; j < this.$refs.canvas.height; j++) {
          var pos = (i + this.$refs.canvas.width * j) * 4
          if (imgData[pos] > 0 || imgData[pos + 1] > 0 || imgData[pos + 2] || imgData[pos + 3] > 0) {
            btnY = Math.max(j, btnY)
            btmX = Math.max(i, btmX)
            topY = Math.min(j, topY)
            topX = Math.min(i, topX)
          }
        }
      }
      topX++
      btmX++
      topY++
      btnY++
      const data = [topX, topY, btmX, btnY]
      return data
    }
  }
}
</script>

<style scoped>
canvas {
  max-width: 100%;
  display: block;
}
</style>