<template>
  <div ref="main">
    <canvas ref="canvas" class="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
  </div>
</template>
<script>
import elementResizeDetectorMaker from 'element-resize-detector'
import {getRatio} from './utils/tools'
import {FPS, ANIMATION_TIME} from './config/index'

export default {
  name: 'MapLine',
  data () {
    return {
      ratio: getRatio(),
      ctx: '',
      r: 15,
      time: 0,
      timeIndex: 0,
      highLightLineArr: [],
      now: '',
      then: Date.now(),
      interval: 1000 / FPS,
      delta: '',
      ANIMATION_TIME,
      requestAnimationFrameTimer: 0
    }
  },
  props: {
    lineList: {
      type: Array,
      default: () => []
    },
    lineValue: {
      type: Array,
      default: () => []
    },
    currName: {
      type: String,
      default: ''
    },
    animation: {
      type: Boolean,
      default: false
    },
    highLightLines: {
      type: Array,
      default: () => []
    },
    mapWidth: {
      type: Number,
      default: 0
    },
    mapHeight: {
      type: Number,
      default: 0
    }
  },
  watch: {
    line () {
      this.render()
    },
    highLightLines () {
      this.render()
    }
  },
  computed: {
    fontSize () {
      return 13 * this.ratio
    },
    canvasWidth () {
      return this.mapWidth * this.ratio
    },
    canvasHeight () {
      return this.mapHeight * this.ratio
    }
  },
  mounted () {
    this.observer = elementResizeDetectorMaker()
    this.observer.listenTo(this.$refs.main, this.render)
  },
  beforeDestroy () {
    this.observer.removeListener(this.$refs.main, this.render)
    clearTimeout(this.timeIndex)
    cancelAnimationFrame(this.requestAnimationFrameTimer)
  },
  methods: {
    render () {
      const el = this.$refs.canvas
      const ctx = el.getContext('2d') || {}
      this.ctx = ctx
      ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      this.setHighLightLines(this.highLightLines)
      this.renderLines()
    },
    // 绘制线集合
    renderLines () {
      const ctx = this.ctx
      ctx.width = this.canvasWidth
      ctx.height = this.canvasHeight
      ctx.lineWidth = 2 * this.ratio
      ctx.clearRect(0, 0, this.canvasWidth, this.canvasHeight)
      const lines = this.lineList.concat(this.highLightLineArr)
      lines.forEach((line) => {
        line.animation > 0 && (line.animation -= this.ANIMATION_TIME)
        const isHideLight = line.isLight && this.time / 2 > 10 && line.animation > 0
        this.renderLine(line, isHideLight)
      })
      // 不兼容requestAnimationFrame，则用setTimeout
      if (this.animation) {
        if (window.requestAnimationFrame) {
          cancelAnimationFrame(this.requestAnimationFrameTimer)
          this.doAnimation()
        } else {
          this.timeIndex = setTimeout(() => {
            clearTimeout(this.timeIndex)
            this.setTimeForDraw()
          }, this.ANIMATION_TIME)
        }
      }
    },
    doAnimation () {
      this.requestAnimationFrameTimer = requestAnimationFrame(this.doAnimation)
      this.now = Date.now()
      this.delta = this.now - this.then
      // 经过了足够的时间
      if (this.delta > this.interval) {
        // 这里不能简单then=now，否则还会出现细微时间差问题。例如fps=10，每帧100ms，而现在每16ms（60fps）执行一次draw。16*7=112>100，需要7次才实际绘制一次。这个情况下，实际10帧需要112*10=1120ms>1000ms才绘制完成
        this.then = this.now - (this.delta % this.interval)
        this.setTimeForDraw()
      }
    },
    // 执行潮流动画
    setTimeForDraw () {
      this.time = this.time >= 40 ? 0 : this.time + 1
      this.renderLines()
    },
    // 绘制线路
    renderLine (line, isHideLight) {
      const ctx = this.ctx
      if (isHideLight) {
        ctx.strokeStyle = '#10ecf9'
      } else {
        ctx.strokeStyle = line.color || '#10ecf9'
      }
      let lineWidth = 2
      if (line.name === this.currName || line.isLight) {
        lineWidth = 4
      }
      ctx.lineWidth = lineWidth * this.ratio
      // 判断是否为虚线
      const isDash = line.typ && (line.index <= line.typ - 1)
      this.renderSolidLine(ctx, line, isDash)
      ctx.save()
      !isDash && this.renderLineDash(line)
      ctx.restore()
    },
    // 设置高亮线路
    setHighLightLines (lines) {
      const animation = 10 * 1000
      this.highLightLineArr = []
      // 选择断面后，返回的线路数值名称是‘xx-xx 1’的形式，而目前展示网架图的线路数据名称是‘xx-xx’的形式，重新组装一个数组做对比
      const lineList = this.lineList
      lineList.forEach(item => {
        this.lineValue.forEach(({name = '', values = []}) => {
          if (item.name === name && !item.nameWithNum) {
            item.nameWithNum = values[item.index] ? values[item.index].name : ''
          }
        })
        lines.forEach(({name: {elName = '', elNameAlias = ''}, warnType}) => {
          if (item.nameWithNum === elName) {
            const color = this.getWarnColor(warnType)
            this.highLightLineArr.push({isLight: true, color, animation, ...item})
          }
        })
      })
    },
    /**
     * 获取断面线路颜色
     * @param type 1， 2， 3
     * @returns {string|string}
     */
    getWarnColor (type = 0) {
      const colors = ['#00ff00', '#00ff00', '#ff9739', '#ff0000']
      return colors[type] || ''
    },
    // 绘制实线
    renderSolidLine (ctx, {x1, y1, x2, y2}, isDash) {
      const DashArr = isDash ? [15 * this.ratio, 10 * this.ratio] : []
      ctx.beginPath()
      ctx.setLineDash(DashArr)
      ctx.moveTo(x1, y1)
      ctx.lineTo(x2, y2)
      ctx.stroke()
      ctx.closePath()
    },
    // 绘制虚线（动画虚线）
    renderLineDash (line) {
      const {x1, y1, x2, y2, value} = line
      const ctx = this.ctx
      // 判断潮流方向
      if (!value) {
        return false
      }
      ctx.beginPath()
      ctx.strokeStyle = this.getLineColor()
      const DashArr = [20 * this.ratio, 22.5 * this.ratio]
      ctx.setLineDash(DashArr)
      ctx.lineDashOffset = this.time * (value > 0 ? -1 : 1) * this.ratio
      ctx.moveTo(x1, y1)
      ctx.lineTo(x2, y2)
      ctx.stroke()
      ctx.closePath()
    },
    // 获取当前线路动画颜色
    getLineColor () {
      const op = Math.abs(Math.sin(Math.PI / 360 * this.time * 9))
      return `rgba(228,255,123,${op})`
    },
    // 角度 转换 值
    getRads (degrees) {
      return (Math.PI * degrees) / 180
    }
  }
}
</script>
<style scoped>
.canvas {
  width: 100%;
  height: 100%;
}
</style>
