<template>
  <div
    class="saturation"
    @mousedown.prevent.stop="selectSaturation"
  >
    <canvas ref="canvasSaturation" />
    <div
      :style="slideSaturationStyle"
      class="slide"
    />
  </div>
</template>

<script lang="ts">
/* eslint-disable */
import { defineComponent } from 'vue'
import { createLinearGradient } from './composible'

export default defineComponent({
  props: {
    color: {
      type: String,
      default: '#000000'
    },
    hsv: {
      type: Object,
      default: null
    },
    saturationWidth: {
      type: Number,
      default: 152
    },
    saturationHeight: {
      type: Number,
      default: 152
    }
  },
  emits: ['selectSaturation'],
  data () {
    return {
      slideSaturationStyle: {}
    }
  },
  mounted () {
    this.renderColor()
    this.renderSlide()
  },
  methods: {
    renderColor () {
      const canvas: any = this.$refs.canvasSaturation
      const width = this.saturationWidth
      const height = this.saturationHeight
      const ctx = canvas.getContext('2d')
      canvas.width = width
      canvas.height = height

      ctx.fillStyle = this.color
      ctx.fillRect(0, 0, width, height)

      createLinearGradient(
        'l',
        ctx,
        width,
        height,
        '#FFFFFF',
        'rgba(255,255,255,0)'
      )
      createLinearGradient('p', ctx, width, height, 'rgba(0,0,0,0)', '#000000')
    },
    renderSlide () {
      this.slideSaturationStyle = {
        left: this.hsv.s * this.saturationWidth - 5 + 'px',
        top: (1 - this.hsv.v) * this.saturationHeight - 5 + 'px'
      }
    },
    selectSaturation (e: any) {
      const {
        top: saturationTop,
        left: saturationLeft
      } = this.$el.getBoundingClientRect()
      const ctx = e.target.getContext('2d')

      const mousemove = (e: any) => {
        let x = e.clientX - saturationLeft
        let y = e.clientY - saturationTop

        if (x < 0) {
          x = 0
        }
        if (y < 0) {
          y = 0
        }
        if (x > this.saturationWidth) {
          x = this.saturationWidth
        }
        if (y > this.saturationHeight) {
          y = this.saturationHeight
        }

        // Do not modify the dom by monitoring data changes, otherwise when the color is #ffffff, the slide will go to the lower left corner
        this.slideSaturationStyle = {
          left: x - 5 + 'px',
          top: y - 5 + 'px'
        }
        // If you use the maximum value, the selected pixel will be empty, and the empty default is black
        const imgData = ctx.getImageData(
          Math.min(x, this.saturationWidth - 1),
          Math.min(y, this.saturationHeight - 1),
          1,
          1
        )
        const [r, g, b] = imgData.data
        this.$emit('selectSaturation', { r, g, b })
      }

      mousemove(e)

      const mouseup = () => {
        document.removeEventListener('mousemove', mousemove)
        document.removeEventListener('mouseup', mouseup)
      }

      document.addEventListener('mousemove', mousemove)
      document.addEventListener('mouseup', mouseup)
    }
  }
})
</script>

<style lang="scss">
.saturation {
  @apply cursor-pointer relative;
  & canvas {
    @apply rounded-sm;
  }
  .slide {
    @apply absolute pointer-events-none border border-white;
    left: 100px;
    top: 0;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    box-shadow: 0 0 1px 1px rgba(0, 0, 0, 0.3);
  }
}
</style>
