    const mapv = window.mapv || {}
    const Layer = mapv.baiduMapLayer ? mapv.baiduMapLayer.__proto__ : Function

    /**
     * @private
     * @class MapvBaseLayer
     * @classdesc MapV图层渲染
     * @param map - {string} 地图
     * @param layer -{Object} 图层
     * @param dataSet -{Object} 数据集
     * @param options -{Object} 交互时所需可选参数。
     * @see https://github.com/huiyan-fe/mapv/blob/master/API.md
     * @extends Layer
     *
     */
    export default class MapvBaseLayer extends Layer {
      constructor(map, dataSet, options, cesiumLayer) {
        super(map, dataSet, options)

        if (!Layer) return

        this.map = map // 此处的map是外面传入的cesium的map对象
        this.scene = map.scene
        this.dataSet = dataSet

        const self = this
        const data = null
        options = options || {}

        self.init(options)
        self.argCheck(options)

        this.initDevicePixelRatio()

        this.canvasLayer = cesiumLayer

        this.stopAniamation = false
        this.animation = options.animation

        this.clickEvent = this.clickEvent.bind(this)
        this.mousemoveEvent = this.mousemoveEvent.bind(this)

        this.bindEvent()
      }

      /**
       * @function cesium.zondy.MapvBaseLayer.prototype.initDevicePixelRatio
       * @description window.devicePixelRatio是设备上物理像素和设备独立像素(device-independent pixels (dips))的比例。
       * 公式表示就是：window.devicePixelRatio = 物理像素 / dips,该函数主要应用与移动设备
       */
      initDevicePixelRatio() {
        this.devicePixelRatio = window.devicePixelRatio || 1
      }

      clickEvent(e) {
        const pixel = e.point
        super.clickEvent(pixel, e)
      }

      mousemoveEvent(e) {
        const pixel = e.point
        super.mousemoveEvent(pixel, e)
      }

      addAnimatorEvent() {}

      animatorMovestartEvent() {
        const animationOptions = this.options.animation
        if (this.isEnabledTime() && this.animator) {
          this.steps.step = animationOptions.stepsRange.start
          // this.animator.stop();
        }
      }

      animatorMoveendEvent() {
        if (this.isEnabledTime() && this.animator) {
          // this.animator.start();
        }
      }

      bindEvent() {
        const map = this.map
        if (this.options.methods) {
          if (this.options.methods.click) {
            // map.on('click', this.clickEvent);
          }
          if (this.options.methods.mousemove) {
            // map.on('mousemove', this.mousemoveEvent);
          }
        }
      }

      unbindEvent() {
        const map = this.map

        if (this.options.methods) {
          if (this.options.methods.click) {
            map.off('click', this.clickEvent)
          }
          if (this.options.methods.mousemove) {
            map.off('mousemove', this.mousemoveEvent)
          }
        }
      }

      getContext() {
        return this.canvasLayer.canvas.getContext(this.context)
      }

      init(options) {
        const self = this

        self.options = options

        this.initDataRange(options)

        this.context = self.options.context || '2d'

        if (self.options.zIndex) {
          this.canvasLayer && this.canvasLayer.setZIndex(self.options.zIndex)
        }

        this.initAnimator()
      }

      _canvasUpdate(time) {
        const map = this.map
        const scene = this.scene
        if (!this.canvasLayer || this.stopAniamation) {
          return
        }
        const self = this

        const animationOptions = self.options.animation

        const context = self.getContext()

        if (self.isEnabledTime()) {
          if (time === undefined) {
            this.clear(context)
            return
          }
          if (this.context === '2d') {
            context.save()
            context.globalCompositeOperation = 'destination-out'
            context.fillStyle = 'rgba(0, 0, 0, .1)'
            context.fillRect(0, 0, context.canvas.width, context.canvas.height)
            context.restore()
          }
        } else {
          this.clear(context)
        }

        if (this.context === '2d') {
          for (const key in self.options) {
            context[key] = self.options[key]
          }
        } else {
          context.clear(context.COLOR_BUFFER_BIT)
        }

        const dataGetOptions = {
          transferCoordinate(coordinate) {
            const pointSphere = Cesium.Cartesian3.fromDegrees(
              coordinate[0],
              coordinate[1]
            )
            var position = self.map.camera.position
            let cameraHeight =
              self.map.scene.globe.ellipsoid.cartesianToCartographic(
                position
              ).height
            cameraHeight += self.map.scene.globe.ellipsoid.maximumRadius * 1.2
            const distance = Cesium.Cartesian3.distance(position, pointSphere)
            if (distance > cameraHeight) {
              return undefined
              // return [-50, -50];
            }

            var position = Cesium.Cartesian3.fromDegrees(
              coordinate[0],
              coordinate[1]
            )
            const point = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
              self.map.scene,
              position
            )
            if (!point) return [0, 0]
            return [point.x, point.y]
          }
        }

        if (time !== undefined) {
          dataGetOptions.filter = function (item) {
            const trails = animationOptions.trails || 10
            if (time && item.time > time - trails && item.time < time) {
              return true
            } else {
              return false
            }
          }
        }

        const data = self.dataSet.get(dataGetOptions)

        this.processData(data)

        if (self.options.unit == 'm' && self.options.size) {
          // self.options._size = self.options.size / zoomUnit;
          self.options._size = self.options.size
        } else {
          self.options._size = self.options.size
        }

        let pixel = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
          scene,
          Cesium.Cartesian3.fromDegrees(0, 0)
        )
        if (!pixel) pixel = [0, 0]
        this.drawContext(context, new mapv.DataSet(data), self.options, pixel)

        self.options.updateCallback && self.options.updateCallback(time)
      }

      updateData(data, options) {
        let _data = data
        if (_data && _data.get) {
          _data = _data.get()
        }
        if (_data != undefined) {
          this.dataSet.set(_data)
        }

        super.update({
          options
        })
      }

      addData(data, options) {
        let _data = data
        if (data && data.get) {
          _data = data.get()
        }
        this.dataSet.add(_data)
        this.update({
          options
        })
      }

      getData() {
        return this.dataSet
      }

      removeData(filter) {
        if (!this.dataSet) {
          return
        }
        const newData = this.dataSet.get({
          filter(data) {
            return filter != null && typeof filter === 'function'
              ? !filter(data)
              : true
          }
        })
        this.dataSet.set(newData)
        this.stopAniamation = true
        /* this.update({
            options: null
        }); */
      }

      clearData() {
        this.dataSet && this.dataSet.clear()
        this.stopAniamation = true
        /* this.update({
            options: null
        }); */
      }

      draw() {
        this.canvasLayer.draw()
      }

      // 该函数从mapv/canvas/clear中提取
      clear(context) {
        context &&
          context.clearRect &&
          context.clearRect(0, 0, context.canvas.width, context.canvas.height)
      }
    }