<template>
  <div ref="main" class="main"></div>
</template>
<script>
import elementResizeDetectorMaker from 'element-resize-detector'
import {getRatio, polygon} from './utils/tools'
import {icons} from './config/index'

export default {
  name: 'MapHover',
  props: {
    nodeList: {
      type: Array,
      default: () => []
    },
    lineList: {
      type: Array,
      default: () => []
    },
    mapWidth: {
      type: Number,
      default: 0
    },
    mapHeight: {
      type: Number,
      default: 0
    },
    nodeDragable: {
      type: Boolean,
      default: false
    },
    // 缩放
    scaleValue: {
      type: Number,
      default: 50
    }
  },
  data () {
    return {
      icons,
      ratio: getRatio(),
      canvasHoverFlag: '',
      canvasHoverTimer: '',
      isMouseDown: false,
      mouseEventTimeIndex: '',
      // 节点拖动前的坐标
      nodeOldPos: {
        x: '',
        y: ''
      },
      // 节点拖动后的坐标
      nodeNewPos: {
        x: '',
        y: ''
      },
      mainWidth: '', // div.class宽
      mainHeight: '' // div.class高
    }
  },
  computed: {
    scaleW () {
      return this.mapWidth / this.mainWidth
    },
    scaleH () {
      return this.mapHeight / this.mainHeight
    },
    collectionArr () {
      return this.polygonCollectionArr.concat(this.lineCollectionArr)
    },
    polygonCollectionArr () {
      return this.getNodeCollectionArr()
    },
    lineCollectionArr () {
      return this.getLineCollectionArr()
    }
  },
  watch: {
    scaleValue () {
      setTimeout(() => {
        this.setMainWidthHeight()
      }, 50)
    }
  },
  mounted () {
    this.setMouseEvent()
    this.observer = elementResizeDetectorMaker()
    this.observer.listenTo(this.$refs.main, this.setMainWidthHeight)
  },
  beforeDestroy () {
    this.observer.removeListener(this.$refs.main, this.setMainWidthHeight)
  },
  methods: {
    // 设置鼠标在canvas上的事件
    setMouseEvent () {
      const el = this.$refs.main
      if (!el) return
      el.onmousedown = (e) => {
        this.ctxMouseDown(e)
      }
      el.onmousemove = (e) => {
        this.ctxMouseMove(e)
      }
      el.onmouseup = (e) => {
        this.ctxMouseUp(e)
      }
      el.onmouseleave = (e) => {
        this.onHover('')
      }
      el.ondblclick = (e) => {
        this.judgePointPosition(e)
      }
    },
    ctxMouseDown (e) {
      this.isMouseDown = true
      this.pageX = e.pageX
      this.pageY = e.pageY
      const {disx, disy} = this.getMouseDisInCanvas(e) // 点击在网架图里的坐标
      this.disx = disx
      this.disy = disy
      // console.log('mouseDown在网架图上的x:' + this.disx)
      // console.log('mouseDown在网架图上的y:' + this.disy)
      this.curMouseOnNode = {}
      this.judgePointPosition(e)
    },
    ctxMouseMove (e) {
      if (this.isMouseDown) { // mousemove有两种情况，一种是按住鼠标的拖拽行为
        if (this.nodeDragable && this.curMouseOnNode.name) {
          const {disx, disy} = this.getMouseDisInCanvas(e)
          this.disx2 = disx
          this.disy2 = disy
          const moveDisx = this.disx2 - this.disx // 在网架图里的偏移量
          const moveDisy = this.disy2 - this.disy
          // console.log('mouse在网架图上移动x距离:' + moveDisx)
          // console.log('mouse在网架图上移动y距离:' + moveDisy)
          this.nodeNewPos.x = moveDisx + this.nodeOldPos.x // 节点新的位置 = 偏移量 + 节点位置坐标
          this.nodeNewPos.y = moveDisy + this.nodeOldPos.y
          this.$emit('on-node-drag',
            {x: this.nodeNewPos.x, y: this.nodeNewPos.y},
            this.curMouseOnNode.name)
        }
      } else { // 另一种是悬浮行为
        this.judgePointPosition(e)
      }
    },
    ctxMouseUp (e) {
      // el.style.cursor = 'pointer'
      this.isMouseDown = false
      if (this.pageX === e.pageX && this.pageY === e.pageY) { // mouseUp有两种情况，一种是在单击。即onMouseDown和onMouseUp两次鼠标位置相同
        this.judgePointPosition(e)
      } else { // 另一种是拖拽后的mouseup，即onMouseDown和onMouseUp两次鼠标位置不同
        if (this.nodeDragable && this.curMouseOnNode.name) { // 如果开启了节点拖拽，并且标识curMouseOnNode有值
          this.$emit('on-node-drag-end',
            {x: this.nodeNewPos.x, y: this.nodeNewPos.y},
            this.curMouseOnNode.name)
        }
      }
    },
    // 判断鼠标是否在节点，线路等元素上, 节流
    judgePointPosition (event) {
      clearTimeout(this.mouseEventTimeIndex)
      this.mouseEventTimeIndex = setTimeout(() => {
        const el = this.$refs.main
        const location = this.getMouseLocation(event.clientX, event.clientY)
        const currNode = this.getNodeOnMouseLocation(location)
        this.onHover(currNode.name)
        el.style.cursor = currNode.name ? 'pointer' : ''
        if (currNode.name) {
          this.$emit('on-mouse-event', {currNode, event})
          // 如果鼠标在节点上，保存这个节点用于拖拽
          if (currNode.typ === 1) {
            this.curMouseOnNode = currNode
            this.nodeOldPos = this.getNodePos(currNode.name)
          }
        }
      }, 200)
    },
    // 获取鼠标点击在网架图里的位置
    getMouseDisInCanvas (e) {
      const {top, left} = this.getMainBound()
      const disx = (e.pageX - left) * this.scaleW
      const disy = (e.pageY - top) * this.scaleH
      return {disx, disy}
    },
    // 获取节点的原始坐标
    getNodePos (nodeName) {
      const findNode = this.nodeList.find(({name}) => name === nodeName)
      return {x: findNode.originalx, y: findNode.originaly}
    },
    setMainWidthHeight () {
      const {width, height} = this.getMainBound()
      this.mainWidth = width
      this.mainHeight = height
    },
    // 获取main的长度信息
    getMainBound () {
      const el = this.$refs.main
      return el.getBoundingClientRect()
    },
    getNodeOnMouseLocation (location = []) {
      return this.collectionArr.find(({position}) => polygon(location, position)) || {name: ''}
    },
    // 设置鼠标悬浮要显示气泡的节点
    getNodeCollectionArr () {
      const fontSize = 13 * this.ratio
      return this.nodeList.map((node) => {
        let {type = 0, name = '', x = 0, y = 0, dx = 0, dy = 0} = node
        // 圆形 x,y是圆点
        let position = []
        // 文本(外省节点)
        if (type === 3) {
          const w = name.length * fontSize
          const h = fontSize
          x = Math.round(x + dx - w / 2)
          y = Math.round(y + 13 * 2 / 5 + dy - h)
          position = [
            [x, y],
            [x + w, y],
            [x + w, y + h],
            [x, y + h]]
        } else {
          const r = this.getPolygonSize({type})
          x = Math.round(x - r)
          y = Math.round(y - r)
          position = [
            [x, y],
            [x + 2 * r, y],
            [x + 2 * r, y + 2 * r],
            [x, y + r]
          ]
        }
        return {
          name,
          position,
          item: node,
          typ: 1 // 1为点 2为线
        }
      })
    },
    // 获取区域的半径
    getPolygonSize (node) {
      const icon = this.icons.find(({type = []}) =>
        type === node.type) || {size: 10}
      return Math.round(icon.size * this.ratio)
    },
    // 设置鼠标悬浮要显示气泡的线路
    getLineCollectionArr () {
      return this.lineList.map(item => {
        const lineWidth = 10 * this.ratio
        const {x1, x2, y1, y2} = item
        // 为了让线路更容易被悬浮选中，将线条扩大5像素
        const positionTop = [
          [x1 - lineWidth, y1 + lineWidth],
          [x1 + lineWidth, y1 - lineWidth],
          [x2 + lineWidth, y2 - lineWidth],
          [x2 - lineWidth, y2 + lineWidth]
        ]
        const positionBottom = [
          [x1 - lineWidth, y1 - lineWidth],
          [x1 + lineWidth, y1 + lineWidth],
          [x2 + lineWidth, y2 + lineWidth],
          [x2 - lineWidth, y2 - lineWidth]
        ]
        const position = x1 <= x2 ? (y1 <= y2 ? [...positionTop] : [...positionBottom]) : (y1 <= y2 ? [...positionBottom] : [...positionTop])
        return {
          name: item.name,
          nameAlias: item.nameAlias,
          position: position, // 线路四个顶点的坐标数组
          item: item,
          typ: 2 // 1为点 2为线
        }
      })
    },
    // 获取鼠标在canvas上的坐标
    getMouseLocation (x, y) {
      const {width, height, left, top} = this.getMainBound()
      return [Math.round((x - left) * (this.mapWidth / width)) * this.ratio, Math.round((y - top) * (this.mapHeight / height) * this.ratio)]
    },
    onHover (name, e) {
      if (this.canvasHoverFlag !== name) {
        this.canvasHoverFlag = name
        this.$emit('on-hover', this.canvasHoverFlag)
      }
    }
  }
}
</script>
<style scoped>
.main {
  width: 100%;
  height: 100%;
}
</style>
