/** * Mars3D平台插件,结合echarts可视化功能插件 mars3d-echarts * * 版本信息: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.echarts || require('echarts')), (window.mars3d || require('mars3d'))) : typeof define === 'function' && define.amd ? define(['exports', 'echarts', 'mars3d'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["mars3d-echarts"] = {}, global.echarts, global.mars3d)); })(this, (function (exports, echarts, 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 echarts__namespace = /*#__PURE__*/_interopNamespace(echarts); var mars3d__namespace = /*#__PURE__*/_interopNamespace(mars3d); const Cesium$1 = mars3d__namespace.Cesium; // 地图坐标系统类。参考了开源:https://github.com/sharpzao/EchartsCesium class CompositeCoordinateSystem { //= ========= 构造方法 ========== constructor(scene, api) { this._mars3d_scene = scene; this.dimensions = ["lng", "lat"]; this._mapOffset = [0, 0]; this._api = api; } //= ========= 方法 ========== setMapOffset(mapOffset) { this._mapOffset = mapOffset; } getBMap() { return this._mars3d_scene } dataToPoint(data) { const scene = this._mars3d_scene; const defVal = [NaN, NaN]; // echarts内部就是用NaN来做判断的 let heightTerrain = scene.echartsFixedHeight; if (scene.echartsAutoHeight) { 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 = Cesium$1.SceneTransforms.wgs84ToWindowCoordinates(scene, position); // var px = scene.cartesianToCanvasCoordinates(position); if (!px) { return defVal } // 判断是否在球的背面 if (scene.echartsDepthTest && 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 - this._mapOffset[0], px.y - this._mapOffset[1]] } getViewRect() { const api = this._api; return new echarts__namespace.graphic.BoundingRect(0, 0, api.getWidth(), api.getHeight()) } getRoamTransform() { return echarts__namespace.matrix.create() } } // 用于确定创建列表数据时要使用的维度 CompositeCoordinateSystem.dimensions = ["lng", "lat"]; CompositeCoordinateSystem.create = function (ecModel, api) { let coordSys; const scene = ecModel.scheduler.ecInstance._mars3d_scene; ecModel.eachComponent("mars3dMap", function (mars3dMapModel) { const painter = api.getZr().painter; if (!painter) { return } if (!coordSys) { coordSys = new CompositeCoordinateSystem(scene, api); } mars3dMapModel.coordinateSystem = coordSys; coordSys.setMapOffset(mars3dMapModel.__mapOffset || [0, 0]); }); ecModel.eachSeries(function (seriesModel) { if (seriesModel.get("coordinateSystem") === "mars3dMap") { if (!coordSys) { coordSys = new CompositeCoordinateSystem(scene, api); } seriesModel.coordinateSystem = coordSys; } }); }; /// //////扩展echarts/////////// if (echarts__namespace?.init) { echarts__namespace.registerCoordinateSystem("mars3dMap", CompositeCoordinateSystem); echarts__namespace.registerAction( { type: "mars3dMapRoam", event: "mars3dMapRoam", update: "updateLayout" }, function (payload, ecModel) {} ); echarts__namespace.extendComponentModel({ type: "mars3dMap", getBMap: function () { return this._mars3d_scene }, defaultOption: { roam: false } }); echarts__namespace.extendComponentView({ type: "mars3dMap", init: function (ecModel, api) { this.api = api; this.scene = ecModel.scheduler.ecInstance._mars3d_scene; this.scene.postRender.addEventListener(this.moveHandler, this); }, moveHandler: function (type, target) { this.api.dispatchAction({ type: "mars3dMapRoam" }); }, render: function (mars3dMapModel, ecModel, api) {}, dispose: function (target) { this.scene.postRender.removeEventListener(this.moveHandler, this); } }); } else { throw new Error("请引入 echarts 库 ") } const Cesium = mars3d__namespace.Cesium; const BaseLayer = mars3d__namespace.layer.BaseLayer; let _div_zIndex = 999; /** * Echarts图层, * 【需要引入 echarts 库 和 mars3d-echarts 插件库】 * * @param {Object} [options] 参数对象,包括以下: * @param {Object} [options.Echarts本身] 支持Echarts本身所有Options参数,具体查阅 [Echarts配置项手册]{@link https://echarts.apache.org/zh/option.html} * * @param {Boolean} [options.depthTest=true] 是否进行计算深度判断,在地球背面或被遮挡时不显示(大数据时,需要关闭) * @param {Number} [options.fixedHeight=0] 点的固定的海拔高度 * @param {Boolean} [options.clampToGround=false] 点是否贴地 * @param {Boolean} [options.pointerEvents=false] 图层是否可以进行鼠标交互,为false时可以穿透操作及缩放地图 * * * @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] 加载完成数据后是否自动飞行定位到数据所在的区域。 * @export * @class EchartsLayer * @extends {BaseLayer} */ class EchartsLayer extends BaseLayer { constructor(options = {}) { super(options); this._pointerEvents = this.options.pointerEvents; } /** * echarts对象,是echarts.init方法返回的 echartsInstance 实例 * @type {HTMLCanvasElement} * @readonly * @see https://echarts.apache.org/zh/api.html#echartsInstance */ get layer() { return this._echartsInstance } /** * 是否可以鼠标交互,为false时可以穿透操作及缩放地图,但无法进行鼠标交互及触发相关事件。true时无法缩放地球,但可以使用echarts相关的事件或toolitp等。 * @type {Boolean} */ get pointerEvents() { return this._pointerEvents } set pointerEvents(value) { this._pointerEvents = value; if (this._echartsContainer) { if (value) { this._echartsContainer.style.pointerEvents = "all"; } else { /* 加上这个css后鼠标可以穿透,但是无法触发单击等鼠标事件 */ this._echartsContainer.style.pointerEvents = "none"; } } } _setOptionsHook(options, newOptions) { this.setEchartsOption(options); } _showHook(show) { if (show) { this._echartsContainer.style.visibility = "visible"; } else { this._echartsContainer.style.visibility = "hidden"; } } /** * 对象添加到地图前创建一些对象的钩子方法, * 只会调用一次 * @return {void} 无 * @private */ _mountedHook() { this._map.scene.echartsDepthTest = this.options.depthTest ?? true; // 是否进行计算深度(大数据时,需要关闭) this._map.scene.echartsAutoHeight = this.options.clampToGround ?? false; this._map.scene.echartsFixedHeight = this.options.fixedHeight ?? 0; } /** * 对象添加到地图上的创建钩子方法, * 每次add时都会调用 * @return {void} 无 * @private */ _addedHook() { this._echartsContainer = this._createChartOverlay(); this._echartsInstance = echarts__namespace.init(this._echartsContainer); this._echartsInstance._mars3d_scene = this._map.scene; this.setEchartsOption(this.options); } /** * 对象从地图上移除的创建钩子方法, * 每次remove时都会调用 * @return {void} 无 * @private */ _removedHook() { if (this._echartsInstance) { this._echartsInstance.clear(); this._echartsInstance.dispose(); delete this._echartsInstance; } if (this._echartsContainer) { this._map.container.removeChild(this._echartsContainer); delete this._echartsContainer; } } _createChartOverlay() { const scene = this._map.scene; scene.canvas.setAttribute("tabIndex", 0); const chartContainer = mars3d__namespace.DomUtil.create("div", "mars3d-echarts", this._map.container); chartContainer.style.position = "absolute"; chartContainer.style.top = "0px"; chartContainer.style.left = "0px"; chartContainer.style.width = scene.canvas.clientWidth + "px"; chartContainer.style.height = scene.canvas.clientHeight + "px"; chartContainer.style.pointerEvents = this._pointerEvents ? "all" : "none"; // auto时可以交互,但是没法放大地球, none 没法交互 chartContainer.style.zIndex = this.options.zIndex || _div_zIndex++; return chartContainer } /** * 改变图层canvas容器尺寸,在容器大小发生改变时需要手动调用。 * @return {void} 无 * @see https://echarts.apache.org/zh/api.html#echartsInstance.resize */ resize() { if (!this._echartsInstance) { return } const scene = this._map.scene; this._echartsContainer.style.width = scene.canvas.clientWidth + "px"; this._echartsContainer.style.height = scene.canvas.clientHeight + "px"; this._echartsInstance.resize(); } /** * 设置图表实例的配置项以及数据, * 万能接口,所有参数和数据的修改都可以通过 setOption 完成, * ECharts 会合并新的参数和数据,然后刷新图表。 * 如果开启动画的话,ECharts 找到两组数据之间的差异然后通过合适的动画去表现数据的变化。 * @param {Object} option 图表的配置项和数据,具体见 [Echarts配置项手册]{@link https://echarts.apache.org/zh/option.html}。 * @param {Boolean} [notMerge=false] 是否不跟之前设置的 option 进行合并。默认为 false。即表示合并。合并的规则,详见 组件合并模式。如果为 true,表示所有组件都会被删除,然后根据新 option 创建所有新组件。 * @param {Boolean} [lazyUpdate=false] 在设置完 option 后是否不立即更新图表,默认为 false,即同步立即更新。如果为 true,则会在下一个 animation frame 中,才更新图表。 * @return {void} 无 * @see https://echarts.apache.org/zh/api.html#echartsInstance.setOption */ setEchartsOption(option, notMerge, lazyUpdate) { if (this._echartsInstance) { option.mars3dMap = option.mars3dMap || {}; // 需要注册 this._echartsInstance.setOption(option, notMerge, lazyUpdate); } } /** * 获取图层内所有数据的 矩形边界值 * @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) { let xmin, xmax, ymin, ymax; function refPoint(coors) { if (!Array.isArray(coors)) { return } const lng = coors[0] || 0; const lat = coors[1] || 0; if (lng !== 0 && lat !== 0) { if (xmin === undefined) { xmin = lng; xmax = lng; ymin = lat; ymax = lat; } else { xmin = Math.min(xmin, lng); xmax = Math.max(xmax, lng); ymin = Math.min(ymin, lat); ymax = Math.max(ymax, lat); } } } const series = this.options.series; if (series) { series.forEach((serie) => { if (serie.data) { serie.data.forEach((item) => { if (item.value) { refPoint(item.value); } else if (item.coords) { item.coords.forEach((coord) => { refPoint(coord); }); } }); } }); } if (xmin === 0 && ymin === 0 && xmax === 0 && ymax === 0) { return null } if (options?.isFormat) { return { xmin: xmin, xmax: xmax, ymin: ymin, ymax: ymax } } else { return Cesium.Rectangle.fromDegrees(xmin, ymin, xmax, ymax) } } /// /////////////////事件相关////////////////////// /** * 绑定事件处理函数, * * @param {String} eventName 事件名称,全小写,例如'click','mousemove', 'legendselected' ,可以参考[echarts官网说明]{@link https://echarts.apache.org/zh/api.html#echartsInstance.on} * @param {Function} callback 绑定的监听器回调方法 * @param {Object} [context] 侦听器的上下文(this关键字将指向的对象)。 * @return {EchartsLayer} 当前对象本身,可以链式调用 */ on(eventName, callback, context) { this._echartsInstance.on(eventName, callback, context || this); return this } /** * 带条件的绑定事件处理函数 * @param {String} eventName 事件名称,全小写,例如'click','mousemove', 'legendselected' * @param {String|Object} query 可选的过滤条件,能够只在指定的组件或者元素上进行响应。可以参考[echarts官网说明]{@link https://echarts.apache.org/zh/api.html#echartsInstance.on} * @param {Function} callback 绑定的监听器回调方法 * @param {Object} [context] 侦听器的上下文(this关键字将指向的对象) * @return {EchartsLayer} 当前对象本身,可以链式调用 */ onByQuery(eventName, query, callback, context) { this._echartsInstance.on(eventName, query, callback, context || this); return this } /** * 解除绑定指定类型事件监听器 * * @param {String} eventName 事件名称,全小写,例如'click','mousemove', 'legendselected' * @param {Function} [callback] 绑定的监听器回调方法,未传值时解绑所有指定类型对应事件 * @param {Object} [context] 侦听器的上下文(this关键字将指向的对象)。 * @return {EchartsLayer} 当前对象本身,可以链式调用 */ off(eventName, callback, context) { this._echartsInstance.off(eventName, callback, context || this); return this } } // 注册下 mars3d__namespace.LayerUtil.register("echarts", EchartsLayer); mars3d__namespace.layer.EchartsLayer = EchartsLayer; exports.EchartsLayer = EchartsLayer; Object.keys(echarts).forEach(function (k) { if (k !== 'default' && !exports.hasOwnProperty(k)) Object.defineProperty(exports, k, { enumerable: true, get: function () { return echarts[k]; } }); }); Object.defineProperty(exports, '__esModule', { value: true }); }));