/**
 * Mars3D平台插件,结合mapv可视化功能插件  mars3d-mapv
 *
 * 版本信息：v3.4.7
 * 编译日期：2022-09-15 16:25:35
 * 版权所有：Copyright by 火星科技  http://mars3d.cn
 * 使用单位：安徽XX有限公司 ，2021-08-18
 */
(function (global, factory) {
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, (window.mapv || require('mapv')), (window.mars3d || require('mars3d'))) :
  typeof define === 'function' && define.amd ? define(['exports', 'mapv', 'mars3d'], factory) :
  (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["mars3d-mapv"] = {}, global.mapv, global.mars3d));
})(this, (function (exports, mapv, mars3d) { 'use strict';

  function _interopNamespace(e) {
    if (e && e.__esModule) return e;
    var n = Object.create(null);
    if (e) {
      Object.keys(e).forEach(function (k) {
        if (k !== 'default') {
          var d = Object.getOwnPropertyDescriptor(e, k);
          Object.defineProperty(n, k, d.get ? d : {
            enumerable: true,
            get: function () { return e[k]; }
          });
        }
      });
    }
    n["default"] = e;
    return n;
  }

  var mapv__namespace = /*#__PURE__*/_interopNamespace(mapv);
  var mars3d__namespace = /*#__PURE__*/_interopNamespace(mars3d);

  /* eslint-disable no-unused-expressions */

  const Cesium$1 = mars3d__namespace.Cesium;

  const baiduMapLayer = mapv__namespace ? mapv__namespace.baiduMapLayer : null;

  // eslint-disable-next-line no-proto
  const BaseLayer$1 = baiduMapLayer ? baiduMapLayer.__proto__ : Function;

  class MapVRenderer extends BaseLayer$1 {
    //= ========= 构造方法 ==========
    constructor(map, dataset, options, mapVLayer) {
      super(map, dataset, options);
      if (!BaseLayer$1) {
        return
      }

      this.map = map;
      this.scene = map.scene;

      this.dataSet = dataset;
      options = options || {};

      this.init(options);
      this.argCheck(options);
      this.initDevicePixelRatio();
      this.canvasLayer = mapVLayer;
      this.stopAniamation = !1;
      this.animation = options.animation;
      // this.bindEvent()
    }

    //= ========= 方法 ==========
    initDevicePixelRatio() {
      this.devicePixelRatio = window.devicePixelRatio || 1;
    }

    addAnimatorEvent() {}
    animatorMovestartEvent() {
      const t = this.options.animation;
      this.isEnabledTime() && this.animator && (this.steps.step = t.stepsRange.start);
    }

    animatorMoveendEvent() {
      this.isEnabledTime() && this.animator;
    }

    // bindEvent() {
    //   if (this.options.methods.click) {
    //     this.map.on("click", this.clickEvent, this)
    //   }
    //   if (this.options.methods.mousemove) {
    //     this.map.on("mouseMove", this.mousemoveEvent, this)
    //   }
    // }

    // unbindEvent() {
    //   this.map.off("click", this.clickEvent, this)
    //   this.map.off("mouseMove", this.mousemoveEvent, this)
    // }

    // clickEvent(event) {
    //   super.clickEvent(event.windowPosition, event)
    // }

    // mousemoveEvent(event) {
    //   super.mousemoveEvent(event.windowPosition, event)
    // }

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

    init(t) {
      this.options = t;
      this.initDataRange(t);
      this.context = this.options.context || "2d";

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

      this.initAnimator();
    }

    _canvasUpdate(t) {
      const scene = this.scene;
      if (this.canvasLayer && !this.stopAniamation) {
        const i = this.options.animation;
        const n = this.getContext();
        if (this.isEnabledTime()) {
          // eslint-disable-next-line no-void
          if (void 0 === t) {
            // eslint-disable-next-line no-void
            return void this.clear(n)
          }
          this.context === "2d" &&
            (n.save(),
            (n.globalCompositeOperation = "destination-out"),
            (n.fillStyle = "rgba(0, 0, 0, .1)"),
            n.fillRect(0, 0, n.canvas.width, n.canvas.height),
            n.restore());
        } else {
          this.clear(n);
        }
        if (this.context === "2d") {
          for (const o in this.options) {
            n[o] = this.options[o];
          }
        } else {
          n.clear(n.COLOR_BUFFER_BIT);
        }
        const a = {
          transferCoordinate: function (data) {
            const defVal = null; // [-999, -999]

            let heightTerrain = scene.mapvFixedHeight;
            if (scene.mapvAutoHeight) {
              heightTerrain = scene.globe.getHeight(Cesium$1.Cartographic.fromDegrees(data[0], data[1]));
            }

            // 坐标转换
            const position = Cesium$1.Cartesian3.fromDegrees(data[0], data[1], heightTerrain);
            if (!position) {
              return defVal
            }
            const px = scene.cartesianToCanvasCoordinates(position);
            if (!px) {
              return defVal
            }

            // 判断是否在球的背面
            if (scene.mapvDepthTest && scene.mode === Cesium$1.SceneMode.SCENE3D) {
              const occluder = new Cesium$1.EllipsoidalOccluder(scene.globe.ellipsoid, scene.camera.positionWC);
              const visible = occluder.isPointVisible(position);
              // visible为true说明点在球的正面，否则点在球的背面。
              // 需要注意的是不能用这种方法判断点的可见性，如果球放的比较大，点跑到屏幕外面，它返回的依然为true
              if (!visible) {
                return defVal
              }
            }
            // 判断是否在球的背面

            return [px.x, px.y]
          }
        };
        // eslint-disable-next-line no-void
        void 0 !== t &&
          (a.filter = function (e) {
            const n = i.trails || 10;
            return !!(t && e.time > t - n && e.time < t)
          });
        const c = this.dataSet.get(a);
        // eslint-disable-next-line no-sequences
        this.processData(c), this.options.unit === "m" && this.options.size, (this.options._size = this.options.size);

        const h = scene.cartesianToCanvasCoordinates(Cesium$1.Cartesian3.fromDegrees(0, 0));
        if (!h) {
          return
        }

        this.drawContext(n, new mapv__namespace.DataSet(c), this.options, h);
        this.options.updateCallback && this.options.updateCallback(t);
      }
    }

    updateData(t, e) {
      let i = t;
      // eslint-disable-next-line
      i && i.get && (i = i.get()), void 0 !== i && this.dataSet.set(i);

      super.update({
        options: e
      });
    }

    addData(t, e) {
      let i = t;
      // eslint-disable-next-line
      t && t.get && (i = t.get()),
        this.dataSet.add(i),
        this.update({
          options: e
        });
    }

    getData() {
      return this.dataSet
    }

    removeData(t) {
      if (this.dataSet) {
        const e = this.dataSet.get({
          filter: function (e) {
            return t == null || typeof t !== "function" || !t(e)
          }
        });
        this.dataSet.set(e);
        this.update({
          options: null
        });
      }
    }

    clearData() {
      this.dataSet && this.dataSet.clear();
      this.update({
        options: null
      });
    }

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

    clear(t) {
      t && t.clearRect && t.clearRect(0, 0, t.canvas.width, t.canvas.height);
    }

    destroy() {
      // this.unbindEvent()
      this.clear(this.getContext());
      this.clearData();
      this.animator && this.animator.stop();
      this.animator = null;
      this.canvasLayer = null;
    }
  }

  // 修改mapv内部方法，已适应数据在球背面或看不见的区域的数据不显示的处理
  if (mapv__namespace?.DataSet) {
    mapv__namespace.DataSet.prototype.transferCoordinate = function (data, transferFn, fromColumn, toColumnName) {
      toColumnName = toColumnName || "_coordinates";
      fromColumn = fromColumn || "coordinates";

      for (let i = 0; i < data.length; i++) {
        const geometry = data[i].geometry;
        const coordinates = geometry[fromColumn];
        switch (geometry.type) {
          case "Point":
            {
              const pt = transferFn(coordinates);
              if (pt) {
                geometry[toColumnName] = pt;
              } else {
                geometry[toColumnName] = [-999, -999];
              }
            }
            break
          case "LineString":
            {
              const newCoordinates = [];
              for (let j = 0; j < coordinates.length; j++) {
                const pt = transferFn(coordinates[j]);
                if (pt) {
                  newCoordinates.push(pt);
                }
              }
              geometry[toColumnName] = newCoordinates;
            }
            break
          case "MultiLineString":
          case "Polygon":
            {
              const newCoordinates = getPolygon(coordinates);
              geometry[toColumnName] = newCoordinates;
            }
            break
          case "MultiPolygon":
            {
              const newCoordinates = [];
              for (let c = 0; c < coordinates.length; c++) {
                const polygon = getPolygon(coordinates[c]);
                if (polygon.length > 0) {
                  newCoordinates.push(polygon);
                }
              }

              geometry[toColumnName] = newCoordinates;
            }
            break
        }
      }

      function getPolygon(coordinates) {
        const newCoordinates = [];
        for (let c = 0; c < coordinates.length; c++) {
          const coordinate = coordinates[c];
          const newcoordinate = [];
          for (let j = 0; j < coordinate.length; j++) {
            const pt = transferFn(coordinate[j]);
            if (pt) {
              newcoordinate.push(pt);
            }
          }
          if (newcoordinate.length > 0) {
            newCoordinates.push(newcoordinate);
          }
        }
        return newCoordinates
      }

      return data
    };
  } else {
    throw new Error("请引入 mapv 库 ")
  }

  const Cesium = mars3d__namespace.Cesium;
  const BaseLayer = mars3d__namespace.layer.BaseLayer;

  let divId = 0;

  /**
   * MapV图层
   * 【需要引入 mapv.js 库 和 mars3d-mapv 插件库】
   *
   * @param {Object} options 图层参数，包括：
   * @param {Object} [options.data] new mapv.DataSet(data)的data值，如有传入时可以用于替代dataSet参数
   * @param {Boolean} [options.depthTest=true] 是否进行计算深度判断，在地球背面或被遮挡时不显示（大数据时，需要关闭）
   * @param {Number} [options.fixedHeight=0] 点的固定的海拔高度
   * @param {Boolean} [options.clampToGround=false] 点是否贴地
   * @param {*} [options.多个参数] 支持mapv本身所有drawOptions图层样式参数，具体查阅 [mapv库drawOptions文档]{@link https://github.com/huiyan-fe/mapv/wiki/%E7%B1%BB%E5%8F%82%E8%80%83} ，也可以 [在线编辑图层样式]{@link https://mapv.baidu.com/editor/}
   *
   * @param {String|Number} [options.id = createGuid()] 图层id标识
   * @param {String|Number} [options.pid = -1] 图层父级的id，一般图层管理中使用
   * @param {String} [options.name = ''] 图层名称
   * @param {Boolean} [options.show = true] 图层是否显示
   * @param {BaseClass|Boolean} [options.eventParent]  指定的事件冒泡对象，默认为map对象，false时不冒泡
   * @param {Object} [options.center] 图层自定义定位视角 {@link Map#setCameraView}
   * @param {Number} options.center.lng 经度值, 180 - 180
   * @param {Number} options.center.lat 纬度值, -90 - 90
   * @param {Number} [options.center.alt] 高度值
   * @param {Number} [options.center.heading] 方向角度值，绕垂直于地心的轴旋转角度, 0至360
   * @param {Number} [options.center.pitch] 俯仰角度值，绕纬度线旋转角度, -90至90
   * @param {Number} [options.center.roll] 翻滚角度值，绕经度线旋转角度, -90至90
   * @param {Boolean} [options.flyTo] 加载完成数据后是否自动飞行定位到数据所在的区域。
   *
   * @param {*} [dataSet]  mapv.DataSet数据集,可以参考[ MapV数据集对象说明]{@link https://github.com/huiyan-fe/mapv/blob/master/src/data/DataSet.md}
   * @export
   * @class MapVLayer
   * @extends {BaseLayer}
   */
  class MapVLayer extends BaseLayer {
    //= ========= 构造方法 ==========
    constructor(options, dataSet) {
      super(options);

      this._pointerEvents = this.options.pointerEvents;
      this.dataSet = dataSet || new mapv__namespace.DataSet(options.data);

      /**
       * 图层对应的Canvas对象
       * @type {HTMLCanvasElement}
       * @readonly
       */
      this.canvas = null;
    }

    // /**
    //  * 是否可以鼠标交互，为false时可以穿透操作及缩放地图，但无法进行鼠标交互及触发相关事件。true时无法缩放地球，但可以使用mapv相关的事件
    //  * @type {Boolean}
    //  */
    get pointerEvents() {
      return this._pointerEvents
    }

    set pointerEvents(value) {
      this._pointerEvents = value;
      if (this.canvas) {
        if (value) {
          this.canvas.style.pointerEvents = "all";
        } else {
          /* 加上这个css后鼠标可以穿透，但是无法触发单击等鼠标事件 */
          this.canvas.style.pointerEvents = "none";
        }
      }
    }

    //= ========= 方法 ==========
    _showHook(show) {
      if (show) {
        this.canvas.style.display = "block";
      } else {
        this.canvas.style.display = "none";
      }
    }

    /**
     * 对象添加到地图前创建一些对象的钩子方法，
     * 只会调用一次
     * @return {void}  无
     * @private
     */
    _mountedHook() {
      this._map.scene.mapvDepthTest = this.options.depthTest ?? true; // 是否进行计算深度（大数据时，需要关闭）
      this._map.scene.mapvAutoHeight = this.options.clampToGround ?? false;
      this._map.scene.mapvFixedHeight = this.options.fixedHeight ?? 0;
    }

    /**
     * 对象添加到地图上的创建钩子方法，
     * 每次add时都会调用
     * @return {void}  无
     * @private
     */
    _addedHook() {
      if (this.dataSet && (!this.dataSet._data || this.dataSet._data.length === 0)) {
        this.dataSet._data = [].concat(this.dataSet._dataCache);
      }
      this._mapVRenderer = new MapVRenderer(this._map, this.dataSet, this.options, this);

      this.initDevicePixelRatio();
      this.canvas = this._createCanvas();
      this.render = this.render.bind(this);

      this.bindEvent();
      this._reset();
    }

    /**
     * 对象从地图上移除的创建钩子方法，
     * 每次remove时都会调用
     * @return {void}  无
     * @private
     */
    _removedHook() {
      // 释放
      this.unbindEvent();

      if (this._mapVRenderer) {
        this._mapVRenderer.destroy();
        this._mapVRenderer = null;
      }
      this.canvas.parentElement.removeChild(this.canvas);
    }

    initDevicePixelRatio() {
      this.devicePixelRatio = window.devicePixelRatio || 1;
    }

    bindEvent() {
      // 绑定cesium事件与mapv联动
      this._map.on(mars3d__namespace.EventType.mouseDown, this._onMoveStartEvent, this); // 按下
      // this._map.on(mars3d.EventType.mouseUp, this._onMoveEndEvent, this) //释放
      this._map.on(mars3d__namespace.EventType.cameraMoveStart, this._onMoveStartEvent, this);
      this._map.on(mars3d__namespace.EventType.cameraMoveEnd, this._onMoveEndEvent, this);

      if (this.options?.methods?.click) {
        this._map.on(mars3d__namespace.EventType.click, this._onMapClick, this);
      }
      if (this.options?.methods?.mousemove) {
        this._map.on(mars3d__namespace.EventType.mouseMove, this._onMapMouseMove, this);
      }
    }

    unbindEvent() {
      this._map.off(mars3d__namespace.EventType.mouseDown, this._onMoveStartEvent, this); // 按下
      // this._map.off(mars3d.EventType.mouseUp, this._onMoveEndEvent, this) //释放
      this._map.off(mars3d__namespace.EventType.cameraMoveStart, this._onMoveStartEvent, this);
      this._map.off(mars3d__namespace.EventType.cameraMoveEnd, this._onMoveEndEvent, this);

      this._map.off(mars3d__namespace.EventType.postRender, this._reset, this);

      if (this.options?.methods?.click) {
        this._map.off(mars3d__namespace.EventType.click, this._onMapClick, this);
      }
      if (this.options?.methods?.mousemove) {
        this._map.off(mars3d__namespace.EventType.mouseMove, this._onMapMouseMove, this);
      }
    }

    _onMoveStartEvent() {
      if (this._mapVRenderer) {
        this._mapVRenderer.animatorMovestartEvent();

        this._map.off(mars3d__namespace.EventType.postRender, this._reset, this);
        this._map.on(mars3d__namespace.EventType.postRender, this._reset, this);
      }
    }

    _onMoveEndEvent() {
      if (this._mapVRenderer) {
        this._map.off(mars3d__namespace.EventType.postRender, this._reset, this);

        this._mapVRenderer.animatorMoveendEvent();
        this._reset();
      }
    }

    _setOptionsHook(options, newOptions) {
      this._removedHook();
      this._addedHook();
    }

    /**
     * 新增mapv数据
     * @param {*} dataSet  mapv.DataSet数据集,可以参考[ MapV数据集对象说明]{@link https://github.com/huiyan-fe/mapv/blob/master/src/data/DataSet.md}
     * @returns {void} 无
     */
    addData(dataSet) {
      if (this._mapVRenderer) {
        this._mapVRenderer.addData(dataSet, this.options);
      }
    }

    /**
     * 更新mapv数据
     * @param {*} dataSet  mapv.DataSet数据集,可以参考[ MapV数据集对象说明]{@link https://github.com/huiyan-fe/mapv/blob/master/src/data/DataSet.md}
     * @returns {void} 无
     */
    updateData(dataSet) {
      if (this._mapVRenderer) {
        this._mapVRenderer.updateData(dataSet, this.options);
      }
    }

    /**
     * 获取数据
     * @return {*} mapv.DataSet数据集,可以参考[ MapV数据集对象说明]{@link https://github.com/huiyan-fe/mapv/blob/master/src/data/DataSet.md}
     */
    getData() {
      if (this._mapVRenderer) {
        this.dataSet = this._mapVRenderer.getData();
      }
      return this.dataSet
    }

    /**
     * 删除指定数据
     * @param {*} data  mapv.DataSet数据集
     * @returns {void} 无
     */
    removeData(data) {
      if (this._mapVRenderer) {
        this._mapVRenderer.removeData(data);
      }
    }

    /**
     * 删除所有数据
     * @returns {void} 无
     */
    removeAllData() {
      if (this._mapVRenderer) {
        this._mapVRenderer.clearData();
      }
    }

    _createCanvas() {
      const container = mars3d__namespace.DomUtil.create("canvas", "mars3d-mapv", this._map.container);
      container.id = this.options.layerid || "mapv" + divId++;
      container.style.position = "absolute";
      container.style.top = "0px";
      container.style.left = "0px";
      container.style.pointerEvents = this._pointerEvents ? "auto" : "none"; // auto时可以交互，但是没法放大地球, none没法交互
      container.style.zIndex = this.options.zIndex || 100;
      container.width = parseInt(this._map.canvas.width);
      container.height = parseInt(this._map.canvas.height);
      container.style.width = this._map.canvas.style.width;
      container.style.height = this._map.canvas.style.height;

      if (this.options.context === "2d") {
        const e = this.devicePixelRatio;
        container.getContext(this.options.context).scale(e, e);
      }
      return container
    }

    _reset() {
      this.resize();
      this.render();
    }

    /**
     * 重绘图层
     * @return {void}  无
     */
    draw() {
      this._reset();
    }

    remove() {
      if (this._mapVRenderer) {
        this._mapVRenderer.destroy();
        this._mapVRenderer = null;
      }
      this.canvas.parentElement.removeChild(this.canvas);
    }

    render() {
      this._mapVRenderer._canvasUpdate();
    }

    /**
     * 改变图层canvas容器尺寸
     * @return {void}  无
     */
    resize() {
      if (this.canvas) {
        const container = this.canvas;
        container.style.position = "absolute";
        container.style.top = "0px";
        container.style.left = "0px";
        container.width = parseInt(this._map.canvas.width);
        container.height = parseInt(this._map.canvas.height);
        container.style.width = this._map.canvas.style.width;
        container.style.height = this._map.canvas.style.height;
      }
    }

    /**
     * 获取图层内所有数据的 矩形边界值
     * @param {Boolean} [options] 控制参数
     * @param {Boolean} [options.isFormat=false] 是否格式化，格式化时示例： { xmin: 73.16895, xmax: 134.86816, ymin: 12.2023, ymax: 54.11485 }
     * @return {Cesium.Rectangle|Object} isFormat：true时，返回格式化对象，isFormat：false时返回Cesium.Rectangle对象
     */
    getRectangle(options) {
      if (!this.dataSet || !this.dataSet._data) {
        return
      }

      const extent = mars3d__namespace.Util.getExtentByGeoJSON({ type: "FeatureCollection", features: this.dataSet._data });
      if (!extent) {
        return
      }

      if (options?.isFormat) {
        return extent
      } else {
        return Cesium.Rectangle.fromDegrees(extent.xmin, extent.ymin, extent.xmax, extent.ymax)
      }
    }

    /// /////////////////事件相关//////////////////////
    _onMapClick(event) {
      this._cache_event = event;
      if (this._mapVRenderer) {
        this._mapVRenderer.clickEvent(event.windowPosition, event);
      }
    }

    _onMapMouseMove(event) {
      this._cache_event = event;
      if (this._mapVRenderer) {
        this._mapVRenderer.mousemoveEvent(event.windowPosition, event);
      }
    }

    /**
     * 绑定事件处理函数,
     *
     * @param {String} eventName  事件名称，全小写，例如'click'，'mouseMove'
     * @param {Function} callback 绑定的监听器回调方法
     * @param {Object} [context]  侦听器的上下文(this关键字将指向的对象)。
     * @return {EchartsLayer} 当前对象本身,可以链式调用
     */
    on(eventName, callback, context) {
      this.options.methods = this.options.methods || {};

      if (eventName === mars3d__namespace.EventType.click) {
        this.options.methods.click = (e) => {
          if (e) {
            callback.bind(context)({ ...this._cache_event, layer: this, data: e });
          }
        };
        this._map.on(mars3d__namespace.EventType.click, this._onMapClick, this);
      } else if (eventName === mars3d__namespace.EventType.mouseMove) {
        this.options.methods.mousemove = (e) => {
          if (e) {
            callback.bind(context)({ ...this._cache_event, layer: this, data: e });
          }
        };
        this._map.on(mars3d__namespace.EventType.mouseMove, this._onMapMouseMove, this);
      }
      return this
    }

    /**
     * 解除绑定指定类型事件监听器
     *
     * @param {String} eventName  事件名称，全小写，例如'click'，'mouseMove'
     * @param {Function} [callback] 绑定的监听器回调方法,未传值时解绑所有指定类型对应事件
     * @return {EchartsLayer} 当前对象本身,可以链式调用
     */
    off(eventName, callback) {
      if (eventName === "click") {
        this._map.off(eventName, this._onMapClick, this);
        if (this.options.methods?.mousemove) {
          delete this.options.methods.click;
        }
      } else if (eventName === "mouseMove") {
        this._map.off(eventName, this._onMapMouseMove, this);
        if (this.options.methods?.mousemove) {
          delete this.options.methods.mousemove;
        }
      }
      return this
    }
  }

  // 注册下
  mars3d__namespace.LayerUtil.register("mapv", MapVLayer);

  mars3d__namespace.layer.MapVLayer = MapVLayer;

  exports.MapVLayer = MapVLayer;
  Object.keys(mapv).forEach(function (k) {
    if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, {
      enumerable: true,
      get: function () { return mapv[k]; }
    });
  });

  Object.defineProperty(exports, '__esModule', { value: true });

}));
