<template lang="pug">
div
  div(v-if="!hasBmView", ref="view", style="width: 100%; height: 100%")
  slot
</template>

<script>
import Vue from 'vue'
import image from '../static/u8995.png'
const _panFactor = 0.0005
export default {
  name: 'ol-map',
  props: {
    url: {
      type: String,
      default: image // http://localhost:8089/geoserver/gwc/service/wmts'
    },
    type: {
      type: String,
      default: 'picture'
    },
    center: {
      type: Array,
      default: [0, 0],
      required: true
    },
    zoom: {
      type: Number,
      default: 2
    },
    minZoom: {
      type: Number,
      default: 0
    },
    maxZoom: {
      type: Number,
      default: 5
    },
    extent: {
      type: Array,
      default: function () {
        return [116.24261269642659, 40.21687592760154,
          116.27199903984895, 40.2462622710239]
      }
    },
    projection: {
      type: String,
      default: 'EPSG:4326'
    },
    rotation: {
      type: Number,
      default: 0
    },
    zoomFactor: {
      type: Number,
      default: 2
    },
    resolution: {
      type: Number
    },
    resolutions: {
      type: Array,
      default: function () {
        return [2.5152827955346596E-5, 1.8864620966509947E-5, 1.2576413977673298E-5, 6.288206988836649E-6, 2.5152827955346597E-6, 1.2576413977673299E-6]
      }
    },
    maxResolution: {
      type: Number
    },
    minResolution: {
      type: Number
    }
  },
  data () {
    return {
      hasBmView: false,
      olmap: null,
      gridNames: ['10,000', '7,500', '5,000', '2,500', '1,000', '500'],
      layer: null
    }
  },
  watch: {
    url (val) {
      this.olmap.removeLayer(this.layer)
      this.olmap.setView(null)
      this.olmap.setTarget(null)
      this.olmap.setLayerGroup(null)
      this.olmap = null
      this.init()
    },
    center (val) {
      const { olmap, center } = this
      olmap.getView().setCenter(center)
    },
    zoom (val) {
      const { olmap } = this
      olmap.getView().setZoom(val)
    },
    minZoom (val) {
      const { olmap } = this
      olmap.setMinZoom(val)
    },
    maxZoom (val) {
      const { olmap } = this
      olmap.setMaxZoom(val)
    }
  },
  methods: {
    init () {
      let $el = this.$refs.view // 地图布局，地图是用和容器渲染-------
      for (let $node of this.$slots.default || []) {
        if ($node.componentOptions && $node.componentOptions.tag === 'bs-view') {
          this.hasBmView = true
          $el = $node.elm
        }
      }
      const { ol, zoom, projection, center, extent, url, type, gridNames, resolutions, minZoom, maxZoom } = this
      var pro = new ol.proj.Projection({// 地图投影类型
        code: projection,
        units: 'degrees',
        extent: extent
      })
      if (type === 'map') {
        const source = new ol.source.WMTS({
          url,
          layer: 'bstar:zhengfadaxue',
          matrixSet: 'zhengfadaxue',
          format: 'image/png',
          projection: pro,
          tileGrid: new ol.tilegrid.WMTS({
            tileSize: [256, 256],
            extent,
            origin: [116.24261269642659, 40.24907154738439],
            resolutions: resolutions,
            matrixIds: gridNames
          }),
          style: '',
          wrapX: true
        })
        this.layer = new ol.layer.Tile({
          source: source
        })
      }
      if (type === 'picture') {
        this.layer = new ol.layer.Image({
          source: new ol.source.ImageStatic({
            url, // 静态地图图片地址
            imageExtent: extent, // 映射到地图的范围
            projection: pro
          })
        })
      }
      this.layer.set('id', 'basemap')
      this.layer.set('name', '底图')
      const map = new ol.Map({
        target: $el,
        controls: ol.control.defaults({ attribution: false, zoom: false }),
        layers: [this.layer],
        view: new ol.View({
          projection: pro,
          center,
          zoom,
          resolutions,
          minZoom,
          maxZoom
        })
      })
      this.olmap = map
      Vue.prototype.$map = map
      this.$emit('ready', {
        ol,
        map
      })
      // 地图移动结束事件
      this.olmap.on('moveend', ev => {
        // let loc = ev.coordinate
        // this.$emit('moveend', { lon: loc[0], lat: loc[1] })
      })
      // 地图开始移动事件
      this.olmap.on('movestart', ev => {
        // let loc = ev.coordinate
        // this.$emit('movestart', { lon: loc[0], lat: loc[1] })
      })
      // 鼠标拖拽事件
      this.olmap.on('pointerdrag', ev => {
        let loc = ev.coordinate
        this.$emit('mousedrag', { lon: loc[0], lat: loc[1] })
      })
      // 鼠标移动事件
      this.olmap.on('pointermove', ev => {
        let loc = ev.coordinate
        this.$emit('mousemove', { lon: loc[0], lat: loc[1], dragging: ev.dragging })
      })
      // 鼠标单击事件
      this.olmap.on('click', ev => {
        let loc = ev.coordinate
        this.$emit('click', { lon: loc[0], lat: loc[1] })
      })
      // 鼠标单次单击事件
      this.olmap.on('singleclick', ev => {
        let loc = ev.coordinate
        this.$emit('singleclick', { lon: loc[0], lat: loc[1] })
      })
      // 鼠标双击事件
      this.olmap.on('dblclick', ev => {
        let loc = ev.coordinate
        this.$emit('dblclick', { lon: loc[0], lat: loc[1] })
      })
      // 地图渲染事件----渲染前
      this.olmap.on('precompose', ev => {
        this.$emit('precompose')
        console.log('地图渲染前------地图渲染事件')
      })
      // 地图渲染事件----渲染后
      this.olmap.on('postcompose', ev => {
        this.$emit('postcompose')
        console.log('地图渲染后------地图渲染事件')
      })
      // 地图事件，渲染后----
      this.olmap.on('postrender', ev => {
        this.$emit('postrender')
        console.log('地图渲染前------地图事件')
      })
      // 地图事件，渲染后----
      this.olmap.on('change:layerGroup', ev => {
        console.log('地图事件---图层发生变化----')
      })
      // 地图事件，渲染后----
      this.olmap.on('change:view', ev => {
        console.log('地图视图发生改变-----')
        console.log(ev)
      })
      // 地图缩放事件
      this.olmap.getView().on('change:resolution', ev => {
        var zoom = this.olmap.getView().getZoom()
        var center = this.olmap.getView().getCenter()
        var extent = this.olmap.getView().calculateExtent(this.olmap.getSize())
        this.$emit('zoom', { zoom, center, extent })
      })
    },
    centerAndZoom (x, y, level) {
      this.centerAt(x, y)
      this.setLevel(level)
    },
    centerAt (x, y) {
      this.olmap.getView().setCenter([x, y])
    },
    centerAtWithOffset (x, y, offX, offY) {
      var _screenP = this.toScreen(x, y)
      _screenP.x = _screenP.x + offX
      _screenP.y = _screenP.y + offY
      var _mapP = this.toMap(_screenP.x, _screenP.y)
      this.centerAt(_mapP.x, _mapP.y)
    },
    setLevel (level) {
      this.olmap.getView().setZoom(level)
    },
    moveToLeft () {
      var view = this.olmap.getView()
      var mapCenter = view.getCenter()
      // 让地图中心的x值增加，即可使得地图向左移动，增加的值根据效果可自由设定
      mapCenter[0] += _panFactor
      view.setCenter(mapCenter)
      this.olmap.render()
    },
    moveToRight () {
      var view = this.olmap.getView()
      var extent = this.getCurrentExtent()
      console.log('地图范围：' + extent)
      var level = this.getLevel()
      console.log('地图级别：' + level)
      //  var mapCenter = ol.extent.getCenter([extent.minX, extent.minY, extent.maxX, extent.maxY])
      var mapCenter = view.getCenter()
      // 让地图中心的x值减少，即可使得地图向右移动，减少的值根据效果可自由设定
      mapCenter[0] -= _panFactor
      view.setCenter(mapCenter)
      this.olmap.render()
    },
    // 向上移动地图
    moveToUp () {
      var view = this.olmap.getView()
      var mapCenter = view.getCenter()
      // 让地图中心的y值减少，即可使得地图向上移动，减少的值根据效果可自由设定
      mapCenter[1] -= _panFactor
      view.setCenter(mapCenter)
      this.olmap.render()
    },
    // 向下移动地图
    moveToDown () {
      var view = this.olmap.getView()
      var mapCenter = view.getCenter()
      // 让地图中心的y值增加，即可使得地图向下移动，增加的值根据效果可自由设定
      mapCenter[1] += _panFactor
      view.setCenter(mapCenter)
      this.olmap.render()
    },
    getCurrCenter () {
      return this.olmap.getView().getCenter()
    },
    getLevel () {
      return this.olmap.getView().getZoom()
    },
    setExtent (extent) {
      this.olmap.getView().fit([extent.minX, extent.minY, extent.maxX, extent.maxY], this.olmap.getSize())
    },
    getCurrentExtent () {
      var extent = this.olmap.getView().calculateExtent(this.olmap.getSize())
      if (!extent) {
        return null
      }
      return {
        minX: extent[0],
        minY: extent[1],
        maxX: extent[2],
        maxY: extent[3]
      }
    },
    getEventCoordinate (event) {
      return this.olmap.getEventCoordinate(event)
    },
    isInCurrentExtent (x, y) {
      const { ol } = this
      var extent = this.getCurrentExtent()
      return ol.extent.containsXY(extent, x, y)
    },
    toMap (x, y) {
      var pixel = [x, y]
      var coordinate = this.olmap.getCoordinateFromPixel(pixel)
      if (!coordinate) {
        return null
      }
      return {
        x: coordinate[0],
        y: coordinate[1]
      }
    },
    toScreen (x, y) {
      var coordinate = [x, y]
      var pixel = this.olmap.getPixelFromCoordinate(coordinate)
      if (!pixel) {
        return null
      }
      return {
        x: pixel[0],
        y: pixel[1]
      }
    },
    getView () {
      return this.olmap.getView()
    },
    getAllLayers () {
      return this.olmap.getLayers().getArray()
    },
    getAllLayersID () {
      var layerIdArr = []
      var layers = this.getAllLayers()
      layers.forEach(function (_layer) {
        var id = _layer.get('id')
        layerIdArr.push(id)
      })
      return layerIdArr
    },
    getLayer (layerId) {
      var layers = this.getAllLayers()
      var layer = null
      layers.forEach(function (_layer) {
        var id = _layer.get('id')
        if (id === layerId) {
          layer = _layer
        }
      })
      return layer
    },
    isLayerExist (layerid) {
      return this.getLayer(layerid) == null
    },
    zoomIn () {
      this.setLevel(this.getLevel() + 1)
    },
    zoomOut () {
      this.setLevel(this.getLevel() - 1 >= 0 ? (this.getLevel() - 1) : 0)
    },
    addLayer (config) {
      const { ol } = this
      var {
      id,
        name
    } = config
      if (this.getLayer(id)) {
        return this.getLayer(id)
      }
      var layer = new ol.layer.Vector({
        source: new ol.source.Vector()
      })
      layer.set('id', id)
      layer.set('name', name)
      this.olmap.addLayer(layer)
      return layer
    },
    removeLayer (id) {
      this.olmap.removeLayer(this.getLayer(id))
    },
    addControl (control) {
      this.olmap.addControl(control)
    },
    addInteraction (interaction, isActive = false) {
      this.olmap.addInteraction(interaction)
      interaction.setActive(isActive)
    },
    removeControl (control) {
      this.olmap.removeControl(control)
    },
    removeInteraction (interaction) {
      this.olmap.removeInteraction(interaction)
    },
    getInteractions () {
      return this.olmap.getInteractions()
    },
    getControls () {
      return this.olmap.getControls()
    },
    getOverlays () {
      return this.olmap.getOverlays()
    },
    addOverlay (overlay) {
      this.olmap.addOverlay(overlay)
    },
    removeOverlay (overlayer) {
      this.olmap.removeOverlay(overlayer)
    },
    getOverlayById (id) {
      return this.olmap.getOverlayById(id)
    },
    getViewport () {
      return this.olmap.getViewport()
    },
    forEachFeatureAtPixel (pixel, callback) {
      this.olmap.forEachFeatureAtPixel(pixel, function (feature) {
        callback(feature)
      })
    },
    getTargetElement () {
      return this.olmap.getTargetElement()
    },
    getSize () {
      return this.olmap.getSize()
    },
    hasFeatureAtPixel (pix) {
      return this.olmap.hasFeatureAtPixel(pix)
    }
  },
  mounted () {
    this.init()
  }
}
</script>
