yi-map-web 1.0.2 → 1.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"yi-map-web.mjs","sources":["../src/components/mars-work/expand/task/CameraList.js","../src/components/mars-work/expand/task/CameraView.js","../src/components/mars-work/expand/task/MapRotate.js","../src/components/mars-work/expand/task/PointRotate.js","../src/components/mars-work/expand/task/RouteLine.js","../src/components/mars-work/expand/task/ZoomIn.js","../src/components/mars-work/expand/task/ZoomOut.js","../src/components/mars-work/expand/task/FlickerEntity.js","../src/components/mars-work/expand/graphic/CanvasBillboard.js","../src/components/mars-work/mars-map.vue","../src/components/mars-map/panels/ToolbarPanel.vue","../src/components/mars-map/panels/VisionPanel.vue","../src/components/mars-map/composables/useMap.ts","../src/components/mars-map/composables/useMeasure.ts","../src/components/mars-map/composables/useDraw.ts","../src/components/mars-map/composables/useVision.ts","../src/components/mars-map/MarsMapContainer.vue","../src/components/business/poi-marker/usePoiMarker.ts","../src/components/business/poi-marker/PoiMarkerLayer.vue","../src/components/business/poi-marker/PoiMarkerPanel.vue","../src/components/business/track/useTrack.ts","../src/components/business/track/TrackLayer.vue","../src/components/business/track/TrackPanel.vue","../src/index.ts"],"sourcesContent":["import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 视角列表播放(分步执行)\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n * @param {object[]} [options.list] 视角数组\r\n */\r\nexport class CameraList extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraViewList(this.options.list)\r\n }\r\n\r\n // 暂停(非必须)\r\n _pauseWork() {\r\n this._disableWork()\r\n }\r\n}\r\nmars3d.thing.Task.register(\"cameraList\", CameraList)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 单个视角定位\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.center] 视角参数\r\n */\r\nexport class CameraView extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraView(this.options.center, { duration: this._duration })\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n this._map.cancelFlyTo()\r\n }\r\n}\r\nmars3d.thing.Task.register(\"camera\", CameraView)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 地球自旋转\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.center] 初始视角\r\n * @param {number} [options.speed] 旋转速度\r\n */\r\nexport class MapRotate extends mars3d.TaskItem {\r\n constructor(options = {}) {\r\n super(options)\r\n\r\n this._speed = this.options.speed || 0.01\r\n this._center = this.options.center || { lat: 29.093038, lng: 108.804459, alt: 23321232.7, heading: 0, pitch: -90 }\r\n }\r\n\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraView(this._center, {\r\n duration: 1,\r\n complete: () => {\r\n this._map.on(mars3d.EventType.clockTick, this._map_onClockTick, this)\r\n }\r\n })\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n this._map.off(mars3d.EventType.clockTick, this._map_onClockTick, this)\r\n }\r\n\r\n _map_onClockTick() {\r\n if (this.isPause) {\r\n return // 暂停时不执行\r\n }\r\n\r\n this._map.scene.camera.rotate(mars3d.Cesium.Cartesian3.UNIT_Z, this._speed)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"mapRotate\", MapRotate)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 内或外旋转\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {boolean} [options.isRotateOut] true:绕外旋转 ,false:绕内旋转\r\n * @param {boolean} [options.direction=false] 旋转方向, true逆时针,false顺时针\r\n * @param {number} [options.time=60] 飞行一周所需时间(单位 秒),控制速度\r\n * @param {boolean} [options.autoStop] 是否自动停止\r\n * @param {number} [options.autoStopAngle] 自动停止的角度值(0-360度),未设置时不自动停止\r\n * @param {object} [options.point] 绕点旋转对应的中心点位置\r\n */\r\nexport class PointRotate extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n if (this.options.center) {\r\n this._map.setCameraView(this.options.center, { duration: 0 })\r\n }\r\n\r\n if (this.options.autoStop) {\r\n delete this.options.autoStopAngle // 是否自动停止\r\n }\r\n\r\n if (this.options.isRotateOut) {\r\n this._rotateOut = new mars3d.thing.RotateOut(this.options)\r\n this._map.addThing(this._rotateOut)\r\n } else {\r\n this._rotatePoint = new mars3d.thing.RotatePoint(this.options)\r\n this._map.addThing(this._rotatePoint)\r\n }\r\n\r\n if (this.options.isRotateOut) {\r\n this._rotateOut.start()\r\n } else {\r\n this._rotatePoint.start(this.options.point)\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._rotatePoint) {\r\n this._rotatePoint.stop()\r\n this._rotatePoint.destroy()\r\n delete this._rotatePoint\r\n }\r\n if (this._rotateOut) {\r\n this._rotateOut.stop()\r\n this._rotateOut.destroy()\r\n delete this._rotateOut\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"pointRotate\", PointRotate)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 按路线漫游\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.route] FixedRoute对应的构造参数\r\n */\r\nexport class RouteLine extends mars3d.TaskItem {\r\n // constructor(options) {\r\n // super(options)\r\n // }\r\n\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._graphicLayer = new mars3d.layer.GraphicLayer()\r\n this._map.addLayer(this._graphicLayer)\r\n\r\n const fixedRoute = new mars3d.graphic.FixedRoute(this.options.route)\r\n this._graphicLayer.addGraphic(fixedRoute)\r\n this._fixedRoute = fixedRoute\r\n\r\n fixedRoute.start()\r\n }\r\n\r\n // 暂停(非必须)\r\n _pauseWork(options) {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.pause()\r\n }\r\n }\r\n\r\n // 继续(非必须)\r\n _proceedWork() {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.proceed()\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.stop()\r\n delete this._fixedRoute\r\n }\r\n\r\n if (this._graphicLayer) {\r\n this._graphicLayer.destroy()\r\n delete this._graphicLayer\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"routeLine\", RouteLine)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 放大地图\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {number} [options.relativeAmount=2] 相对量\r\n */\r\nexport class ZoomIn extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.zoomIn(this.options.relativeAmount)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"zoomIn\", ZoomIn)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 缩小地图\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {number} [options.relativeAmount=2] 相对量\r\n */\r\nexport class ZoomOut extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.zoomOut(this.options.relativeAmount)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"zoomOut\", ZoomOut)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 矢量对象高亮闪烁(仅Entity)\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {string|number} [options.layerId] 图层ID\r\n * @param {string|number} [options.graphicId] 矢量对象ID\r\n *\r\n * @param {number} [options.step=10] 闪烁增量, 控制速度\r\n * @param {string} [options.color] 高亮的颜色\r\n * @param {number} [options.maxAlpha=0.3] 闪烁的最大透明度,从 0 到 maxAlpha 渐变\r\n */\r\nexport class FlickerEntity extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n const layer = this._map.getLayerById(this.options.layerId)\r\n if (layer) {\r\n layer.show = true\r\n layer.readyPromise.then(() => {\r\n this._graphic = layer.getGraphicById(this.options.graphicId)\r\n if (this._graphic) {\r\n this._graphic.show = true\r\n this._graphic.startFlicker({\r\n time: this._duration,\r\n step: this.options.step,\r\n maxAlpha: this.options.maxAlpha,\r\n color: this.options.color\r\n })\r\n }\r\n })\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._graphic) {\r\n this._graphic.stopFlicker()\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"flickerEntity\", FlickerEntity)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n// 通过Canvas绘制复杂或动态对象的图标点Graphic\r\nexport class CanvasBillboard extends mars3d.graphic.BillboardPrimitive {\r\n /**\r\n * 文字\r\n * @type {string}\r\n */\r\n get text() {\r\n return this.style.text\r\n }\r\n\r\n set text(val) {\r\n this.style.text = val\r\n\r\n this.label.text = val\r\n }\r\n\r\n /**\r\n * 对象添加到图层前创建一些对象的钩子方法,\r\n * 只会调用一次\r\n * @return {Promise<object>} 无\r\n * @private\r\n */\r\n _addedHook(style) {\r\n style.image = \"//data.mars3d.cn/img/marker/bg/textPnl.png\"\r\n style.label = {\r\n ...style,\r\n text: this.style.text,\r\n font_size: 55,\r\n color: style.textColor ?? \"#ffffff\",\r\n hasPixelOffset: true,\r\n pixelOffsetX: 0,\r\n pixelOffsetY: -36 * (style.scale ?? 1)\r\n }\r\n if (style.scaleByDistance) {\r\n style.label.pixelOffsetScaleByDistance = style.scaleByDistance\r\n }\r\n\r\n super._addedHook(style)\r\n }\r\n}\r\n\r\n// 注册下\r\nmars3d.GraphicUtil.register(\"canvasBillboard\", CanvasBillboard)\r\n","<!--\r\n 地图渲染组件\r\n-->\r\n\r\n<template>\r\n <div :id=\"withKeyId\" class=\"mars3d-container\"></div>\r\n</template>\r\n<script setup lang=\"ts\">\r\nimport * as mars3d from \"mars3d\";\r\nimport \"./expand/index\"; // 引入插件或注册扩展js\r\n\r\nimport { computed, onUnmounted, onMounted, toRaw } from \"vue\";\r\n// import { $alert, $message } from \"@mars/components/mars-ui/index\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n mapKey?: string; // 多个地图时,可传入key区分地图\r\n url?: string; // 传入的地图构造参数url,可为空,只传options\r\n options?: any; // 传入的地图构造参数options,可覆盖url内的参数\r\n }>(),\r\n {\r\n mapKey: \"default\",\r\n url: undefined,\r\n options: undefined,\r\n },\r\n);\r\n\r\n// 用于存放地球组件实例\r\nlet map: mars3d.Map; // 地图对象\r\n\r\n// 使用用户传入的 mapKey 拼接生成 withKeyId 作为当前显示容器的id\r\nconst withKeyId = computed(() => `mars3d-container-${props.mapKey}`);\r\n\r\n// onload事件将在地图渲染后触发\r\nconst emit = defineEmits([\"onload\"]);\r\n\r\nconst initMars3d = async () => {\r\n // 获取配置\r\n let mapOptions;\r\n if (props.url) {\r\n // 存在url时才读取\r\n mapOptions = await mars3d.Util.fetchJson({ url: props.url });\r\n if (props.options) {\r\n mapOptions = mars3d.Util.merge(mapOptions, toRaw(props.options)); // 合并配置\r\n }\r\n } else if (props.options) {\r\n mapOptions = toRaw(props.options);\r\n }\r\n // console.log(\"Map地图构造参数\", mapOptions);\r\n\r\n // 禁用控制台版权信息输出\r\n (mars3d as any).Util.showCopyright = false;\r\n\r\n map = new mars3d.Map(withKeyId.value, mapOptions);\r\n\r\n // 针对不同终端的优化配置\r\n if (mars3d.Util.isPCBroswer()) {\r\n map.zoomFactor = 2.0; // 鼠标滚轮放大的步长参数\r\n\r\n // IE浏览器优化\r\n if (window.navigator.userAgent.toLowerCase().indexOf(\"msie\") >= 0) {\r\n map.viewer.targetFrameRate = 20; // 限制帧率\r\n map.scene.requestRenderMode = false; // 取消实时渲染\r\n }\r\n } else {\r\n map.zoomFactor = 5.0; // 鼠标滚轮放大的步长参数\r\n\r\n // 移动设备上禁掉以下几个选项,可以相对更加流畅\r\n map.scene.requestRenderMode = false; // 取消实时渲染\r\n map.scene.fog.enabled = false;\r\n map.scene.skyAtmosphere.show = false;\r\n map.scene.globe.showGroundAtmosphere = false;\r\n }\r\n\r\n // 二三维切换不用动画\r\n if (map.viewer.sceneModePicker) {\r\n map.viewer.sceneModePicker.viewModel.duration = 0.0;\r\n }\r\n\r\n // 绑定当前项目的默认右键菜单\r\n // map.bindContextMenu(getContextMenu())\r\n\r\n // 隐藏右下角的Mars3D logo\r\n if ((map as any).mars3dLogo) {\r\n (map as any).mars3dLogo.show = false;\r\n }\r\n // 强制从DOM中移除logo元素\r\n setTimeout(() => {\r\n const logoElements = document.getElementsByClassName(\"mars3d-logo\");\r\n for (let i = 0; i < logoElements.length; i++) {\r\n logoElements[i].remove();\r\n }\r\n }, 100);\r\n\r\n // webgl渲染失败后,刷新页面\r\n // map.on(mars3d.EventType.renderError, async () => {\r\n // await $alert(\"程序内存消耗过大,请重启浏览器\")\r\n // window.location.reload()\r\n // })\r\n\r\n onMapLoad(); // map构造完成后的一些处理\r\n emit(\"onload\", map);\r\n};\r\n\r\n// map构造完成后的一些处理,可以按需注释和选用\r\nfunction onMapLoad() {\r\n // Mars3D地图内部使用,如右键菜单弹窗\r\n // @ts-ignore\r\n // window.globalAlert = $alert;\r\n // // @ts-ignore\r\n // window.globalMsg = $message;\r\n}\r\n\r\nonMounted(() => {\r\n initMars3d();\r\n});\r\n// 组件卸载之前销毁mars3d实例\r\nonUnmounted(() => {\r\n if (map) {\r\n map.destroy();\r\n map = null;\r\n }\r\n // console.log(\"map销毁完成\", map);\r\n});\r\n</script>\r\n\r\n<style lang=\"less\">\r\n/**cesium 工具按钮栏*/\r\n.cesium-viewer-toolbar {\r\n top: auto !important;\r\n bottom: 35px !important;\r\n left: 12px !important;\r\n right: auto !important;\r\n}\r\n\r\n.cesium-toolbar-button img {\r\n width: 22px;\r\n height: 100%;\r\n}\r\n.cesium-toolbar-button:hover img {\r\n width: 28px;\r\n}\r\n.cesium-svgPath-svg {\r\n scale: 0.8;\r\n}\r\n.cesium-svgPath-svg:hover {\r\n scale: 1;\r\n}\r\n.cesium-button .cesium-baseLayerPicker-selected {\r\n width: 100%;\r\n}\r\n\r\n.cesium-button:hover .cesium-baseLayerPicker-selected {\r\n width: 100%;\r\n}\r\n\r\n.cesium-viewer-toolbar > .cesium-toolbar-button,\r\n.cesium-navigationHelpButton-wrapper,\r\n.cesium-viewer-geocoderContainer {\r\n margin-bottom: 5px;\r\n float: left;\r\n clear: both;\r\n text-align: center;\r\n}\r\n\r\n.cesium-viewer-geocoderContainer form .cesium-geocoder-input {\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n}\r\n\r\n.cesium-button {\r\n background-color: rgba(39, 44, 54, 0.8);\r\n\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n\r\n color: #ffffff;\r\n fill: #e6e6e6;\r\n line-height: 38px;\r\n}\r\n\r\n.cesium-button:hover {\r\n background-color: rgba(51, 133, 255, 1);\r\n box-shadow: none;\r\n border: none;\r\n}\r\n\r\n/**cesium 底图切换面板*/\r\n.cesium-baseLayerPicker-dropDown {\r\n bottom: 0;\r\n left: 40px;\r\n max-height: 700px;\r\n margin-bottom: 5px;\r\n background-color: rgba(23, 49, 71, 0.7);\r\n}\r\n\r\n/**cesium 帮助面板*/\r\n.cesium-navigation-help {\r\n top: auto;\r\n bottom: 0;\r\n left: 40px;\r\n transform-origin: left bottom;\r\n background: none;\r\n background-color: rgba(23, 49, 71, 0.8);\r\n\r\n .cesium-navigation-help-instructions,\r\n .cesium-navigation-button {\r\n background: none;\r\n }\r\n\r\n .cesium-navigation-button-selected,\r\n .cesium-navigation-button-unselected:hover {\r\n background-color: rgba(1, 35, 22, 1);\r\n }\r\n}\r\n\r\n/**cesium 二维三维切换*/\r\n.cesium-sceneModePicker-wrapper {\r\n width: auto;\r\n}\r\n\r\n.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {\r\n float: right;\r\n margin: 0 3px;\r\n}\r\n\r\n/**cesium POI查询输入框*/\r\n.cesium-viewer-geocoderContainer .search-results {\r\n left: 0;\r\n right: 40px;\r\n width: auto;\r\n z-index: 9999;\r\n}\r\n\r\n.cesium-geocoder-searchButton {\r\n width: 38px;\r\n height: 38px;\r\n background-color: rgba(39, 44, 54, 0.8);\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n fill: #e6e6e6;\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .cesium-geocoder-input {\r\n height: 40px;\r\n width: 40px;\r\n background-color: rgba(63, 72, 84, 0.7);\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .search-results {\r\n background-color: rgba(23, 49, 71, 0.8);\r\n}\r\n\r\n/**cesium info信息框*/\r\n.cesium-infoBox {\r\n top: 50px;\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.cesium-infoBox-title {\r\n background-color: rgba(23, 49, 71, 0.8);\r\n}\r\n\r\n/**cesium 任务栏的FPS信息*/\r\n.cesium-performanceDisplay-defaultContainer {\r\n top: auto;\r\n bottom: 35px;\r\n right: 50px;\r\n}\r\n\r\n.cesium-performanceDisplay-ms,\r\n.cesium-performanceDisplay-fps {\r\n color: #fff;\r\n}\r\n\r\n/**cesium tileset调试信息面板*/\r\n.cesium-viewer-cesiumInspectorContainer {\r\n top: 10px;\r\n left: 10px;\r\n right: auto;\r\n}\r\n\r\n.cesium-cesiumInspector {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n/**覆盖mars3d内部控件的颜色等样式*/\r\n.mars3d-compass .mars3d-compass-outer {\r\n fill: rgba(39, 44, 54, 0.8);\r\n}\r\n.mars3d-compass .mars3d-compass-inner {\r\n background: rgba(39, 44, 54, 0.8);\r\n fill: #fff;\r\n}\r\n\r\n.mars3d-contextmenu-ul,\r\n.mars3d-sub-menu {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n.mars3d-contextmenu-ul {\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n}\r\n\r\n.mars3d-contextmenu-ul > li > a:hover,\r\n.mars3d-sub-menu > li > a:hover,\r\n.mars3d-contextmenu-ul > li > a:focus,\r\n.mars3d-sub-menu > li > a:focus,\r\n.mars3d-contextmenu-ul > li > .active,\r\n.mars3d-sub-menu > li > .active {\r\n background-color: var(--mars-hover-color, #3ea6ff);\r\n}\r\n\r\n.mars3d-contextmenu-ul > .active > a,\r\n.mars3d-sub-menu > .active > a,\r\n.mars3d-contextmenu-ul > .active > a:hover,\r\n.mars3d-sub-menu > .active > a:hover,\r\n.mars3d-contextmenu-ul > .active > a:focus,\r\n.mars3d-sub-menu > .active > a:focus {\r\n background-color: var(--mars-hover-color, #3ea6ff);\r\n}\r\n\r\n/* Popup样式*/\r\n.mars3d-popup-color {\r\n color: var(--mars-text-color, #ffffff);\r\n}\r\n\r\n.mars3d-popup-background {\r\n // background: none会导致剖面的popup没有颜色\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n// .mars3d-popup-content-wrapper {\r\n// box-shadow: none !important;\r\n// padding: 0 !important;\r\n// background: var(--mars-base-border) !important;\r\n// border-radius: 4px;\r\n// }\r\n\r\n.mars3d-popup-content {\r\n margin: 15px;\r\n}\r\n.mars3d-popup-btn-custom {\r\n padding: 3px 10px;\r\n border: 1px solid #209ffd;\r\n background: #209ffd1c;\r\n color: var(--mars-text-color);\r\n}\r\n\r\n.mars3d-tooltip {\r\n color: var(--mars-text-color, #ffffff);\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n border: 1px solid var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.mars3d-tooltip-top:before {\r\n border-top-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-bottom:before {\r\n border-bottom-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-left:before {\r\n border-left-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-right:before {\r\n border-right-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n.mars3d-template-content label {\r\n padding-right: 6px;\r\n}\r\n\r\n/* all 中的html样式 */\r\n.mars3d-template-titile {\r\n height: 33px;\r\n line-height: 33px;\r\n padding-left: 10px;\r\n border-radius: 4px 4px 0px 0px;\r\n box-shadow:\r\n 0px 6px 12px -2px rgba(50, 50, 93, 0.15),\r\n 0px 3px 7px -3px rgba(0, 0, 0, 0.2);\r\n color: var(--mars-control-text) !important;\r\n background: var(--mars-msg-title-bg);\r\n font-family: var(--mars-font-family);\r\n\r\n a {\r\n font-size: 16px;\r\n color: var(--mars-msg-title-color, #479be0);\r\n text-decoration: none;\r\n }\r\n}\r\n\r\n.mars3d-template-content {\r\n margin-top: 0 !important;\r\n background-color: var(--mars-dropdown-bg);\r\n padding: 10px;\r\n color: #eaf2ff;\r\n\r\n label {\r\n padding-right: 6px;\r\n }\r\n\r\n input {\r\n color: var(--mars-text-color);\r\n background-color: transparent !important;\r\n padding: 4px 5px;\r\n }\r\n\r\n input::placeholder {\r\n color: #cdcdcd !important;\r\n }\r\n\r\n textarea {\r\n color: var(--mars-base-color);\r\n background-color: transparent !important;\r\n padding: 4px 5px;\r\n }\r\n\r\n textarea::placeholder {\r\n color: #cdcdcd !important;\r\n }\r\n}\r\n\r\n.mars3d-popup-btn-custom {\r\n padding: 3px 10px;\r\n border: 1px solid #209ffd;\r\n background: #209ffd1c;\r\n color: var(--mars-text-color, #ffffff);\r\n}\r\n\r\n.mars3d-popup-content {\r\n margin: 15px;\r\n}\r\n\r\n.mars3d-divGraphic:hover {\r\n z-index: 999 !important;\r\n}\r\n\r\n/* 隐藏Mars3D logo */\r\n.mars3d-logo {\r\n display: none !important;\r\n visibility: hidden !important;\r\n opacity: 0 !important;\r\n pointer-events: none;\r\n}\r\n</style>\r\n","<!--\r\n ToolbarPanel — 测量 & 绘制工具栏\r\n\r\n 改进点(相对原 RightPanel):\r\n - 测量与绘制合并为统一工具栏,去掉冗余的 selectedGraphic 等未使用 prop\r\n - 新增激活态高亮(activeDrawType prop)\r\n - 图标语义更准确(使用 title 提示用户功能)\r\n-->\r\n<template>\r\n <div class=\"toolbar-panel\" :class=\"{ collapsed: isCollapsed }\">\r\n <!-- 收起/展开 header -->\r\n <div class=\"panel-header\" @click=\"toggleCollapse\">\r\n <i\r\n :class=\"[\r\n 'toggle-icon',\r\n 'fa',\r\n isCollapsed ? 'fa-chevron-down' : 'fa-chevron-up',\r\n ]\"\r\n />\r\n </div>\r\n\r\n <div class=\"panel-content\" v-show=\"!isCollapsed\">\r\n <!-- 测量工具组 -->\r\n <div class=\"menu-group\">\r\n <div\r\n v-for=\"item in measureTools\"\r\n :key=\"item.tool\"\r\n class=\"menu-item\"\r\n :title=\"item.title\"\r\n @click=\"activateTool(item.tool)\"\r\n >\r\n <i :class=\"item.iconClasses\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"divider\" />\r\n\r\n <!-- 绘制工具组 -->\r\n <div class=\"menu-group\">\r\n <div\r\n v-for=\"item in drawTools\"\r\n :key=\"item.tool\"\r\n class=\"menu-item\"\r\n :class=\"{ active: activeDrawType === item.drawType }\"\r\n :title=\"item.title\"\r\n @click=\"activateTool(item.tool)\"\r\n >\r\n <i :class=\"item.iconClasses\" />\r\n </div>\r\n <div class=\"divider\" />\r\n <!-- 清除按钮 -->\r\n <div class=\"menu-item\" title=\"清除全部\" @click=\"emitClear\">\r\n <i class=\"fa-solid fa-trash-can\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\n\r\n// ─── Props ───────────────────────────────────────────────────────────────────\r\ndefineProps<{\r\n activeDrawType?: string | null;\r\n}>();\r\n\r\n// ─── Emits ───────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n toolActivate: [tool: string];\r\n clear: [];\r\n}>();\r\n\r\n// ─── State ───────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(false);\r\n\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\nconst activateTool = (tool: string) => {\r\n emit(\"toolActivate\", tool);\r\n};\r\nconst emitClear = () => {\r\n emit(\"clear\");\r\n};\r\n\r\n// ─── 工具配置 ─────────────────────────────────────────────────────────────────\r\ninterface ToolItem {\r\n tool: string;\r\n title: string;\r\n iconClasses: string[];\r\n drawType?: string;\r\n}\r\n\r\nconst measureTools: ToolItem[] = [\r\n {\r\n tool: \"measureDistance\",\r\n title: \"测量距离\",\r\n iconClasses: [\"fa\", \"fa-arrows-alt-h\"], // 水平双向箭头,更准确表达距离\r\n },\r\n {\r\n tool: \"measureArea\",\r\n title: \"测量面积\",\r\n iconClasses: [\"fa\", \"fa-vector-square\"], // 矢量方块,更几何感、专业感\r\n },\r\n {\r\n tool: \"measureHeight\",\r\n title: \"测量高度差\",\r\n iconClasses: [\"fa\", \"fa-arrows-alt-v\"], // 垂直双向箭头,清晰表达高度\r\n },\r\n {\r\n tool: \"measureAngle\",\r\n title: \"测量角度\",\r\n iconClasses: [\"fa-solid\", \"fa-compass-drafting\"], // 绘图圆规图标,专业表达角度测量\r\n },\r\n];\r\n\r\nconst drawTools: ToolItem[] = [\r\n {\r\n tool: \"drawPoint\",\r\n title: \"点标记\",\r\n iconClasses: [\"fa\", \"fa-map-marker\"], // 地图标记点,比空心圆更直观\r\n drawType: \"point\",\r\n },\r\n {\r\n tool: \"drawLine\",\r\n title: \"线标记\",\r\n iconClasses: [\"fa\", \"fa-slash\"], // 斜线比短横线更像\"线\"的概念\r\n drawType: \"polyline\",\r\n },\r\n {\r\n tool: \"drawPolygon\",\r\n title: \"面标记\",\r\n iconClasses: [\"fa-solid\", \"fa-draw-polygon\"], // 多边形绘制图标,语义明确\r\n drawType: \"polygon\",\r\n },\r\n {\r\n tool: \"drawCircle\",\r\n title: \"圆标记\",\r\n iconClasses: [\"fa\", \"fa-circle\"], // 实心圆表示圆\r\n drawType: \"circle\",\r\n },\r\n {\r\n tool: \"drawRectangle\",\r\n title: \"矩形标记\",\r\n iconClasses: [\"fa-regular\", \"fa-square\"], // 空心方块,与圆标记风格统一\r\n drawType: \"rectangle\",\r\n },\r\n {\r\n tool: \"drawFreePolygon\",\r\n title: \"自由多边形\",\r\n iconClasses: [\"fa\", \"fa-pencil\"], // 铅笔表示自由绘制\r\n drawType: \"freePolygon\",\r\n },\r\n];\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n.toolbar-panel {\r\n position: absolute;\r\n top: 10px;\r\n right: 0;\r\n width: 42px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px 0 0 6px;\r\n border-right: none;\r\n z-index: 999;\r\n transition: max-height 0.3s ease;\r\n max-height: calc(100vh - 120px);\r\n overflow-y: auto;\r\n backdrop-filter: blur(4px);\r\n\r\n &.collapsed {\r\n max-height: 38px;\r\n .panel-content {\r\n display: none;\r\n }\r\n .panel-header {\r\n padding: 8px;\r\n justify-content: center;\r\n border-radius: 6px 0 0 6px;\r\n }\r\n }\r\n\r\n .panel-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 8px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 0 0 0;\r\n cursor: pointer;\r\n user-select: none;\r\n\r\n .toggle-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n &:hover .toggle-icon {\r\n color: #3ea6ff;\r\n }\r\n }\r\n\r\n .panel-content {\r\n padding: 6px 0;\r\n }\r\n\r\n .menu-group {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n .menu-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 8px;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n border-radius: 3px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n\r\n &.active {\r\n background: rgba(62, 166, 255, 0.4);\r\n color: #fff;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n i {\r\n font-size: 14px;\r\n line-height: 1;\r\n }\r\n }\r\n\r\n .divider {\r\n height: 1px;\r\n background: rgba(255, 255, 255, 0.08);\r\n margin: 6px 8px;\r\n }\r\n\r\n &::-webkit-scrollbar {\r\n width: 3px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n VisionPanel — 视角控制面板\r\n\r\n 职责:\r\n - 右下角悬浮按钮 + 弹出浮层\r\n - 四个功能:环绕飞行 / 移动到此处 / 第一视角 / 键盘漫游\r\n - 激活态通过 prop 传入,不在此处维护逻辑\r\n-->\r\n<template>\r\n <!-- 触发按钮 -->\r\n <div class=\"vision-button\" title=\"视觉功能\" @click=\"togglePopup\">\r\n <i class=\"fa fa-eye\" />\r\n </div>\r\n\r\n <!-- 弹出面板 -->\r\n <Transition name=\"vision-fade\">\r\n <div v-if=\"popupVisible\" class=\"vision-popup\">\r\n <div class=\"popup-header\">\r\n <span>视觉功能</span>\r\n <i class=\"fa fa-times close-icon\" @click=\"popupVisible = false\" />\r\n </div>\r\n <div class=\"popup-content\">\r\n <div\r\n v-for=\"item in visionItems\"\r\n :key=\"item.action\"\r\n class=\"popup-item\"\r\n :class=\"{ active: isActive(item) }\"\r\n @click=\"execute(item.action)\"\r\n >\r\n <i :class=\"['fa', item.icon]\" />\r\n <span>{{ getLabel(item) }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </Transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\n\r\n// ─── Props ───────────────────────────────────────────────────────────────────\r\nconst props = defineProps<{\r\n circleFlyActive?: boolean;\r\n flyToActive?: boolean;\r\n firstPersonActive?: boolean;\r\n keyboardNavigateActive?: boolean;\r\n}>();\r\n\r\n// ─── Emits ───────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n visionExecute: [action: string];\r\n}>();\r\n\r\n// ─── State ───────────────────────────────────────────────────────────────────\r\nconst popupVisible = ref(false);\r\nconst togglePopup = () => { popupVisible.value = !popupVisible.value; };\r\nconst execute = (action: string) => { emit(\"visionExecute\", action); };\r\n\r\n// ─── 功能配置表 ───────────────────────────────────────────────────────────────\r\ninterface VisionItem {\r\n action: string;\r\n icon: string;\r\n label: string;\r\n activeLabel?: string;\r\n activeProp?: keyof typeof props;\r\n}\r\n\r\nconst visionItems: VisionItem[] = [\r\n {\r\n action: \"circleFly\",\r\n icon: \"fa-refresh\",\r\n label: \"环绕飞行\",\r\n activeLabel: \"关闭环绕飞行\",\r\n activeProp: \"circleFlyActive\",\r\n },\r\n {\r\n action: \"flyTo\",\r\n icon: \"fa-location-arrow\",\r\n label: \"移动到此处\",\r\n activeProp: \"flyToActive\",\r\n },\r\n {\r\n action: \"firstPerson\",\r\n icon: \"fa-user\",\r\n label: \"开启第一视角\",\r\n activeLabel: \"关闭第一视角\",\r\n activeProp: \"firstPersonActive\",\r\n },\r\n {\r\n action: \"keyboardNavigate\",\r\n icon: \"fa-keyboard-o\",\r\n label: \"开启键盘漫游\",\r\n activeLabel: \"关闭键盘漫游\",\r\n activeProp: \"keyboardNavigateActive\",\r\n },\r\n];\r\n\r\nconst isActive = (item: VisionItem) =>\r\n item.activeProp ? !!props[item.activeProp] : false;\r\n\r\nconst getLabel = (item: VisionItem) =>\r\n isActive(item) && item.activeLabel ? item.activeLabel : item.label;\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n.vision-button {\r\n position: absolute;\r\n bottom: 80px;\r\n right: 0;\r\n width: 42px;\r\n height: 42px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border-radius: 6px 0 0 6px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-right: none;\r\n z-index: 999;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n backdrop-filter: blur(4px);\r\n transition: all 0.2s ease;\r\n\r\n &:hover { \r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n i { font-size: 14px; }\r\n}\r\n\r\n.vision-popup {\r\n position: absolute;\r\n bottom: 80px;\r\n right: 48px;\r\n width: 170px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border-radius: 6px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n backdrop-filter: blur(4px);\r\n z-index: 998;\r\n\r\n .popup-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 8px 12px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 5px 5px 0 0;\r\n\r\n span { color: #e8f4ff; font-size: 13px; font-weight: 600; }\r\n\r\n .close-icon {\r\n color: #7a9ec0;\r\n font-size: 14px;\r\n cursor: pointer;\r\n transition: color 0.2s ease;\r\n &:hover { color: #3ea6ff; }\r\n }\r\n }\r\n\r\n .popup-content { padding: 6px 0; }\r\n\r\n .popup-item {\r\n display: flex;\r\n align-items: center;\r\n padding: 8px 12px;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n border-radius: 3px;\r\n margin: 0 4px;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &.active { \r\n background: rgba(62, 166, 255, 0.4);\r\n color: #fff;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n i { margin-right: 10px; width: 16px; text-align: center; font-size: 14px; }\r\n span { font-size: 12px; }\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.vision-fade-enter-active,\r\n.vision-fade-leave-active {\r\n transition: opacity 0.25s ease, transform 0.25s ease;\r\n}\r\n.vision-fade-enter-from,\r\n.vision-fade-leave-to {\r\n opacity: 0;\r\n transform: translateX(15px);\r\n}\r\n</style>\r\n","/**\r\n * useMap — 地图核心 composable\r\n *\r\n * 职责:\r\n * - 持有 mars3d.Map 实例\r\n * - 管理业务 GraphicLayer(绘图层)和 measureLayer(测量层)\r\n * - 暴露地图事件回调(点击坐标记录)\r\n * - 提供统一的图层/thing 注册接口,方便后续业务扩展\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\n\r\n// 使用 any 避免 Mars3D 类型定义过深导致的 TS 推断溢出\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyShallowRef<T> = { readonly value: T | null };\r\n\r\nexport function useMap() {\r\n const Cesium = mars3d.Cesium;\r\n\r\n // ─── 地图实例(shallowRef 避免深响应代理 Cesium 对象) ───────────────\r\n const mapRef = shallowRef<mars3d.Map | null>(null);\r\n\r\n // ─── 核心图层 ─────────────────────────────────────────────────────────\r\n const graphicLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n const measureLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── 选中图形 ─────────────────────────────────────────────────────────\r\n const selectedGraphic = ref<any>(null);\r\n\r\n // ─── 最后点击位置(视角跳转等功能共享) ──────────────────────────────\r\n const lastClickPosition = ref<{ lng: number; lat: number; alt: number } | null>(null);\r\n\r\n /**\r\n * 在地图加载完毕后调用,完成图层、事件的初始化\r\n */\r\n function initMap(map: mars3d.Map) {\r\n mapRef.value = map;\r\n\r\n // 业务绘图层\r\n const gLayer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(gLayer);\r\n graphicLayer.value = gLayer;\r\n\r\n // 测量专用图层\r\n const mLayer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(mLayer);\r\n measureLayer.value = mLayer;\r\n\r\n // ── 地图点击:记录坐标 ──────────────────────────────────────────\r\n map.on(mars3d.EventType.click, (event: any) => {\r\n if (event.lnglat) {\r\n lastClickPosition.value = event.lnglat;\r\n } else if (event.cartesian) {\r\n const carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(event.cartesian);\r\n lastClickPosition.value = {\r\n lng: Cesium.Math.toDegrees(carto.longitude),\r\n lat: Cesium.Math.toDegrees(carto.latitude),\r\n alt: carto.height > 0 ? carto.height : 5000,\r\n };\r\n }\r\n });\r\n\r\n // ── 图形层交互事件 ────────────────────────────────────────────────\r\n gLayer.on(mars3d.EventType.click, (event: any) => {\r\n selectedGraphic.value = event.graphic;\r\n });\r\n gLayer.on(mars3d.EventType.mouseOver, (event: any) => {\r\n if (!selectedGraphic.value) {\r\n selectedGraphic.value = event.graphic;\r\n }\r\n });\r\n gLayer.on(mars3d.EventType.mouseOut, (event: any) => {\r\n if (selectedGraphic.value === event.graphic) {\r\n selectedGraphic.value = null;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * 销毁地图(组件卸载时调用)\r\n */\r\n function destroyMap() {\r\n if (mapRef.value) {\r\n mapRef.value.destroy();\r\n mapRef.value = null;\r\n }\r\n }\r\n\r\n /**\r\n * 便捷方法:向业务图层添加 Graphic\r\n */\r\n function addGraphic(graphic: any) {\r\n graphicLayer.value?.addGraphic(graphic);\r\n }\r\n\r\n /**\r\n * 向地图添加自定义 Thing(供业务扩展)\r\n */\r\n function addThing(thing: any) {\r\n mapRef.value?.addThing(thing);\r\n }\r\n\r\n return {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n map: mapRef as AnyShallowRef<any>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n graphicLayer: graphicLayer as AnyShallowRef<any>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n measureLayer: measureLayer as AnyShallowRef<any>,\r\n selectedGraphic,\r\n lastClickPosition,\r\n initMap,\r\n destroyMap,\r\n addGraphic,\r\n addThing,\r\n };\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type UseMapReturn = ReturnType<typeof useMap>;\r\n","/**\r\n * useMeasure — 测量工具 composable\r\n *\r\n * 职责:\r\n * - 封装 mars3d.thing.Measure 的生命周期\r\n * - 提供 距离 / 面积 / 高度差 / 角度 四种测量方法\r\n * - 提供 clear 清除方法\r\n *\r\n * 依赖:useMap 返回的 map 与 measureLayer\r\n */\r\nimport { shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\nexport function useMeasure(mapContext: UseMapReturn) {\r\n const measureThing = shallowRef<mars3d.thing.Measure | null>(null);\r\n\r\n /** 在地图初始化后调用,注册 Measure thing */\r\n function initMeasure() {\r\n const map = mapContext.map.value;\r\n const layer = mapContext.measureLayer.value;\r\n if (!map || !layer) return;\r\n\r\n const m = new mars3d.thing.Measure({ graphicLayer: layer } as any);\r\n map.addThing(m);\r\n measureThing.value = m;\r\n }\r\n\r\n /** 测量距离 */\r\n function measureDistance(style?: Record<string, any>) {\r\n measureThing.value?.distance({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 测量面积 */\r\n function measureArea(style?: Record<string, any>) {\r\n measureThing.value?.area({\r\n style: { color: \"#3388ff\", opacity: 0.5, ...style },\r\n });\r\n }\r\n\r\n /** 测量高度差 */\r\n function measureHeight(style?: Record<string, any>) {\r\n measureThing.value?.height({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 测量角度 */\r\n function measureAngle(style?: Record<string, any>) {\r\n measureThing.value?.angle({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 清除所有测量结果 */\r\n function clearMeasure() {\r\n measureThing.value?.clear();\r\n mapContext.measureLayer.value?.clear();\r\n }\r\n\r\n return {\r\n measureThing,\r\n initMeasure,\r\n measureDistance,\r\n measureArea,\r\n measureHeight,\r\n measureAngle,\r\n clearMeasure,\r\n };\r\n}\r\n","/**\r\n * useDraw — 绘制工具 composable\r\n *\r\n * 职责:\r\n * - 封装六种图形绘制(点/线/面/圆/矩形/自由多边形)\r\n * - 统一管理 currentDraw 引用,保证绘制互斥\r\n * - 提供 stopDraw / clearDraw 方法\r\n *\r\n * 依赖:useMap 返回的 measureLayer(绘图结果复用测量层,也可传独立图层)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\n/** 支持的绘制类型枚举,方便外部类型提示 */\r\nexport type DrawType = \"point\" | \"polyline\" | \"polygon\" | \"circle\" | \"rectangle\" | \"freePolygon\";\r\n\r\nexport function useDraw(mapContext: UseMapReturn) {\r\n const currentDraw = shallowRef<any>(null);\r\n /** 当前激活的绘制类型,用于 UI 高亮 */\r\n const activeDrawType = ref<DrawType | null>(null);\r\n\r\n /** 获取绘制目标图层(复用 measureLayer,也可按需传其他层) */\r\n function getLayer() {\r\n return mapContext.measureLayer.value;\r\n }\r\n\r\n /** 内部启动绘制 */\r\n function startDraw(type: string, style: Record<string, any>, drawType: DrawType) {\r\n const layer = getLayer();\r\n if (!layer) return;\r\n stopDraw(); // 先停止上一次未完成的绘制\r\n currentDraw.value = layer.startDraw({ type, style });\r\n activeDrawType.value = drawType;\r\n }\r\n\r\n /** 绘制点 */\r\n function drawPoint(style?: Record<string, any>) {\r\n startDraw(\"point\", { pixelSize: 10, color: \"#ff0000\", ...style }, \"point\");\r\n }\r\n\r\n /** 绘制折线 */\r\n function drawLine(style?: Record<string, any>) {\r\n startDraw(\"polyline\", { width: 3, color: \"#3388ff\", ...style }, \"polyline\");\r\n }\r\n\r\n /** 绘制多边形 */\r\n function drawPolygon(style?: Record<string, any>) {\r\n startDraw(\"polygon\", { color: \"#3388ff\", opacity: 0.5, ...style }, \"polygon\");\r\n }\r\n\r\n /** 绘制圆 */\r\n function drawCircle(style?: Record<string, any>) {\r\n startDraw(\"circle\", { radius: 1000, color: \"#00ff00\", opacity: 0.3, ...style }, \"circle\");\r\n }\r\n\r\n /** 绘制矩形 */\r\n function drawRectangle(style?: Record<string, any>) {\r\n startDraw(\"rectangle\", { color: \"#3388ff\", opacity: 0.5, ...style }, \"rectangle\");\r\n }\r\n\r\n /** 绘制自由多边形(贴地) */\r\n function drawFreePolygon(style?: Record<string, any>) {\r\n startDraw(\r\n \"polygon\",\r\n { color: \"#3388ff\", opacity: 0.5, clampToGround: true, ...style },\r\n \"freePolygon\",\r\n );\r\n }\r\n\r\n /** 停止当前绘制,但保留已绘结果 */\r\n function stopDraw() {\r\n if (currentDraw.value) {\r\n getLayer()?.stopDraw();\r\n currentDraw.value = null;\r\n }\r\n activeDrawType.value = null;\r\n }\r\n\r\n /** 停止并清除所有绘制结果 */\r\n function clearDraw() {\r\n stopDraw();\r\n getLayer()?.clear();\r\n }\r\n\r\n return {\r\n currentDraw,\r\n activeDrawType,\r\n drawPoint,\r\n drawLine,\r\n drawPolygon,\r\n drawCircle,\r\n drawRectangle,\r\n drawFreePolygon,\r\n stopDraw,\r\n clearDraw,\r\n };\r\n}\r\n","/**\r\n * useVision — 视角控制 composable\r\n *\r\n * 职责:\r\n * - 封装环绕飞行(RotatePoint)\r\n * - 封装飞行到指定位置(flyTo / flyHome)\r\n * - 封装第一视角漫游(FirstPersonRoam)\r\n * - 封装键盘漫游(KeyboardRoam)\r\n * - 暴露各功能的激活状态,供 UI 显示切换文案\r\n *\r\n * 依赖:useMap 返回的 map 与 lastClickPosition\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\nexport function useVision(mapContext: UseMapReturn) {\r\n // ─── 状态 ──────────────────────────────────────────────────────────────\r\n const circleFlyActive = ref(false);\r\n const firstPersonActive = ref(false);\r\n const keyboardActive = ref(false);\r\n const flyToActive = ref(false);\r\n\r\n // ─── Thing 实例 ────────────────────────────────────────────────────────\r\n const rotatePoint = shallowRef<mars3d.thing.RotatePoint | null>(null);\r\n const firstPersonRoam = shallowRef<mars3d.thing.FirstPersonRoam | null>(null);\r\n const keyboardRoam = shallowRef<mars3d.thing.KeyboardRoam | null>(null);\r\n let initialCameraView: any = null;\r\n\r\n /** 获取地图实例(内部简写) */\r\n function getMap() {\r\n return mapContext.map.value;\r\n }\r\n\r\n // ─── 环绕飞行 ──────────────────────────────────────────────────────────\r\n function toggleCircleFly() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (rotatePoint.value) {\r\n if (rotatePoint.value.isStart) {\r\n rotatePoint.value.stop();\r\n }\r\n map.removeThing(rotatePoint.value);\r\n rotatePoint.value = null;\r\n circleFlyActive.value = false;\r\n return;\r\n }\r\n\r\n const center = map.getCenter();\r\n const rp = new mars3d.thing.RotatePoint({ distance: 5000, time: 30 });\r\n map.addThing(rp);\r\n rp.start(center);\r\n rotatePoint.value = rp;\r\n circleFlyActive.value = true;\r\n }\r\n\r\n // ─── 飞行到点击位置或地图中心 ──────────────────────────────────────────\r\n function flyTo() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n flyToActive.value = true;\r\n const done = () => setTimeout(() => { flyToActive.value = false; }, 2000);\r\n\r\n const pos = mapContext.lastClickPosition.value;\r\n if (pos) {\r\n const target = { ...pos, alt: pos.alt > 0 ? pos.alt : 5000 };\r\n map.setCameraView(target, { duration: 2, complete: done });\r\n } else {\r\n map.flyHome({ duration: 2 });\r\n done();\r\n }\r\n }\r\n\r\n // ─── 第一视角漫游 ──────────────────────────────────────────────────────\r\n function toggleFirstPerson() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (!firstPersonRoam.value) {\r\n const roam = new mars3d.thing.FirstPersonRoam({});\r\n map.addThing(roam);\r\n initialCameraView = map.getCameraView();\r\n roam.enabled = true;\r\n firstPersonRoam.value = roam;\r\n firstPersonActive.value = true;\r\n } else {\r\n const roam = firstPersonRoam.value;\r\n roam.enabled = !roam.enabled;\r\n firstPersonActive.value = roam.enabled;\r\n if (!roam.enabled && initialCameraView) {\r\n map.setCameraView(initialCameraView, { duration: 1 });\r\n } else if (roam.enabled) {\r\n initialCameraView = map.getCameraView();\r\n }\r\n }\r\n }\r\n\r\n // ─── 键盘漫游 ──────────────────────────────────────────────────────────\r\n function toggleKeyboardNavigate() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (!keyboardRoam.value) {\r\n const roam = new mars3d.thing.KeyboardRoam({});\r\n map.addThing(roam);\r\n roam.enabled = true;\r\n keyboardRoam.value = roam;\r\n keyboardActive.value = true;\r\n } else {\r\n const roam = keyboardRoam.value;\r\n roam.enabled = !roam.enabled;\r\n keyboardActive.value = roam.enabled;\r\n }\r\n }\r\n\r\n return {\r\n // 状态\r\n circleFlyActive,\r\n firstPersonActive,\r\n keyboardActive,\r\n flyToActive,\r\n // 方法\r\n toggleCircleFly,\r\n flyTo,\r\n toggleFirstPerson,\r\n toggleKeyboardNavigate,\r\n };\r\n}\r\n","<!--\r\n MarsMapContainer — 地图核心容器组件\r\n\r\n 功能:\r\n 1. 集成底层 MarsMap 渲染组件\r\n 2. 内置测量/绘制工具栏(ToolbarPanel)和视角控制面板(VisionPanel)\r\n 3. 组合所有 composable,通过 provide 向子组件/插槽透传地图上下文\r\n 4. 通过 default 插槽支持业务组件叠加(popup、图表、统计面板等)\r\n\r\n Props:\r\n - configUrl 地图配置 JSON 路径\r\n - mapKey 多地图时区分实例的 key(默认 \"default\")\r\n - hideToolbar 是否隐藏工具栏(默认 false)\r\n - hideVision 是否隐藏视觉控制按钮(默认 false)\r\n\r\n Expose(供父组件通过 ref 访问):\r\n - map\r\n - graphicLayer\r\n - measureLayer\r\n - selectedGraphic\r\n - addGraphic()\r\n - addThing()\r\n - measure(useMeasure 全量返回)\r\n - draw(useDraw 全量返回)\r\n - vision(useVision 全量返回)\r\n-->\r\n<template>\r\n <div class=\"mars-map-container\">\r\n <!-- 底层地图渲染 -->\r\n <MarsMap\r\n :url=\"configUrl\"\r\n :map-key=\"mapKey\"\r\n @onload=\"onMapLoad\"\r\n />\r\n\r\n <!-- 测量/绘制工具栏 -->\r\n <ToolbarPanel\r\n v-if=\"!hideToolbar\"\r\n :active-draw-type=\"draw.activeDrawType.value\"\r\n @tool-activate=\"handleToolActivate\"\r\n @clear=\"handleClear\"\r\n />\r\n\r\n <!-- 视角控制面板 -->\r\n <VisionPanel\r\n v-if=\"!hideVision\"\r\n :circle-fly-active=\"vision.circleFlyActive.value\"\r\n :fly-to-active=\"vision.flyToActive.value\"\r\n :first-person-active=\"vision.firstPersonActive.value\"\r\n :keyboard-navigate-active=\"vision.keyboardActive.value\"\r\n @vision-execute=\"handleVisionExecute\"\r\n />\r\n\r\n <!-- 业务插槽:自定义 UI 叠加层 -->\r\n <slot />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide } from \"vue\";\r\nimport MarsMap from \"../mars-work/mars-map.vue\";\r\nimport ToolbarPanel from \"./panels/ToolbarPanel.vue\";\r\nimport VisionPanel from \"./panels/VisionPanel.vue\";\r\n\r\nimport { useMap } from \"./composables/useMap\";\r\nimport { useMeasure } from \"./composables/useMeasure\";\r\nimport { useDraw } from \"./composables/useDraw\";\r\nimport { useVision } from \"./composables/useVision\";\r\n\r\n// ─── Props ──────────────────────────────────────────────────────────────────\r\nconst props = withDefaults(\r\n defineProps<{\r\n configUrl?: string;\r\n mapKey?: string;\r\n hideToolbar?: boolean;\r\n hideVision?: boolean;\r\n }>(),\r\n {\r\n configUrl: \"config/config.json\",\r\n mapKey: \"default\",\r\n hideToolbar: false,\r\n hideVision: false,\r\n },\r\n);\r\n\r\n// ─── Emits ──────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n /** 地图加载完成,回传 map 实例 */\r\n onload: [map: any];\r\n}>();\r\n\r\n// ─── Composables ────────────────────────────────────────────────────────────\r\nconst mapCtx = useMap();\r\nconst measure = useMeasure(mapCtx);\r\nconst draw = useDraw(mapCtx);\r\nconst vision = useVision(mapCtx);\r\n\r\n// ─── provide(供插槽内的业务组件直接 inject 使用) ──────────────────────────\r\nprovide(\"mapContext\", mapCtx);\r\nprovide(\"measureContext\", measure);\r\nprovide(\"drawContext\", draw);\r\nprovide(\"visionContext\", vision);\r\n\r\n// ─── 地图加载回调 ────────────────────────────────────────────────────────────\r\nfunction onMapLoad(map: any) {\r\n mapCtx.initMap(map);\r\n measure.initMeasure();\r\n emit(\"onload\", map);\r\n}\r\n\r\n// ─── 工具栏事件处理 ──────────────────────────────────────────────────────────\r\ntype ToolAction =\r\n | \"measureDistance\" | \"measureArea\" | \"measureHeight\" | \"measureAngle\"\r\n | \"drawPoint\" | \"drawLine\" | \"drawPolygon\" | \"drawCircle\" | \"drawRectangle\" | \"drawFreePolygon\";\r\n\r\nfunction handleToolActivate(tool: string) {\r\n switch (tool as ToolAction) {\r\n case \"measureDistance\": measure.measureDistance(); break;\r\n case \"measureArea\": measure.measureArea(); break;\r\n case \"measureHeight\": measure.measureHeight(); break;\r\n case \"measureAngle\": measure.measureAngle(); break;\r\n case \"drawPoint\": draw.drawPoint(); break;\r\n case \"drawLine\": draw.drawLine(); break;\r\n case \"drawPolygon\": draw.drawPolygon(); break;\r\n case \"drawCircle\": draw.drawCircle(); break;\r\n case \"drawRectangle\": draw.drawRectangle(); break;\r\n case \"drawFreePolygon\": draw.drawFreePolygon(); break;\r\n }\r\n}\r\n\r\nfunction handleClear() {\r\n measure.clearMeasure();\r\n draw.clearDraw();\r\n}\r\n\r\n// ─── 视角控制事件处理 ────────────────────────────────────────────────────────\r\ntype VisionAction = \"circleFly\" | \"flyTo\" | \"firstPerson\" | \"keyboardNavigate\";\r\n\r\nfunction handleVisionExecute(action: string) {\r\n switch (action as VisionAction) {\r\n case \"circleFly\": vision.toggleCircleFly(); break;\r\n case \"flyTo\": vision.flyTo(); break;\r\n case \"firstPerson\": vision.toggleFirstPerson(); break;\r\n case \"keyboardNavigate\": vision.toggleKeyboardNavigate(); break;\r\n }\r\n}\r\n\r\n// ─── Expose(父组件 ref 访问) ────────────────────────────────────────────────\r\ndefineExpose({\r\n map: mapCtx.map,\r\n graphicLayer: mapCtx.graphicLayer,\r\n measureLayer: mapCtx.measureLayer,\r\n selectedGraphic: mapCtx.selectedGraphic,\r\n lastClickPosition: mapCtx.lastClickPosition,\r\n addGraphic: mapCtx.addGraphic,\r\n addThing: mapCtx.addThing,\r\n measure,\r\n draw,\r\n vision,\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.mars-map-container {\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n</style>\r\n","/**\r\n * usePoiMarker — POI 标注管理 composable\r\n *\r\n * 职责:\r\n * - 维护 POI 数据列表(纯数据层)\r\n * - 管理地图上对应的 BillboardEntity 图形(图形层)\r\n * - 提供 添加 / 删除 / 选中 / 飞行定位 操作\r\n * - 数据与图形保持双向同步(通过 graphicId 关联)\r\n *\r\n * 使用方式(在业务组件内):\r\n * const mapCtx = inject<UseMapReturn>('mapContext')!\r\n * const poi = usePoiMarker(mapCtx)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\n\r\n// ─── POI 数据类型 ─────────────────────────────────────────────────────────────\r\nexport interface PoiItem {\r\n id: string;\r\n name: string;\r\n lng: number;\r\n lat: number;\r\n alt: number;\r\n category: \"default\" | \"warning\" | \"info\";\r\n description?: string;\r\n /** 对应地图上的 Graphic 实例引用 */\r\n graphic?: any;\r\n}\r\n\r\n/** 分类颜色映射 */\r\nconst CATEGORY_ICON: Record<PoiItem[\"category\"], string> = {\r\n default: \"//data.mars3d.cn/img/marker/mark-blue.png\",\r\n warning: \"//data.mars3d.cn/img/marker/mark-red.png\",\r\n info: \"//data.mars3d.cn/img/marker/mark-green.png\",\r\n};\r\n\r\nlet _idCounter = 1;\r\n\r\nexport function usePoiMarker(mapCtx: UseMapReturn) {\r\n // ─── 独立业务图层(与测量层隔离) ─────────────────────────────────────────\r\n const poiLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── POI 数据列表 ──────────────────────────────────────────────────────────\r\n const poiList = ref<PoiItem[]>([]);\r\n\r\n // ─── 当前选中的 POI ────────────────────────────────────────────────────────\r\n const activePoiId = ref<string | null>(null);\r\n\r\n /** 在地图加载后调用,初始化专属图层 */\r\n function initPoiLayer() {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n const layer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(layer);\r\n poiLayer.value = layer;\r\n\r\n // 点击图层上的标注 → 选中对应 POI\r\n layer.on(mars3d.EventType.click, (e: any) => {\r\n const poiId = e.graphic?.attr?.poiId;\r\n if (poiId) selectPoi(poiId);\r\n });\r\n }\r\n\r\n /** 添加 POI(创建数据 + 在地图上生成图形) */\r\n function addPoi(params: Omit<PoiItem, \"id\" | \"graphic\">) {\r\n const layer = poiLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `poi-${_idCounter++}`;\r\n\r\n // 创建地图图形\r\n const graphic = new mars3d.graphic.BillboardEntity({\r\n position: [params.lng, params.lat, params.alt],\r\n style: {\r\n image: CATEGORY_ICON[params.category],\r\n scale: 1,\r\n horizontalOrigin: mars3d.Cesium.HorizontalOrigin.CENTER,\r\n verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,\r\n clampToGround: false,\r\n // 标注文字\r\n label: {\r\n text: params.name,\r\n font_size: 14,\r\n color: \"#ffffff\",\r\n outline: true,\r\n outlineColor: \"#333333\",\r\n outlineWidth: 2,\r\n pixelOffset: new mars3d.Cesium.Cartesian2(0, -40),\r\n visibleDepth: false,\r\n },\r\n },\r\n // popup 弹窗(点击标注时自动展示)\r\n popup: buildPopupHtml(params),\r\n attr: { poiId: id, name: params.name },\r\n });\r\n\r\n layer.addGraphic(graphic);\r\n\r\n const poi: PoiItem = { ...params, id, graphic };\r\n poiList.value.push(poi);\r\n return poi;\r\n }\r\n\r\n /** 删除 POI */\r\n function removePoi(id: string) {\r\n const idx = poiList.value.findIndex((p) => p.id === id);\r\n if (idx === -1) return;\r\n\r\n const poi = poiList.value[idx];\r\n poi.graphic && poiLayer.value?.removeGraphic(poi.graphic);\r\n poiList.value.splice(idx, 1);\r\n\r\n if (activePoiId.value === id) activePoiId.value = null;\r\n }\r\n\r\n /** 选中 POI(高亮 + 视角飞行) */\r\n function selectPoi(id: string, flyTo = false) {\r\n activePoiId.value = id;\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi) return;\r\n\r\n // 高亮:放大图标\r\n poiList.value.forEach((p) => {\r\n if (p.graphic) {\r\n p.graphic.style.scale = p.id === id ? 1.4 : 1.0;\r\n }\r\n });\r\n\r\n if (flyTo) flyToPoi(id);\r\n }\r\n\r\n /** 更新 POI 名称(实时同步到图形和 popup) */\r\n function updatePoiName(id: string, newName: string) {\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi) return;\r\n\r\n poi.name = newName;\r\n\r\n // 同步更新图形 attr\r\n if (poi.graphic) {\r\n poi.graphic.attr = { ...poi.graphic.attr, name: newName };\r\n poi.graphic.popup = buildPopupHtml(poi);\r\n // 同步更新 label 文字\r\n if (poi.graphic.style?.label) {\r\n poi.graphic.style.label.text = newName;\r\n }\r\n poi.graphic.closePopup?.();\r\n }\r\n }\r\n\r\n /** 飞行到 POI 位置 */\r\n function flyToPoi(id: string) {\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi || !mapCtx.map.value) return;\r\n\r\n const map = mapCtx.map.value;\r\n\r\n // 以标注点高度为基准,飞行高度 = 标注高度 + 合理偏移\r\n const baseAlt = poi.alt > 1 ? poi.alt : 50;\r\n const flyAlt = baseAlt + 1500;\r\n\r\n // 不指定 pitch,让相机正上方俯视,定位最准确\r\n map.setCameraView({ lng: poi.lng, lat: poi.lat, alt: flyAlt }, { duration: 1.5 });\r\n }\r\n\r\n /** 清空所有 POI */\r\n function clearAll() {\r\n poiLayer.value?.clear();\r\n poiList.value = [];\r\n activePoiId.value = null;\r\n }\r\n\r\n /** 开启/关闭「点击地图添加标注」模式 */\r\n const isAddMode = ref(false);\r\n let _clickHandler: ((e: any) => void) | null = null;\r\n\r\n function toggleAddMode(\r\n onAdded?: (poi: PoiItem) => void,\r\n defaultName = \"新标注\",\r\n category: PoiItem[\"category\"] = \"default\",\r\n ) {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n if (isAddMode.value) {\r\n // 退出添加模式\r\n if (_clickHandler) {\r\n map.off(mars3d.EventType.click, _clickHandler);\r\n _clickHandler = null;\r\n }\r\n isAddMode.value = false;\r\n } else {\r\n // 进入添加模式:下一次点击地图即创建 POI\r\n isAddMode.value = true;\r\n _clickHandler = (e: any) => {\r\n // 优先取经纬度坐标,兜底用笛卡尔坐标转换\r\n let lng: number, lat: number, alt: number;\r\n\r\n if (e.lnglat) {\r\n lng = e.lnglat.lng;\r\n lat = e.lnglat.lat;\r\n alt = e.lnglat.alt ?? 0;\r\n } else if (e.cartesian) {\r\n const carto = mars3d.Cesium.Cartographic.fromCartesian(e.cartesian);\r\n lng = mars3d.Cesium.Math.toDegrees(carto.longitude);\r\n lat = mars3d.Cesium.Math.toDegrees(carto.latitude);\r\n alt = carto.height > 0 ? carto.height : 50; // terrain height fallback\r\n } else {\r\n return;\r\n }\r\n\r\n // 标注高度至少离地面 50m,避免贴地\r\n const finalAlt = alt > 1 ? alt : 50;\r\n\r\n const poi = addPoi({\r\n name: `${defaultName} ${_idCounter}`,\r\n lng,\r\n lat,\r\n alt: finalAlt,\r\n category,\r\n });\r\n if (poi) onAdded?.(poi);\r\n // 单次模式:添加完即退出\r\n toggleAddMode();\r\n };\r\n map.on(mars3d.EventType.click, _clickHandler);\r\n }\r\n }\r\n\r\n return {\r\n poiLayer,\r\n poiList,\r\n activePoiId,\r\n isAddMode,\r\n initPoiLayer,\r\n addPoi,\r\n removePoi,\r\n selectPoi,\r\n flyToPoi,\r\n updatePoiName,\r\n clearAll,\r\n toggleAddMode,\r\n };\r\n}\r\n\r\n// ─── 工具:生成 popup HTML ────────────────────────────────────────────────────\r\nfunction buildPopupHtml(poi: Omit<PoiItem, \"id\" | \"graphic\">) {\r\n return `\r\n <div style=\"padding:8px 12px;min-width:160px;\">\r\n <div style=\"font-size:15px;font-weight:bold;margin-bottom:6px;color:#fff;\">${poi.name}</div>\r\n <div style=\"font-size:12px;color:#adc6e5;line-height:1.8;\">\r\n <div>经度:${poi.lng.toFixed(6)}</div>\r\n <div>纬度:${poi.lat.toFixed(6)}</div>\r\n <div>高度:${poi.alt.toFixed(1)} m</div>\r\n ${poi.description ? `<div style=\"margin-top:4px;\">${poi.description}</div>` : \"\"}\r\n </div>\r\n </div>\r\n `;\r\n}\r\n\r\nexport type UsePoiMarkerReturn = ReturnType<typeof usePoiMarker>;\r\n","<!--\r\n PoiMarkerLayer — POI 标注地图层组件\r\n\r\n 职责:\r\n - 放置在 MarsMapContainer 的 <slot> 内\r\n - 通过 inject 获取地图上下文,完成图层初始化\r\n - 通过 provide 将 poiCtx 向子组件暴露(inject 只走父→子,不走兄弟)\r\n - 内部通过 <slot> 渲染 PoiMarkerPanel 等子组件,保证 provide/inject 链路正确\r\n - 对外 expose usePoiMarker 全量接口,供父组件 ref 访问\r\n\r\n 使用方式(PoiMarkerPanel 必须作为子内容传入,而非兄弟节点):\r\n <MarsMapContainer @onload=\"...\">\r\n <PoiMarkerLayer ref=\"poiLayerRef\">\r\n <PoiMarkerPanel />\r\n </PoiMarkerLayer>\r\n </MarsMapContainer>\r\n-->\r\n<template>\r\n <!-- provide/inject 需要父子关系,用 slot 渲染子组件 -->\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject, provide, watch, onUnmounted } from \"vue\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\nimport { usePoiMarker } from \"./usePoiMarker\";\r\n\r\n// ─── 注入地图上下文 ────────────────────────────────────────────────────────────\r\nconst mapCtx = inject<UseMapReturn>(\"mapContext\");\r\nif (!mapCtx) throw new Error(\"[PoiMarkerLayer] 必须放置在 MarsMapContainer 内部\");\r\n\r\n// ─── 初始化 POI 管理 composable ────────────────────────────────────────────────\r\nconst poi = usePoiMarker(mapCtx);\r\n\r\n// ─── 等待地图就绪后初始化图层 ─────────────────────────────────────────────────\r\n// map 在 MarsMapContainer onload 后才不为 null\r\nconst stopWatch = watch(\r\n () => mapCtx.map.value,\r\n (map) => {\r\n if (map) {\r\n poi.initPoiLayer();\r\n stopWatch(); // 只需初始化一次\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonUnmounted(() => {\r\n poi.clearAll();\r\n});\r\n\r\n// ─── provide 给同级业务组件(PoiMarkerPanel 等)─────────────────────────────\r\nprovide(\"poiContext\", poi);\r\n\r\n// ─── expose 给父组件 ref ──────────────────────────────────────────────────────\r\ndefineExpose(poi);\r\n</script>\r\n","<!--\r\n PoiMarkerPanel — POI 标注管理面板(左侧)\r\n\r\n 功能:\r\n - 标注列表(名称 / 分类标签 / 定位 / 删除)\r\n - 添加模式切换按钮(点击地图新增标注)\r\n - 分类筛选标签\r\n - 点击列表项飞行到标注位置 + 地图高亮\r\n\r\n 数据来源:inject('poiContext'),由同级 PoiMarkerLayer 提供\r\n-->\r\n<template>\r\n <div\r\n ref=\"panelEl\"\r\n class=\"poi-panel\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :style=\"\r\n !isCollapsed\r\n ? { left: pos.x + 'px', top: pos.y + 'px' }\r\n : { left: pos.x + 'px', top: pos.y + 'px' }\r\n \"\r\n >\r\n <!-- 面板标题栏(可拖拽) -->\r\n <div\r\n class=\"poi-panel__header\"\r\n :class=\"{ 'is-dragging': isDragging }\"\r\n @mousedown.prevent=\"startDrag\"\r\n @click=\"isDragging ? null : toggleCollapse()\"\r\n >\r\n <!-- 收缩后只显示图标 -->\r\n <template v-if=\"isCollapsed\">\r\n <div class=\"collapsed-icon-wrap\">\r\n <i class=\"fa fa-map-marker collapsed-icon\" />\r\n <span class=\"poi-count poi-count--collapsed\">{{\r\n filteredList.length\r\n }}</span>\r\n </div>\r\n </template>\r\n <template v-else>\r\n <span class=\"poi-panel__title\">\r\n <i class=\"fa fa-map-marker\" />\r\n POI 标注管理\r\n <span class=\"poi-count\">{{ filteredList.length }}</span>\r\n </span>\r\n <i class=\"fa fa-chevron-left collapse-icon\" />\r\n </template>\r\n </div>\r\n\r\n <div class=\"poi-panel__body\" v-show=\"!isCollapsed\">\r\n <!-- 操作栏 -->\r\n <div class=\"poi-panel__toolbar\">\r\n <button\r\n class=\"btn\"\r\n :class=\"{ 'btn--active': poi.isAddMode.value }\"\r\n @click=\"toggleAdd\"\r\n >\r\n <i :class=\"['fa', poi.isAddMode.value ? 'fa-times' : 'fa-plus']\" />\r\n {{ poi.isAddMode.value ? \"取消添加\" : \"点击地图添加\" }}\r\n </button>\r\n <button\r\n class=\"btn btn--danger\"\r\n @click=\"confirmClear\"\r\n :disabled=\"poi.poiList.value.length === 0\"\r\n >\r\n <i class=\"fa fa-trash-o\" /> 清空\r\n </button>\r\n </div>\r\n\r\n <!-- 分类筛选 -->\r\n <div class=\"poi-panel__filter\">\r\n <span\r\n v-for=\"cat in categories\"\r\n :key=\"cat.value\"\r\n class=\"filter-tag\"\r\n :class=\"{ active: activeCategory === cat.value }\"\r\n @click=\"activeCategory = cat.value\"\r\n >\r\n <i :class=\"['fa', cat.icon]\" :style=\"{ color: cat.color }\" />\r\n {{ cat.label }}\r\n </span>\r\n </div>\r\n\r\n <!-- POI 列表 -->\r\n <div class=\"poi-panel__list\">\r\n <TransitionGroup name=\"poi-list\">\r\n <div\r\n v-for=\"item in filteredList\"\r\n :key=\"item.id\"\r\n class=\"poi-item\"\r\n :class=\"{ 'poi-item--active': poi.activePoiId.value === item.id }\"\r\n @click=\"onSelect(item.id)\"\r\n >\r\n <!-- 分类色块 -->\r\n <span\r\n class=\"poi-item__dot\"\r\n :style=\"{ background: getCategoryColor(item.category) }\"\r\n />\r\n\r\n <div class=\"poi-item__info\">\r\n <!-- 编辑态:输入框 -->\r\n <input\r\n v-if=\"editingId === item.id\"\r\n class=\"poi-item__name-input\"\r\n v-model=\"editName\"\r\n @keydown.enter=\"saveEdit\"\r\n @keydown.escape=\"cancelEdit\"\r\n @click.stop\r\n ref=\"editInputEl\"\r\n />\r\n <!-- 正常态:名称 -->\r\n <div\r\n v-else\r\n class=\"poi-item__name\"\r\n @dblclick.stop=\"startEdit(item)\"\r\n >\r\n {{ item.name }}\r\n </div>\r\n <div class=\"poi-item__coord\">\r\n {{ item.lng.toFixed(4) }}, {{ item.lat.toFixed(4) }}\r\n </div>\r\n </div>\r\n\r\n <!-- 操作按钮 -->\r\n <div class=\"poi-item__actions\">\r\n <button\r\n class=\"icon-btn\"\r\n title=\"编辑名称\"\r\n @click.stop=\"startEdit(item)\"\r\n >\r\n <i class=\"fa fa-pencil\" />\r\n </button>\r\n <button\r\n class=\"icon-btn\"\r\n title=\"飞行定位\"\r\n @click.stop=\"onFlyTo(item.id)\"\r\n >\r\n <i class=\"fa fa-crosshairs\" />\r\n </button>\r\n <button\r\n class=\"icon-btn icon-btn--danger\"\r\n title=\"删除\"\r\n @click.stop=\"onRemove(item.id)\"\r\n >\r\n <i class=\"fa fa-times\" />\r\n </button>\r\n </div>\r\n </div>\r\n </TransitionGroup>\r\n\r\n <!-- 空状态 -->\r\n <div v-if=\"filteredList.length === 0\" class=\"poi-panel__empty\">\r\n <i class=\"fa fa-map-o\" />\r\n <p>\r\n {{\r\n poi.isAddMode.value ? \"请在地图上点击添加标注\" : \"暂无标注数据\"\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, computed, inject } from \"vue\";\r\nimport type { UsePoiMarkerReturn, PoiItem } from \"./usePoiMarker\";\r\n\r\n// ─── 注入 POI 上下文(由 PoiMarkerLayer provide) ────────────────────────────\r\nconst poi = inject<UsePoiMarkerReturn>(\"poiContext\");\r\nif (!poi) throw new Error(\"[PoiMarkerPanel] 必须与 PoiMarkerLayer 同级使用\");\r\n\r\n// ─── 面板状态 ─────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(true);\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\n\r\n// ─── 拖拽移动 ─────────────────────────────────────────────────────────────────\r\nconst panelEl = ref<HTMLElement | null>(null);\r\nconst isDragging = ref(false);\r\n\r\n// 初始位置(可随需求调整)\r\nconst pos = reactive({ x: 10, y: 10 });\r\n\r\nlet dragStartX = 0;\r\nlet dragStartY = 0;\r\nlet origX = 0;\r\nlet origY = 0;\r\n\r\nfunction startDrag(e: MouseEvent) {\r\n isDragging.value = true;\r\n dragStartX = e.clientX;\r\n dragStartY = e.clientY;\r\n origX = pos.x;\r\n origY = pos.y;\r\n\r\n document.addEventListener(\"mousemove\", onDrag);\r\n document.addEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\nfunction onDrag(e: MouseEvent) {\r\n if (!isDragging.value) return;\r\n pos.x = origX + (e.clientX - dragStartX);\r\n pos.y = origY + (e.clientY - dragStartY);\r\n}\r\n\r\nfunction stopDrag() {\r\n isDragging.value = false;\r\n document.removeEventListener(\"mousemove\", onDrag);\r\n document.removeEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\n// ─── 分类筛选 ─────────────────────────────────────────────────────────────────\r\nconst categories = [\r\n { value: \"all\", label: \"全部\", icon: \"fa-list\", color: \"#aaa\" },\r\n { value: \"default\", label: \"普通\", icon: \"fa-map-marker\", color: \"#3ea6ff\" },\r\n {\r\n value: \"warning\",\r\n label: \"警告\",\r\n icon: \"fa-exclamation-triangle\",\r\n color: \"#ff6b6b\",\r\n },\r\n { value: \"info\", label: \"信息\", icon: \"fa-info-circle\", color: \"#52c41a\" },\r\n] as const;\r\n\r\nconst activeCategory = ref<string>(\"all\");\r\n\r\nconst filteredList = computed(() => {\r\n if (activeCategory.value === \"all\") return poi.poiList.value;\r\n return poi.poiList.value.filter((p) => p.category === activeCategory.value);\r\n});\r\n\r\nconst getCategoryColor = (cat: PoiItem[\"category\"]) => {\r\n const map: Record<string, string> = {\r\n default: \"#3ea6ff\",\r\n warning: \"#ff6b6b\",\r\n info: \"#52c41a\",\r\n };\r\n return map[cat] ?? \"#aaa\";\r\n};\r\n\r\n// ─── 添加模式 ─────────────────────────────────────────────────────────────────\r\nconst addCategory = ref<PoiItem[\"category\"]>(\"default\");\r\n\r\nfunction toggleAdd() {\r\n poi.toggleAddMode(\r\n undefined, // onAdded 回调(可按需传)\r\n \"标注点\",\r\n addCategory.value,\r\n );\r\n}\r\n\r\n// ─── 列表操作 ─────────────────────────────────────────────────────────────────\r\nfunction onSelect(id: string) {\r\n poi.selectPoi(id, true); // 选中并飞行\r\n}\r\n\r\nfunction onFlyTo(id: string) {\r\n poi.flyToPoi(id);\r\n}\r\n\r\nfunction onRemove(id: string) {\r\n poi.removePoi(id);\r\n}\r\n\r\n// ─── 编辑名称 ─────────────────────────────────────────────────────────────────\r\nconst editingId = ref<string | null>(null);\r\nconst editName = ref(\"\");\r\nconst editInputEl = ref<HTMLInputElement | null>(null);\r\n\r\nfunction startEdit(item: PoiItem) {\r\n editingId.value = item.id;\r\n editName.value = item.name;\r\n // DOM 更新后自动聚焦\r\n setTimeout(() => editInputEl.value?.select(), 30);\r\n}\r\n\r\nfunction saveEdit() {\r\n if (editingId.value && editName.value.trim()) {\r\n poi.updatePoiName(editingId.value, editName.value.trim());\r\n }\r\n cancelEdit();\r\n}\r\n\r\nfunction cancelEdit() {\r\n editingId.value = null;\r\n editName.value = \"\";\r\n}\r\n\r\nfunction confirmClear() {\r\n if (window.confirm(`确认清空全部 ${poi.poiList.value.length} 个标注?`)) {\r\n poi.clearAll();\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n// ─── 主面板 ────────────────────────────────────────────────────────────────────\r\n.poi-panel {\r\n position: absolute;\r\n width: 260px;\r\n height: auto;\r\n max-height: calc(100vh - 40px);\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px;\r\n z-index: 999;\r\n display: flex;\r\n flex-direction: column;\r\n backdrop-filter: blur(4px);\r\n transition: width 0.25s ease;\r\n\r\n // 收缩状态:只保留标题栏宽度,内容自适应高度\r\n &.collapsed {\r\n width: 46px;\r\n max-height: none;\r\n overflow: hidden;\r\n\r\n .poi-panel__title {\r\n display: none;\r\n }\r\n .poi-panel__body {\r\n display: none;\r\n }\r\n .collapse-icon {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n// ─── 标题栏 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__header {\r\n position: relative; // 为收缩态角标 absolute 定位提供参考\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 14px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 6px 0 0;\r\n cursor: grab;\r\n user-select: none;\r\n flex-shrink: 0;\r\n\r\n &.is-dragging {\r\n cursor: grabbing;\r\n }\r\n\r\n // 收缩后的图标态\r\n .collapsed-icon {\r\n display: none;\r\n color: #3ea6ff;\r\n font-size: 18px;\r\n }\r\n\r\n .poi-panel__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #e8f4ff;\r\n font-size: 14px;\r\n font-weight: 600;\r\n\r\n .fa {\r\n color: #3ea6ff;\r\n font-size: 15px;\r\n }\r\n }\r\n\r\n .poi-count {\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 11px;\r\n padding: 1px 6px;\r\n border-radius: 10px;\r\n min-width: 18px;\r\n text-align: center;\r\n }\r\n\r\n .collapse-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n }\r\n}\r\n\r\n// 收缩态:图标自适应高度,角标定位在图标右上角\r\n.poi-panel.collapsed .poi-panel__header {\r\n flex-direction: column;\r\n align-items: flex-start; // 左对齐\r\n padding: 8px 10px 10px; // 底部留更多空间\r\n gap: 0;\r\n cursor: pointer;\r\n\r\n // 图标 + 角标一体化容器,图标在左下\r\n .collapsed-icon-wrap {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-top: 12px; // 往下一点\r\n margin-left: 2px;\r\n }\r\n\r\n .collapsed-icon {\r\n display: block;\r\n font-size: 20px;\r\n color: #3ea6ff;\r\n }\r\n\r\n // 角标:相对于图标容器定位,落在图标右上角\r\n .poi-count--collapsed {\r\n display: block;\r\n position: absolute;\r\n top: -10px;\r\n right: -12px;\r\n min-width: 16px;\r\n height: 16px;\r\n line-height: 16px;\r\n font-size: 10px;\r\n padding: 0 3px;\r\n background: #3ea6ff;\r\n color: #fff;\r\n border-radius: 8px;\r\n }\r\n}\r\n\r\n// ─── 面板体 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__body {\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n// ─── 操作栏 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__toolbar {\r\n display: flex;\r\n gap: 8px;\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .btn {\r\n flex: 1;\r\n padding: 6px 8px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.35);\r\n color: #fff;\r\n border-color: #3ea6ff;\r\n }\r\n &--danger {\r\n flex: 0 0 auto;\r\n border-color: rgba(255, 100, 100, 0.4);\r\n background: rgba(255, 100, 100, 0.1);\r\n color: #ffaaaa;\r\n &:hover:not(:disabled) {\r\n background: rgba(255, 100, 100, 0.25);\r\n color: #fff;\r\n }\r\n &:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 分类筛选 ──────────────────────────────────────────────────────────────────\r\n.poi-panel__filter {\r\n display: flex;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n flex-wrap: wrap;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .filter-tag {\r\n padding: 3px 8px;\r\n border-radius: 12px;\r\n font-size: 11px;\r\n color: #7a9ec0;\r\n background: rgba(255, 255, 255, 0.06);\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(255, 255, 255, 0.12);\r\n color: #c8dff0;\r\n }\r\n &.active {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #3ea6ff;\r\n }\r\n }\r\n}\r\n\r\n// ─── 列表 ──────────────────────────────────────────────────────────────────────\r\n.poi-panel__list {\r\n overflow-y: auto;\r\n max-height: calc(100vh - 220px);\r\n padding: 6px 0;\r\n\r\n &::-webkit-scrollbar {\r\n width: 4px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n\r\n.poi-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background 0.15s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.1);\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.18);\r\n }\r\n\r\n &__dot {\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__info {\r\n flex: 1;\r\n min-width: 0;\r\n &-name {\r\n overflow: hidden;\r\n }\r\n }\r\n\r\n &__name {\r\n font-size: 13px;\r\n color: #d8ecff;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n cursor: text;\r\n\r\n &:hover {\r\n color: #a0d4ff;\r\n }\r\n }\r\n\r\n &__name-input {\r\n width: 100%;\r\n font-size: 13px;\r\n color: #e8f4ff;\r\n background: rgba(62, 166, 255, 0.15);\r\n border: 1px solid rgba(62, 166, 255, 0.5);\r\n border-radius: 3px;\r\n padding: 1px 5px;\r\n outline: none;\r\n font-family: inherit;\r\n\r\n &:focus {\r\n border-color: #3ea6ff;\r\n background: rgba(62, 166, 255, 0.22);\r\n }\r\n }\r\n\r\n &__coord {\r\n font-size: 11px;\r\n color: #5a7a9a;\r\n margin-top: 2px;\r\n font-family: monospace;\r\n }\r\n\r\n &__actions {\r\n display: flex;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n opacity: 0;\r\n transition: opacity 0.15s ease;\r\n }\r\n\r\n &:hover &__actions {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.icon-btn {\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: rgba(255, 255, 255, 0.08);\r\n color: #9dc8f0;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n transition: all 0.15s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n &--danger:hover {\r\n background: rgba(255, 80, 80, 0.35);\r\n color: #fff;\r\n }\r\n}\r\n\r\n// ─── 空状态 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__empty {\r\n text-align: center;\r\n padding: 30px 20px;\r\n color: #4a6a8a;\r\n\r\n .fa {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: block;\r\n }\r\n p {\r\n font-size: 12px;\r\n margin: 0;\r\n line-height: 1.6;\r\n }\r\n}\r\n\r\n// ─── 列表动画 ──────────────────────────────────────────────────────────────────\r\n.poi-list-enter-active,\r\n.poi-list-leave-active {\r\n transition: all 0.25s ease;\r\n}\r\n.poi-list-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n.poi-list-leave-to {\r\n opacity: 0;\r\n transform: translateX(12px);\r\n}\r\n</style>\r\n","/**\r\n * useTrack — 轨迹管理 composable\r\n *\r\n * 职责:\r\n * - 维护轨迹数据列表(历史轨迹 + 实时轨迹)\r\n * - 管理地图上的折线图形(PolylinePrimitive / CorridorPrimitive)\r\n * - 提供历史轨迹回放(播放 / 暂停 / 倍速 / 进度拖拽)\r\n * - 提供实时轨迹推送(持续追加坐标点)\r\n * - 数据与图形保持双向同步\r\n *\r\n * 使用方式(在 TrackLayer 内):\r\n * const mapCtx = inject<UseMapReturn>('mapContext')!\r\n * const track = useTrack(mapCtx)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\n\r\n// ─── 数据类型 ─────────────────────────────────────────────────────────────────\r\n\r\n/** 轨迹点 */\r\nexport interface TrackPoint {\r\n time: number; // Unix 时间戳(毫秒)\r\n lng: number;\r\n lat: number;\r\n alt: number;\r\n}\r\n\r\n/** 单条轨迹 */\r\nexport interface TrackItem {\r\n id: string;\r\n name: string;\r\n /** 轨迹点列表(按时间排序) */\r\n points: TrackPoint[];\r\n /** 轨迹线图形 */\r\n lineGraphic?: any;\r\n /** 实时模式下:当前\"已绘制\"到的点索引 */\r\n realtimeDrawnIdx?: number;\r\n /** 实时模式下:当前实时点图形 */\r\n realtimePoint?: any;\r\n /** 实时模式下:当前车头图标 */\r\n realtimeHeading?: any;\r\n /** 实时模式下:所有线段图形(用于删除时统一清理) */\r\n realtimeLineSegments?: any[];\r\n /** 回放开始时间戳 */\r\n _playStartTime?: number;\r\n}\r\n\r\nlet _idCounter = 1;\r\n\r\nexport function useTrack(mapCtx: UseMapReturn) {\r\n // ─── 图层 ─────────────────────────────────────────────────────────────────\r\n const trackLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── 轨迹列表 ─────────────────────────────────────────────────────────────\r\n const trackList = ref<TrackItem[]>([]);\r\n\r\n // ─── 当前选中 / 回放的轨迹 ────────────────────────────────────────────────\r\n const activeTrackId = ref<string | null>(null);\r\n\r\n // ─── 回放状态 ─────────────────────────────────────────────────────────────\r\n const isPlaying = ref(false);\r\n const currentTime = ref(0); // 当前回放时间戳\r\n const playbackSpeed = ref(1); // 倍速(1x / 2x / 4x / 8x)\r\n const playbackProgress = ref(0); // 0~100 百分比\r\n\r\n // ─── 实时模式标记 ──────────────────────────────────────────────────────────\r\n const isRealtimeMode = ref(false);\r\n const activeRealtimeId = ref<string | null>(null);\r\n\r\n // ─── 回放定时器 ───────────────────────────────────────────────────────────\r\n let _playInterval: ReturnType<typeof setInterval> | null = null;\r\n let _realtimeInterval: ReturnType<typeof setInterval> | null = null;\r\n\r\n // ─── 初始化图层 ────────────────────────────────────────────────────────────\r\n function initTrackLayer() {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n const layer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(layer);\r\n trackLayer.value = layer;\r\n }\r\n\r\n // ─── 内部:绘制完整折线 ────────────────────────────────────────────────────\r\n function _buildLineGraphic(track: TrackItem) {\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n // 只画已有坐标\r\n const positions = track.points.map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n const line = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#3ea6ff\") as any,\r\n width: 3,\r\n opacity: 0.9,\r\n clampToGround: false,\r\n },\r\n attr: { trackId: track.id },\r\n });\r\n\r\n layer.addGraphic(line);\r\n return line;\r\n }\r\n\r\n // ─── 内部:实时追加一段线 ──────────────────────────────────────────────────\r\n function _appendRealtimeLine(track: TrackItem, fromIdx: number, toIdx: number) {\r\n const layer = trackLayer.value;\r\n if (!layer || toIdx <= fromIdx) return;\r\n\r\n const positions = track.points.slice(fromIdx, toIdx + 1)\r\n .map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n const segment = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#ff6b35\") as any,\r\n width: 4,\r\n opacity: 1,\r\n clampToGround: false,\r\n },\r\n });\r\n layer.addGraphic(segment);\r\n // 记录线段引用,用于删除时统一清理\r\n if (!track.realtimeLineSegments) {\r\n track.realtimeLineSegments = [];\r\n }\r\n track.realtimeLineSegments.push(segment);\r\n }\r\n\r\n // ─── 内部:更新实时点位图标 ─────────────────────────────────────────────────\r\n function _updateRealtimeMarker(track: TrackItem) {\r\n const layer = trackLayer.value;\r\n if (!layer) return;\r\n\r\n const lastPoint = track.points[track.realtimeDrawnIdx!];\r\n if (!lastPoint) return;\r\n\r\n // 更新图标位置\r\n if (track.realtimePoint) {\r\n track.realtimePoint.position = [lastPoint.lng, lastPoint.lat, lastPoint.alt];\r\n } else {\r\n const marker = new mars3d.graphic.BillboardEntity({\r\n position: [lastPoint.lng, lastPoint.lat, lastPoint.alt],\r\n style: {\r\n image: \"//data.mars3d.cn/img/marker/mark-blue.png\",\r\n scale: 1.2,\r\n horizontalOrigin: mars3d.Cesium.HorizontalOrigin.CENTER,\r\n verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,\r\n },\r\n });\r\n layer.addGraphic(marker);\r\n track.realtimePoint = marker;\r\n }\r\n }\r\n\r\n // ─── 添加历史轨迹(从预置数据回放) ─────────────────────────────────────────\r\n function addTrack(points: TrackPoint[], name = \"轨迹\") {\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `track-${_idCounter++}`;\r\n const track: TrackItem = { id, name, points };\r\n track.lineGraphic = _buildLineGraphic(track);\r\n trackList.value.push(track);\r\n return track;\r\n }\r\n\r\n // ─── 开始实时轨迹推送 ──────────────────────────────────────────────────────\r\n function startRealtime(name = \"实时轨迹\") {\r\n if (activeRealtimeId.value) stopRealtime();\r\n\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `realtime-${_idCounter++}`;\r\n const track: TrackItem = {\r\n id,\r\n name,\r\n points: [],\r\n realtimeDrawnIdx: -1,\r\n };\r\n trackLayer.value = layer;\r\n trackList.value.push(track);\r\n activeRealtimeId.value = id;\r\n isRealtimeMode.value = true;\r\n return track;\r\n }\r\n\r\n // ─── 推送实时坐标点 ───────────────────────────────────────────────────────\r\n function pushRealtimePoint(id: string, lng: number, lat: number, alt = 0) {\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track) return;\r\n\r\n const point: TrackPoint = {\r\n time: Date.now(),\r\n lng,\r\n lat,\r\n alt,\r\n };\r\n track.points.push(point);\r\n track.realtimeDrawnIdx = track.points.length - 1;\r\n\r\n // 首次:直接建线和图标\r\n if (track.points.length === 1) {\r\n track.lineGraphic = _buildLineGraphic(track);\r\n _updateRealtimeMarker(track);\r\n } else {\r\n // 追加一段折线\r\n _appendRealtimeLine(track, track.points.length - 2, track.points.length - 1);\r\n _updateRealtimeMarker(track);\r\n }\r\n\r\n // 自动飞行跟随(最后一点)\r\n if (mapCtx.map.value) {\r\n mapCtx.map.value.flyToPoint(\r\n [lng, lat, alt + 50],\r\n { radius: 500, duration: 0.5 },\r\n );\r\n }\r\n }\r\n\r\n // ─── 停止实时推送(固化轨迹) ──────────────────────────────────────────────\r\n function stopRealtime(id?: string) {\r\n const targetId = id ?? activeRealtimeId.value;\r\n if (!targetId) return;\r\n\r\n const track = trackList.value.find((t) => t.id === targetId);\r\n if (track) {\r\n track.realtimeDrawnIdx = undefined;\r\n if (track.realtimePoint) {\r\n trackLayer.value?.removeGraphic(track.realtimePoint);\r\n track.realtimePoint = undefined;\r\n }\r\n }\r\n\r\n if (activeRealtimeId.value === targetId) {\r\n activeRealtimeId.value = null;\r\n isRealtimeMode.value = false;\r\n }\r\n }\r\n\r\n // ─── 历史轨迹回放 ─────────────────────────────────────────────────────────\r\n function play(trackId?: string) {\r\n const id = trackId ?? activeTrackId.value;\r\n if (!id) return;\r\n\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track || track.points.length < 2) return;\r\n\r\n if (activeTrackId.value !== id) {\r\n selectTrack(id);\r\n }\r\n\r\n isPlaying.value = true;\r\n _clearPlayInterval();\r\n\r\n const start = track.points[0].time;\r\n const end = track.points[track.points.length - 1].time;\r\n const totalMs = end - start;\r\n\r\n // 进度每帧更新\r\n _playInterval = setInterval(() => {\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (!track || !isPlaying.value) return;\r\n\r\n const elapsed = Date.now() - (track._playStartTime ?? Date.now());\r\n const total = end - start;\r\n const progress = Math.min(elapsed / total, 1);\r\n\r\n // 更新当前时间 → 驱动进度条\r\n currentTime.value = start + progress * total;\r\n playbackProgress.value = progress * 100;\r\n\r\n // 逐步绘制轨迹\r\n const targetIdx = Math.floor(progress * (track.points.length - 1));\r\n _updatePlaybackLine(track, targetIdx);\r\n }, 60);\r\n }\r\n\r\n function _updatePlaybackLine(track: TrackItem, toIdx: number) {\r\n const layer = trackLayer.value;\r\n if (!layer) return;\r\n\r\n // 清除旧线\r\n if (track.lineGraphic) {\r\n layer.removeGraphic(track.lineGraphic);\r\n }\r\n\r\n // 画到 toIdx 位置\r\n const positions = track.points.slice(0, toIdx + 1)\r\n .map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n track.lineGraphic = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#00ff88\") as any,\r\n width: 4,\r\n opacity: 1,\r\n clampToGround: false,\r\n },\r\n });\r\n layer.addGraphic(track.lineGraphic);\r\n\r\n // 画当前点位\r\n const pt = track.points[toIdx];\r\n mapCtx.map.value?.flyToPoint(\r\n [pt.lng, pt.lat, pt.alt + 200],\r\n { radius: 300, duration: 0 },\r\n );\r\n }\r\n\r\n function pause() {\r\n isPlaying.value = false;\r\n _clearPlayInterval();\r\n }\r\n\r\n function stop() {\r\n isPlaying.value = false;\r\n playbackProgress.value = 0;\r\n currentTime.value = 0;\r\n _clearPlayInterval();\r\n\r\n // 恢复整条轨迹\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (track && trackLayer.value) {\r\n if (track.lineGraphic) trackLayer.value.removeGraphic(track.lineGraphic);\r\n track.lineGraphic = _buildLineGraphic(track);\r\n }\r\n }\r\n\r\n function setSpeed(speed: number) {\r\n playbackSpeed.value = speed;\r\n if (isPlaying.value) {\r\n pause();\r\n play();\r\n }\r\n }\r\n\r\n /** 跳转到指定进度(0~100) */\r\n function seek(progress: number) {\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (!track) return;\r\n\r\n const targetIdx = Math.floor((progress / 100) * (track.points.length - 1));\r\n currentTime.value = track.points[targetIdx].time;\r\n playbackProgress.value = progress;\r\n _updatePlaybackLine(track, targetIdx);\r\n }\r\n\r\n // ─── 选中轨迹 ─────────────────────────────────────────────────────────────\r\n function selectTrack(id: string) {\r\n activeTrackId.value = id;\r\n stop();\r\n }\r\n\r\n /** 飞行到轨迹概览 */\r\n function flyToTrack(id: string) {\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track || !mapCtx.map.value) return;\r\n\r\n const first = track.points[0];\r\n mapCtx.map.value.flyToPoint(\r\n [first.lng, first.lat, first.alt + 2000],\r\n { radius: 3000, duration: 1.5 },\r\n );\r\n }\r\n\r\n // ─── 删除 / 清空 ───────────────────────────────────────────────────────────\r\n function removeTrack(id: string) {\r\n const idx = trackList.value.findIndex((t) => t.id === id);\r\n if (idx === -1) return;\r\n\r\n const track = trackList.value[idx];\r\n if (track.lineGraphic) trackLayer.value?.removeGraphic(track.lineGraphic);\r\n if (track.realtimePoint) trackLayer.value?.removeGraphic(track.realtimePoint);\r\n // 删除实时轨迹的所有线段\r\n if (track.realtimeLineSegments) {\r\n track.realtimeLineSegments.forEach((seg) => {\r\n trackLayer.value?.removeGraphic(seg);\r\n });\r\n }\r\n trackList.value.splice(idx, 1);\r\n\r\n if (activeTrackId.value === id) {\r\n activeTrackId.value = null;\r\n stop();\r\n }\r\n if (activeRealtimeId.value === id) {\r\n activeRealtimeId.value = null;\r\n isRealtimeMode.value = false;\r\n }\r\n }\r\n\r\n function clearAll() {\r\n stop();\r\n stopRealtime();\r\n trackLayer.value?.clear();\r\n trackList.value = [];\r\n activeTrackId.value = null;\r\n }\r\n\r\n // ─── 内部工具 ─────────────────────────────────────────────────────────────\r\n function _clearPlayInterval() {\r\n if (_playInterval) {\r\n clearInterval(_playInterval);\r\n _playInterval = null;\r\n }\r\n }\r\n\r\n return {\r\n trackLayer,\r\n trackList,\r\n activeTrackId,\r\n isPlaying,\r\n currentTime,\r\n playbackSpeed,\r\n playbackProgress,\r\n isRealtimeMode,\r\n activeRealtimeId,\r\n initTrackLayer,\r\n addTrack,\r\n startRealtime,\r\n pushRealtimePoint,\r\n stopRealtime,\r\n play,\r\n pause,\r\n stop,\r\n setSpeed,\r\n seek,\r\n selectTrack,\r\n flyToTrack,\r\n removeTrack,\r\n clearAll,\r\n };\r\n}\r\n\r\nexport type UseTrackReturn = ReturnType<typeof useTrack>;\r\n","<!--\r\n TrackLayer — 轨迹组件逻辑层\r\n\r\n 职责:\r\n - 放置在 MarsMapContainer 的 slot 内(通过 <slot /> 渲染子组件)\r\n - inject mapContext,初始化轨迹图层\r\n - provide trackContext,供子组件 inject 使用\r\n - expose useTrack 全量接口,供父组件 ref 访问\r\n\r\n 使用方式(Panel 必须作为子内容传入):\r\n <MarsMapContainer>\r\n <TrackLayer ref=\"trackLayerRef\">\r\n <TrackPanel />\r\n </TrackLayer>\r\n </MarsMapContainer>\r\n-->\r\n<template>\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject, provide, watch, onUnmounted } from \"vue\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\nimport { useTrack } from \"./useTrack\";\r\n\r\n// ─── 注入地图上下文 ──────────────────────────────────────────────────────────\r\nconst mapCtx = inject<UseMapReturn>(\"mapContext\");\r\nif (!mapCtx) throw new Error(\"[TrackLayer] 必须放置在 MarsMapContainer 内部\");\r\n\r\n// ─── 初始化轨迹管理 ──────────────────────────────────────────────────────────\r\nconst track = useTrack(mapCtx);\r\n\r\n// ─── 等待地图就绪后初始化图层 ───────────────────────────────────────────────\r\nconst stopWatch = watch(\r\n () => mapCtx.map.value,\r\n (map) => {\r\n if (map) {\r\n track.initTrackLayer();\r\n stopWatch();\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonUnmounted(() => {\r\n track.clearAll();\r\n});\r\n\r\n// ─── provide 给子组件 ───────────────────────────────────────────────────────\r\nprovide(\"trackContext\", track);\r\n\r\n// ─── expose 给父组件 ref ───────────────────────────────────────────────────\r\ndefineExpose(track);\r\n</script>\r\n","<!--\r\n TrackPanel — 轨迹管理面板\r\n\r\n 功能:\r\n - 轨迹列表管理(添加历史轨迹 / 实时轨迹)\r\n - 历史轨迹回放控制(播放 / 暂停 / 停止 / 倍速 / 进度拖拽)\r\n - 实时轨迹推送(开始 / 追加模拟点 / 停止)\r\n - 拖拽移动 + 收缩图标态\r\n\r\n 数据来源:inject('trackContext'),由 TrackLayer provide\r\n-->\r\n<template>\r\n <div\r\n class=\"track-panel\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :style=\"{ left: pos.x + 'px', top: pos.y + 'px' }\"\r\n >\r\n <!-- 标题栏(可拖拽) -->\r\n <div\r\n class=\"track-panel__header\"\r\n :class=\"{ 'is-dragging': isDragging }\"\r\n @mousedown.prevent=\"startDrag\"\r\n @click=\"isDragging ? null : toggleCollapse()\"\r\n >\r\n <template v-if=\"isCollapsed\">\r\n <div class=\"collapsed-icon-wrap\">\r\n <i class=\"fa fa-share-alt collapsed-icon\" />\r\n <span class=\"track-badge\">{{ track.trackList.value.length }}</span>\r\n </div>\r\n </template>\r\n <template v-else>\r\n <span class=\"track-panel__title\">\r\n <i class=\"fa fa-share-alt\" />\r\n 轨迹管理\r\n <span class=\"track-count\">{{ track.trackList.value.length }}</span>\r\n </span>\r\n <i class=\"fa fa-chevron-left collapse-icon\" />\r\n </template>\r\n </div>\r\n\r\n <!-- 面板体 -->\r\n <div class=\"track-panel__body\" v-show=\"!isCollapsed\">\r\n <!-- ── 操作栏 ── -->\r\n <div class=\"track-panel__toolbar\">\r\n <button class=\"btn btn--primary\" @click=\"addDemoTrack\">\r\n <i class=\"fa fa-plus\" /> 历史轨迹\r\n </button>\r\n <button\r\n class=\"btn\"\r\n :class=\"track.isRealtimeMode.value ? 'btn--active' : 'btn--info'\"\r\n @click=\"toggleRealtime\"\r\n >\r\n <i\r\n :class=\"['fa', track.isRealtimeMode.value ? 'fa-stop' : 'fa-bolt']\"\r\n />\r\n {{ track.isRealtimeMode.value ? \"停止推送\" : \"实时轨迹\" }}\r\n </button>\r\n <button\r\n class=\"btn btn--danger\"\r\n @click=\"confirmClear\"\r\n :disabled=\"track.trackList.value.length === 0\"\r\n >\r\n <i class=\"fa fa-trash-o\" />\r\n </button>\r\n </div>\r\n\r\n <!-- ── 回放控制(选中轨迹时显示) ── -->\r\n <div class=\"track-panel__playback\" v-if=\"track.activeTrackId.value\">\r\n <!-- 轨迹名称 -->\r\n <div class=\"playback__track-name\">\r\n <i class=\"fa fa-road\" />\r\n {{ activeTrackName }}\r\n <span class=\"playback__mode-badge\">历史回放</span>\r\n </div>\r\n\r\n <!-- 播放按钮组 -->\r\n <div class=\"playback__controls\">\r\n <button class=\"ctrl-btn\" @click=\"track.stop()\">\r\n <i class=\"fa fa-stop\" />\r\n </button>\r\n <button\r\n class=\"ctrl-btn ctrl-btn--play\"\r\n @click=\"track.isPlaying.value ? track.pause() : track.play()\"\r\n >\r\n <i\r\n :class=\"['fa', track.isPlaying.value ? 'fa-pause' : 'fa-play']\"\r\n />\r\n </button>\r\n <button class=\"ctrl-btn\" @click=\"track.play()\">\r\n <i class=\"fa fa-refresh\" />\r\n </button>\r\n </div>\r\n\r\n <!-- 倍速选择 -->\r\n <div class=\"playback__speed\">\r\n <span class=\"speed-label\">倍速</span>\r\n <div class=\"speed-btns\">\r\n <button\r\n v-for=\"s in speedOptions\"\r\n :key=\"s\"\r\n class=\"speed-btn\"\r\n :class=\"{ active: track.playbackSpeed.value === s }\"\r\n @click=\"track.setSpeed(s)\"\r\n >\r\n {{ s }}x\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- 进度条 -->\r\n <div class=\"playback__timeline\">\r\n <span class=\"time-label\">{{\r\n formatTime(track.currentTime.value)\r\n }}</span>\r\n <input\r\n type=\"range\"\r\n class=\"progress-slider\"\r\n min=\"0\"\r\n max=\"100\"\r\n step=\"0.1\"\r\n :value=\"track.playbackProgress.value\"\r\n @input=\"onSeek\"\r\n />\r\n <span class=\"time-label\">{{ formatTime(trackMaxTime) }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- ── 实时模式指示 ── -->\r\n <div\r\n class=\"track-panel__realtime-hint\"\r\n v-if=\"track.isRealtimeMode.value && !track.activeTrackId.value\"\r\n >\r\n <div class=\"realtime-pulse\">\r\n <i class=\"fa fa-bolt\" />\r\n 实时推送中\r\n <span class=\"blink-dot\" />\r\n </div>\r\n <div class=\"realtime-count\">\r\n 已推送 <strong>{{ realtimePointCount }}</strong> 个坐标点\r\n </div>\r\n </div>\r\n\r\n <!-- ── 轨迹列表 ── -->\r\n <div class=\"track-panel__list\">\r\n <TransitionGroup name=\"track-list\">\r\n <div\r\n v-for=\"item in track.trackList.value\"\r\n :key=\"item.id\"\r\n class=\"track-item\"\r\n :class=\"{\r\n 'track-item--active': track.activeTrackId.value === item.id,\r\n 'track-item--realtime': item.id.startsWith('realtime'),\r\n }\"\r\n @click=\"onSelectTrack(item.id)\"\r\n >\r\n <!-- 颜色条 -->\r\n <span\r\n class=\"track-item__bar\"\r\n :style=\"{\r\n background: item.id.startsWith('realtime')\r\n ? '#ff6b35'\r\n : '#3ea6ff',\r\n }\"\r\n />\r\n\r\n <div class=\"track-item__info\">\r\n <div class=\"track-item__name\">\r\n <i\r\n :class=\"[\r\n 'fa',\r\n item.id.startsWith('realtime') ? 'fa-bolt' : 'fa-road',\r\n ]\"\r\n />\r\n {{ item.name }}\r\n </div>\r\n <div class=\"track-item__meta\">\r\n {{ item.points.length }} 个点\r\n <span v-if=\"item.id.startsWith('realtime')\" class=\"realtime-tag\"\r\n >实时</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <div class=\"track-item__actions\">\r\n <button\r\n class=\"icon-btn\"\r\n title=\"飞行\"\r\n @click.stop=\"track.flyToTrack(item.id)\"\r\n >\r\n <i class=\"fa fa-crosshairs\" />\r\n </button>\r\n <button\r\n class=\"icon-btn icon-btn--danger\"\r\n title=\"删除\"\r\n @click.stop=\"track.removeTrack(item.id)\"\r\n >\r\n <i class=\"fa fa-times\" />\r\n </button>\r\n </div>\r\n </div>\r\n </TransitionGroup>\r\n\r\n <!-- 空状态 -->\r\n <div\r\n v-if=\"track.trackList.value.length === 0\"\r\n class=\"track-panel__empty\"\r\n >\r\n <i class=\"fa fa-map-o\" />\r\n <p>暂无轨迹数据</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, inject, reactive } from \"vue\";\r\nimport type { UseTrackReturn } from \"./useTrack\";\r\n\r\n// ─── 注入轨迹上下文 ──────────────────────────────────────────────────────────\r\nconst track = inject<UseTrackReturn>(\"trackContext\");\r\nif (!track) throw new Error(\"[TrackPanel] 必须与 TrackLayer 同级使用\");\r\n\r\n// ─── 拖拽 ──────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(true);\r\nconst isDragging = ref(false);\r\nconst pos = reactive({ x: 10, y: 80 }); // 默认错开 POI 面板\r\n\r\nlet dragStartX = 0,\r\n dragStartY = 0,\r\n origX = 0,\r\n origY = 0;\r\n\r\nfunction toggleCollapse() {\r\n isCollapsed.value = !isCollapsed.value;\r\n}\r\n\r\nfunction startDrag(e: MouseEvent) {\r\n isDragging.value = true;\r\n dragStartX = e.clientX;\r\n dragStartY = e.clientY;\r\n origX = pos.x;\r\n origY = pos.y;\r\n document.addEventListener(\"mousemove\", onDrag);\r\n document.addEventListener(\"mouseup\", stopDrag);\r\n}\r\nfunction onDrag(e: MouseEvent) {\r\n if (!isDragging.value) return;\r\n pos.x = origX + (e.clientX - dragStartX);\r\n pos.y = origY + (e.clientY - dragStartY);\r\n}\r\nfunction stopDrag() {\r\n isDragging.value = false;\r\n document.removeEventListener(\"mousemove\", onDrag);\r\n document.removeEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\n// ─── 选中轨迹 ──────────────────────────────────────────────────────────────\r\nfunction onSelectTrack(id: string) {\r\n if (track.activeTrackId.value === id) return;\r\n track.selectTrack(id);\r\n track.stop();\r\n}\r\n\r\nconst activeTrackName = computed(() => {\r\n const t = track.trackList.value.find(\r\n (x) => x.id === track.activeTrackId.value,\r\n );\r\n return t?.name ?? \"\";\r\n});\r\n\r\nconst trackMaxTime = computed(() => {\r\n const t = track.trackList.value.find(\r\n (x) => x.id === track.activeTrackId.value,\r\n );\r\n if (!t || t.points.length < 2) return 0;\r\n return t.points[t.points.length - 1].time;\r\n});\r\n\r\n// ─── 倍速选项 ──────────────────────────────────────────────────────────────\r\nconst speedOptions = [1, 2, 4, 8];\r\n\r\n// ─── 进度拖拽 ─────────────────────────────────────────────────────────────\r\nfunction onSeek(e: Event) {\r\n const val = parseFloat((e.target as HTMLInputElement).value);\r\n track.seek(val);\r\n}\r\n\r\n// ─── 时间格式化 ────────────────────────────────────────────────────────────\r\nfunction formatTime(ts: number): string {\r\n if (!ts) return \"00:00\";\r\n const d = new Date(ts);\r\n return `${String(d.getMinutes()).padStart(2, \"0\")}:${String(d.getSeconds()).padStart(2, \"0\")}`;\r\n}\r\n\r\n// ─── 添加演示历史轨迹 ─────────────────────────────────────────────────────\r\nfunction addDemoTrack() {\r\n // 生成一段北京区域贴近实际的路径:方向惯性 + 高度随路线起伏\r\n const baseLng = 116.3974;\r\n const baseLat = 39.909;\r\n const points = [];\r\n let t = Date.now();\r\n\r\n // 初始方向角(弧度)\r\n let heading = Math.random() * Math.PI * 2;\r\n const STEP = 20; // 减少到 20 个点\r\n\r\n for (let i = 0; i < STEP; i++) {\r\n t += 5000 + Math.random() * 5000;\r\n // 方向每步微调 ±15°,模拟沿道路行驶\r\n heading += (Math.random() - 0.5) * (Math.PI / 6);\r\n const stepLng = baseLng + Math.cos(heading) * 0.004;\r\n const stepLat = baseLat + Math.sin(heading) * 0.002;\r\n const alt = 30 + Math.sin((i / STEP) * Math.PI) * 80; // 拱形起伏\r\n points.push({ time: t, lng: stepLng, lat: stepLat, alt });\r\n }\r\n\r\n track.addTrack(points, `轨迹 ${_counter++}`);\r\n}\r\n\r\nlet _counter = 1;\r\n\r\n// ─── 实时轨迹 ─────────────────────────────────────────────────────────────\r\nlet _realtimeTimer: ReturnType<typeof setInterval> | null = null;\r\nlet _currentRealtimeId: string | null = null;\r\n\r\nfunction toggleRealtime() {\r\n if (track.isRealtimeMode.value) {\r\n stopRealtime();\r\n } else {\r\n startRealtime();\r\n }\r\n}\r\n\r\nfunction startRealtime() {\r\n const id = track.startRealtime(`实时轨迹 ${_counter++}`)?.id;\r\n if (!id) return;\r\n _currentRealtimeId = id;\r\n\r\n // 天安门坐标(圆心)\r\n const CENTER_LNG = 116.397;\r\n const CENTER_LAT = 39.908;\r\n // 绕圈半径(约 400 米)\r\n const RADIUS_LNG = 0.004;\r\n const RADIUS_LAT = 0.003;\r\n // 总共 36 个点,每 10° 一个点,完成一圈\r\n const TOTAL_POINTS = 36;\r\n const ANGLE_STEP = (2 * Math.PI) / TOTAL_POINTS;\r\n // 初始角度随机,让起点不在固定位置\r\n let angle = Math.random() * 2 * Math.PI;\r\n let pushCount = 0;\r\n\r\n _realtimeTimer = setInterval(() => {\r\n pushCount++;\r\n // 沿圆形轨迹移动\r\n const lng = CENTER_LNG + Math.cos(angle) * RADIUS_LNG;\r\n const lat = CENTER_LAT + Math.sin(angle) * RADIUS_LAT;\r\n const alt = 40 + Math.sin(angle * 3) * 20; // 高度随位置微微起伏\r\n track.pushRealtimePoint(id, lng, lat, alt);\r\n\r\n // 角度递增,绘制下一位置\r\n angle += ANGLE_STEP;\r\n\r\n // 完成一圈后自动停止\r\n if (pushCount >= TOTAL_POINTS) {\r\n stopRealtime();\r\n }\r\n }, 800);\r\n}\r\n\r\nfunction stopRealtime() {\r\n if (_realtimeTimer) {\r\n clearInterval(_realtimeTimer);\r\n _realtimeTimer = null;\r\n }\r\n if (_currentRealtimeId) {\r\n track.stopRealtime(_currentRealtimeId);\r\n _currentRealtimeId = null;\r\n }\r\n}\r\n\r\nconst realtimePointCount = computed(() => {\r\n const t = track.trackList.value.find((x) => x.id === _currentRealtimeId);\r\n return t?.points.length ?? 0;\r\n});\r\n\r\n// ─── 清空 ─────────────────────────────────────────────────────────────────\r\nfunction confirmClear() {\r\n if (window.confirm(`确认清空全部 ${track.trackList.value.length} 条轨迹?`)) {\r\n stopRealtime();\r\n track.clearAll();\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n// ─── 主面板 ─────────────────────────────────────────────────────────────────\r\n.track-panel {\r\n position: absolute;\r\n width: 280px;\r\n height: auto;\r\n max-height: calc(100vh - 40px);\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px;\r\n z-index: 998;\r\n display: flex;\r\n flex-direction: column;\r\n backdrop-filter: blur(4px);\r\n transition: width 0.25s ease;\r\n\r\n &.collapsed {\r\n width: 46px;\r\n max-height: none;\r\n overflow: hidden;\r\n\r\n .track-panel__title {\r\n display: none;\r\n }\r\n .track-panel__body {\r\n display: none;\r\n }\r\n .collapse-icon {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n// ─── 标题栏 ────────────────────────────────────────────────────────────────\r\n.track-panel__header {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 14px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 6px 0 0;\r\n cursor: grab;\r\n user-select: none;\r\n flex-shrink: 0;\r\n\r\n &.is-dragging {\r\n cursor: grabbing;\r\n }\r\n\r\n .collapsed-icon {\r\n display: none;\r\n color: #ff6b35;\r\n font-size: 18px;\r\n }\r\n\r\n .track-panel__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #e8f4ff;\r\n font-size: 14px;\r\n font-weight: 600;\r\n .fa {\r\n color: #ff6b35;\r\n font-size: 15px;\r\n }\r\n }\r\n\r\n // 展开态角标(红色)\r\n .track-count {\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 11px;\r\n padding: 1px 6px;\r\n border-radius: 10px;\r\n min-width: 18px;\r\n text-align: center;\r\n }\r\n\r\n .collapse-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n }\r\n}\r\n\r\n// 收缩态\r\n.track-panel.collapsed .track-panel__header {\r\n flex-direction: column;\r\n align-items: flex-start; // 左对齐\r\n padding: 8px 10px 10px; // 底部留更多空间\r\n gap: 0;\r\n cursor: pointer;\r\n\r\n // 图标 + 角标一体化容器,图标在左下,角标叠在图标右上\r\n .collapsed-icon-wrap {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-top: 12px; // 往下一点\r\n margin-left: 2px; // 往左一点\r\n }\r\n\r\n .collapsed-icon {\r\n display: block;\r\n color: #ff6b35;\r\n font-size: 18px;\r\n }\r\n\r\n // 角标:相对于图标容器定位,落在图标右上角\r\n .track-badge {\r\n position: absolute;\r\n top: -12px;\r\n right: -12px;\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 10px;\r\n font-weight: 600;\r\n min-width: 16px;\r\n height: 16px;\r\n line-height: 16px;\r\n text-align: center;\r\n border-radius: 8px;\r\n padding: 0 3px;\r\n }\r\n}\r\n\r\n// ─── 面板体 ────────────────────────────────────────────────────────────────\r\n.track-panel__body {\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n// ─── 操作栏 ───────────────────────────────────────────────────────────────\r\n.track-panel__toolbar {\r\n display: flex;\r\n gap: 6px;\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .btn {\r\n flex: 1;\r\n padding: 5px 8px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &--active {\r\n background: rgba(255, 100, 50, 0.35);\r\n color: #ffaa88;\r\n border-color: #ff6b35;\r\n }\r\n &--primary {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #fff;\r\n border-color: rgba(62, 166, 255, 0.6);\r\n }\r\n &--info {\r\n background: rgba(255, 107, 53, 0.2);\r\n color: #ffaa88;\r\n border-color: rgba(255, 107, 53, 0.5);\r\n }\r\n &--danger {\r\n flex: 0 0 auto;\r\n width: 36px;\r\n border-color: rgba(255, 80, 80, 0.4);\r\n background: rgba(255, 80, 80, 0.1);\r\n color: #ffaaaa;\r\n &:hover:not(:disabled) {\r\n background: rgba(255, 80, 80, 0.25);\r\n color: #fff;\r\n }\r\n &:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 回放控制 ─────────────────────────────────────────────────────────────\r\n.track-panel__playback {\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .playback__track-name {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-size: 12px;\r\n color: #9dc8f0;\r\n margin-bottom: 8px;\r\n\r\n .fa {\r\n color: #00ff88;\r\n }\r\n .playback__mode-badge {\r\n background: rgba(0, 255, 136, 0.15);\r\n color: #00ff88;\r\n font-size: 10px;\r\n padding: 1px 6px;\r\n border-radius: 8px;\r\n margin-left: 4px;\r\n }\r\n }\r\n\r\n // 播放按钮组\r\n .playback__controls {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 8px;\r\n margin-bottom: 8px;\r\n }\r\n\r\n // 单独控制按钮\r\n .ctrl-btn {\r\n width: 30px;\r\n height: 30px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n\r\n &--play {\r\n width: 38px;\r\n height: 38px;\r\n background: rgba(0, 200, 100, 0.2);\r\n border-color: rgba(0, 200, 100, 0.6);\r\n color: #00ff88;\r\n font-size: 15px;\r\n &:hover {\r\n background: rgba(0, 200, 100, 0.35);\r\n }\r\n }\r\n }\r\n\r\n // 倍速\r\n .playback__speed {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n margin-bottom: 8px;\r\n\r\n .speed-label {\r\n font-size: 11px;\r\n color: #5a7a9a;\r\n }\r\n .speed-btns {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .speed-btn {\r\n padding: 2px 7px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n background: rgba(255, 255, 255, 0.04);\r\n color: #7a9ec0;\r\n border-radius: 10px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #fff;\r\n }\r\n &.active {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #3ea6ff;\r\n border-color: #3ea6ff;\r\n }\r\n }\r\n }\r\n\r\n // 进度条\r\n .playback__timeline {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n\r\n .time-label {\r\n font-size: 10px;\r\n color: #5a7a9a;\r\n font-family: monospace;\r\n min-width: 36px;\r\n text-align: center;\r\n }\r\n\r\n .progress-slider {\r\n flex: 1;\r\n height: 4px;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background: rgba(62, 166, 255, 0.2);\r\n border-radius: 2px;\r\n outline: none;\r\n cursor: pointer;\r\n\r\n &::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 50%;\r\n background: #3ea6ff;\r\n cursor: pointer;\r\n box-shadow: 0 0 6px rgba(62, 166, 255, 0.6);\r\n }\r\n\r\n &::-moz-range-thumb {\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 50%;\r\n background: #3ea6ff;\r\n border: none;\r\n cursor: pointer;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 实时模式提示 ──────────────────────────────────────────────────────────\r\n.track-panel__realtime-hint {\r\n padding: 8px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n\r\n .realtime-pulse {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-size: 12px;\r\n color: #ff6b35;\r\n .fa {\r\n color: #ff6b35;\r\n }\r\n }\r\n\r\n .blink-dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: #ff6b35;\r\n animation: blink 1s ease-in-out infinite;\r\n }\r\n\r\n .realtime-count {\r\n font-size: 11px;\r\n color: #7a9ec0;\r\n strong {\r\n color: #ff6b35;\r\n }\r\n }\r\n}\r\n\r\n@keyframes blink {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n }\r\n 50% {\r\n opacity: 0.2;\r\n }\r\n}\r\n\r\n// ─── 轨迹列表 ─────────────────────────────────────────────────────────────\r\n.track-panel__list {\r\n overflow-y: auto;\r\n max-height: calc(100vh - 340px);\r\n padding: 6px 0;\r\n\r\n &::-webkit-scrollbar {\r\n width: 4px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n\r\n.track-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.1);\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.18);\r\n }\r\n &--realtime .track-item__bar {\r\n background: #ff6b35 !important;\r\n }\r\n\r\n &__bar {\r\n width: 3px;\r\n height: 30px;\r\n border-radius: 2px;\r\n background: #3ea6ff;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__info {\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n &__name {\r\n overflow: hidden;\r\n font-size: 13px;\r\n color: #ffffff;\r\n white-space: nowrap;\r\n text-overflow: ellipsis;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n .fa {\r\n color: #8ab4d4;\r\n font-size: 12px;\r\n }\r\n }\r\n\r\n &__meta {\r\n font-size: 11px;\r\n color: #9dc8f0;\r\n margin-top: 2px;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .realtime-tag {\r\n background: rgba(255, 107, 53, 0.2);\r\n color: #ff6b35;\r\n font-size: 10px;\r\n padding: 0 5px;\r\n border-radius: 6px;\r\n }\r\n\r\n &__actions {\r\n display: flex;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n opacity: 0;\r\n transition: opacity 0.15s;\r\n }\r\n\r\n &:hover &__actions {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.icon-btn {\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: rgba(255, 255, 255, 0.08);\r\n color: #9dc8f0;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n transition: all 0.15s;\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n &--danger:hover {\r\n background: rgba(255, 80, 80, 0.35);\r\n color: #fff;\r\n }\r\n}\r\n\r\n// ─── 空状态 ────────────────────────────────────────────────────────────────\r\n.track-panel__empty {\r\n text-align: center;\r\n padding: 30px 20px;\r\n color: #4a6a8a;\r\n .fa {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: block;\r\n }\r\n p {\r\n font-size: 12px;\r\n margin: 0;\r\n }\r\n}\r\n\r\n// ─── 列表动画 ──────────────────────────────────────────────────────────────\r\n.track-list-enter-active,\r\n.track-list-leave-active {\r\n transition: all 0.25s ease;\r\n}\r\n.track-list-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n.track-list-leave-to {\r\n opacity: 0;\r\n transform: translateX(12px);\r\n}\r\n</style>\r\n","/**\r\n * Mars3D Vue3 Components - 统一导出入口\r\n *\r\n * @description 封装了 Mars3D 地图的基础能力(测量、绘制、视角控制)\r\n * 及业务组件(POI 标注、轨迹管理)的 Vue3 组件库\r\n *\r\n * @example\r\n * // 完整引入\r\n * import Mars3dVueComponents from '@your-org/mars3d-vue-components'\r\n * app.use(Mars3dVueComponents)\r\n *\r\n * // 按需引入\r\n * import { MarsMapContainer, useMap } from '@your-org/mars3d-vue-components'\r\n */\r\n\r\n// 引入全局样式(导航球、Cesium 控件等样式覆盖)\r\nimport \"./styles/mars3d-theme.css\";\r\n\r\n// 引入 Mars3D / Cesium 基础 CSS(导航球、罗盘、状态栏等控件样式)\r\nimport \"mars3d-cesium/Build/Cesium/Widgets/widgets.css\";\r\nimport \"mars3d/mars3d.css\";\r\n\r\n// ── 基础组件 ──────────────────────────────────────────────────────────────────\r\nexport { default as MarsMapContainer } from \"./components/mars-map/MarsMapContainer.vue\";\r\nexport { default as ToolbarPanel } from \"./components/mars-map/panels/ToolbarPanel.vue\";\r\nexport { default as VisionPanel } from \"./components/mars-map/panels/VisionPanel.vue\";\r\n\r\n// ── Composables ────────────────────────────────────────────────────────────────\r\nexport { useMap } from \"./components/mars-map/composables/useMap\";\r\nexport { useMeasure } from \"./components/mars-map/composables/useMeasure\";\r\nexport { useDraw } from \"./components/mars-map/composables/useDraw\";\r\nexport { useVision } from \"./components/mars-map/composables/useVision\";\r\n\r\n// ── 业务组件 ──────────────────────────────────────────────────────────────────\r\nexport { default as PoiMarkerLayer } from \"./components/business/poi-marker/PoiMarkerLayer.vue\";\r\nexport { default as PoiMarkerPanel } from \"./components/business/poi-marker/PoiMarkerPanel.vue\";\r\nexport { default as TrackLayer } from \"./components/business/track/TrackLayer.vue\";\r\nexport { default as TrackPanel } from \"./components/business/track/TrackPanel.vue\";\r\n\r\n// ── 业务 Composable ───────────────────────────────────────────────────────────\r\nexport { usePoiMarker } from \"./components/business/poi-marker/usePoiMarker\";\r\nexport { useTrack } from \"./components/business/track/useTrack\";\r\n\r\n// ── 类型导出 ─────────────────────────────────────────────────────────────────\r\nexport type { UseMapReturn } from \"./components/mars-map/composables/useMap\";\r\nexport type { DrawType } from \"./components/mars-map/composables/useDraw\";\r\nexport type {\r\n PoiItem,\r\n UsePoiMarkerReturn,\r\n} from \"./components/business/poi-marker/usePoiMarker\";\r\nexport type {\r\n TrackPoint,\r\n TrackItem,\r\n UseTrackReturn,\r\n} from \"./components/business/track/useTrack\";\r\n\r\n// ── 安装插件(完整引入时使用)─────────────────────────────────────────────────\r\nimport type { App, Component } from \"vue\";\r\nimport MarsMapContainer from \"./components/mars-map/MarsMapContainer.vue\";\r\nimport ToolbarPanel from \"./components/mars-map/panels/ToolbarPanel.vue\";\r\nimport VisionPanel from \"./components/mars-map/panels/VisionPanel.vue\";\r\nimport PoiMarkerLayer from \"./components/business/poi-marker/PoiMarkerLayer.vue\";\r\nimport PoiMarkerPanel from \"./components/business/poi-marker/PoiMarkerPanel.vue\";\r\nimport TrackLayer from \"./components/business/track/TrackLayer.vue\";\r\nimport TrackPanel from \"./components/business/track/TrackPanel.vue\";\r\n\r\nconst components: Record<string, Component> = {\r\n MarsMapContainer,\r\n ToolbarPanel,\r\n VisionPanel,\r\n PoiMarkerLayer,\r\n PoiMarkerPanel,\r\n TrackLayer,\r\n TrackPanel,\r\n};\r\n\r\nconst YiMapWeb = {\r\n install(app: App, options?: { prefix?: string }) {\r\n const prefix = options?.prefix ?? \"\";\r\n for (const [name, component] of Object.entries(components)) {\r\n app.component(prefix ? `${prefix}${name}` : name, component);\r\n }\r\n },\r\n};\r\n\r\nexport default YiMapWeb;\r\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_withDirectives","_hoisted_1","_hoisted_2","_Fragment","_renderList","_hoisted_4","_createVNode","_Transition","_openBlock","_hoisted_3","_toDisplayString","MarsMap","_createBlock","_unref","_renderSlot","_idCounter","_normalizeStyle","_hoisted_5","_hoisted_6","_createTextVNode","_hoisted_8","_hoisted_10","_TransitionGroup","_hoisted_12","_withModifiers","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_19","track","_a","PoiMarkerLayer","TrackLayer"],"mappings":";;AAYO,MAAM,mBAAmB,OAAO,SAAS;AAAA;AAAA,EAE9C,gBAAgB;AACd,SAAK,KAAK,kBAAkB,KAAK,QAAQ,IAAI;AAAA,EAC/C;AAAA;AAAA,EAGA,aAAa;AACX,SAAK,aAAY;AAAA,EACnB;AACF;AACA,OAAO,MAAM,KAAK,SAAS,cAAc,UAAU;ACV5C,MAAM,mBAAmB,OAAO,SAAS;AAAA;AAAA,EAE9C,gBAAgB;AACd,SAAK,KAAK,cAAc,KAAK,QAAQ,QAAQ,EAAE,UAAU,KAAK,WAAW;AAAA,EAC3E;AAAA;AAAA,EAGA,eAAe;AACb,SAAK,KAAK,YAAW;AAAA,EACvB;AACF;AACA,OAAO,MAAM,KAAK,SAAS,UAAU,UAAU;ACVxC,MAAM,kBAAkB,OAAO,SAAS;AAAA,EAC7C,YAAY,UAAU,IAAI;AACxB,UAAM,OAAO;AAEb,SAAK,SAAS,KAAK,QAAQ,SAAS;AACpC,SAAK,UAAU,KAAK,QAAQ,UAAU,EAAE,KAAK,WAAW,KAAK,YAAY,KAAK,cAAY,SAAS,GAAG,OAAO,IAAG;AAAA,EAClH;AAAA;AAAA,EAGA,gBAAgB;AACd,SAAK,KAAK,cAAc,KAAK,SAAS;AAAA,MACpC,UAAU;AAAA,MACV,UAAU,MAAM;AACd,aAAK,KAAK,GAAG,OAAO,UAAU,WAAW,KAAK,kBAAkB,IAAI;AAAA,MACtE;AAAA,IACN,CAAK;AAAA,EACH;AAAA;AAAA,EAGA,eAAe;AACb,SAAK,KAAK,IAAI,OAAO,UAAU,WAAW,KAAK,kBAAkB,IAAI;AAAA,EACvE;AAAA,EAEA,mBAAmB;AACjB,QAAI,KAAK,SAAS;AAChB;AAAA,IACF;AAEA,SAAK,KAAK,MAAM,OAAO,OAAO,OAAO,OAAO,WAAW,QAAQ,KAAK,MAAM;AAAA,EAC5E;AACF;AACA,OAAO,MAAM,KAAK,SAAS,aAAa,SAAS;AC5B1C,MAAM,oBAAoB,OAAO,SAAS;AAAA;AAAA,EAE/C,gBAAgB;AACd,QAAI,KAAK,QAAQ,QAAQ;AACvB,WAAK,KAAK,cAAc,KAAK,QAAQ,QAAQ,EAAE,UAAU,GAAG;AAAA,IAC9D;AAEA,QAAI,KAAK,QAAQ,UAAU;AACzB,aAAO,KAAK,QAAQ;AAAA,IACtB;AAEA,QAAI,KAAK,QAAQ,aAAa;AAC5B,WAAK,aAAa,IAAI,OAAO,MAAM,UAAU,KAAK,OAAO;AACzD,WAAK,KAAK,SAAS,KAAK,UAAU;AAAA,IACpC,OAAO;AACL,WAAK,eAAe,IAAI,OAAO,MAAM,YAAY,KAAK,OAAO;AAC7D,WAAK,KAAK,SAAS,KAAK,YAAY;AAAA,IACtC;AAEA,QAAI,KAAK,QAAQ,aAAa;AAC5B,WAAK,WAAW,MAAK;AAAA,IACvB,OAAO;AACL,WAAK,aAAa,MAAM,KAAK,QAAQ,KAAK;AAAA,IAC5C;AAAA,EACF;AAAA;AAAA,EAGA,eAAe;AACb,QAAI,KAAK,cAAc;AACrB,WAAK,aAAa,KAAI;AACtB,WAAK,aAAa,QAAO;AACzB,aAAO,KAAK;AAAA,IACd;AACA,QAAI,KAAK,YAAY;AACnB,WAAK,WAAW,KAAI;AACpB,WAAK,WAAW,QAAO;AACvB,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACF;AACA,OAAO,MAAM,KAAK,SAAS,eAAe,WAAW;AC5C9C,MAAM,kBAAkB,OAAO,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAM7C,gBAAgB;AACd,SAAK,gBAAgB,IAAI,OAAO,MAAM,aAAY;AAClD,SAAK,KAAK,SAAS,KAAK,aAAa;AAErC,UAAM,aAAa,IAAI,OAAO,QAAQ,WAAW,KAAK,QAAQ,KAAK;AACnE,SAAK,cAAc,WAAW,UAAU;AACxC,SAAK,cAAc;AAEnB,eAAW,MAAK;AAAA,EAClB;AAAA;AAAA,EAGA,WAAW,SAAS;AAClB,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,MAAK;AAAA,IACxB;AAAA,EACF;AAAA;AAAA,EAGA,eAAe;AACb,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,QAAO;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,eAAe;AACb,QAAI,KAAK,aAAa;AACpB,WAAK,YAAY,KAAI;AACrB,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,KAAK,eAAe;AACtB,WAAK,cAAc,QAAO;AAC1B,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AACF;AACA,OAAO,MAAM,KAAK,SAAS,aAAa,SAAS;AC5C1C,MAAM,eAAe,OAAO,SAAS;AAAA;AAAA,EAE1C,gBAAgB;AACd,SAAK,KAAK,OAAO,KAAK,QAAQ,cAAc;AAAA,EAC9C;AACF;AACA,OAAO,MAAM,KAAK,SAAS,UAAU,MAAM;ACNpC,MAAM,gBAAgB,OAAO,SAAS;AAAA;AAAA,EAE3C,gBAAgB;AACd,SAAK,KAAK,QAAQ,KAAK,QAAQ,cAAc;AAAA,EAC/C;AACF;AACA,OAAO,MAAM,KAAK,SAAS,WAAW,OAAO;ACDtC,MAAM,sBAAsB,OAAO,SAAS;AAAA;AAAA,EAEjD,gBAAgB;AACd,UAAM,QAAQ,KAAK,KAAK,aAAa,KAAK,QAAQ,OAAO;AACzD,QAAI,OAAO;AACT,YAAM,OAAO;AACb,YAAM,aAAa,KAAK,MAAM;AAC5B,aAAK,WAAW,MAAM,eAAe,KAAK,QAAQ,SAAS;AAC3D,YAAI,KAAK,UAAU;AACjB,eAAK,SAAS,OAAO;AACrB,eAAK,SAAS,aAAa;AAAA,YACzB,MAAM,KAAK;AAAA,YACX,MAAM,KAAK,QAAQ;AAAA,YACnB,UAAU,KAAK,QAAQ;AAAA,YACvB,OAAO,KAAK,QAAQ;AAAA,UAChC,CAAW;AAAA,QACH;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA,EAGA,eAAe;AACb,QAAI,KAAK,UAAU;AACjB,WAAK,SAAS,YAAW;AAAA,IAC3B;AAAA,EACF;AACF;AACA,OAAO,MAAM,KAAK,SAAS,iBAAiB,aAAa;AC3ClD,MAAM,wBAAwB,OAAO,QAAQ,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKrE,IAAI,OAAO;AACT,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA,EAEA,IAAI,KAAK,KAAK;AACZ,SAAK,MAAM,OAAO;AAElB,SAAK,MAAM,OAAO;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,WAAW,OAAO;AAChB,UAAM,QAAQ;AACd,UAAM,QAAQ;AAAA,MACZ,GAAG;AAAA,MACH,MAAM,KAAK,MAAM;AAAA,MACjB,WAAW;AAAA,MACX,OAAO,MAAM,aAAa;AAAA,MAC1B,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,cAAc,OAAO,MAAM,SAAS;AAAA,IAC1C;AACI,QAAI,MAAM,iBAAiB;AACzB,YAAM,MAAM,6BAA6B,MAAM;AAAA,IACjD;AAEA,UAAM,WAAW,KAAK;AAAA,EACxB;AACF;AAGA,OAAO,YAAY,SAAS,mBAAmB,eAAe;;;;;;;;;;;AC9B9D,UAAM,QAAQ;AAcd,QAAI;AAGJ,UAAM,YAAY,SAAS,MAAM,oBAAoB,MAAM,MAAM,EAAE;AAGnE,UAAM,OAAO;AAEb,UAAM,aAAa,YAAY;AAE7B,UAAI;AACJ,UAAI,MAAM,KAAK;AAEb,qBAAa,MAAM,OAAO,KAAK,UAAU,EAAE,KAAK,MAAM,KAAK;AAC3D,YAAI,MAAM,SAAS;AACjB,uBAAa,OAAO,KAAK,MAAM,YAAY,MAAM,MAAM,OAAO,CAAC;AAAA,QACjE;AAAA,MACF,WAAW,MAAM,SAAS;AACxB,qBAAa,MAAM,MAAM,OAAO;AAAA,MAClC;AAIC,aAAe,KAAK,gBAAgB;AAErC,YAAM,IAAI,OAAO,IAAI,UAAU,OAAO,UAAU;AAGhD,UAAI,OAAO,KAAK,eAAe;AAC7B,YAAI,aAAa;AAGjB,YAAI,OAAO,UAAU,UAAU,YAAA,EAAc,QAAQ,MAAM,KAAK,GAAG;AACjE,cAAI,OAAO,kBAAkB;AAC7B,cAAI,MAAM,oBAAoB;AAAA,QAChC;AAAA,MACF,OAAO;AACL,YAAI,aAAa;AAGjB,YAAI,MAAM,oBAAoB;AAC9B,YAAI,MAAM,IAAI,UAAU;AACxB,YAAI,MAAM,cAAc,OAAO;AAC/B,YAAI,MAAM,MAAM,uBAAuB;AAAA,MACzC;AAGA,UAAI,IAAI,OAAO,iBAAiB;AAC9B,YAAI,OAAO,gBAAgB,UAAU,WAAW;AAAA,MAClD;AAMA,UAAK,IAAY,YAAY;AAC1B,YAAY,WAAW,OAAO;AAAA,MACjC;AAEA,iBAAW,MAAM;AACf,cAAM,eAAe,SAAS,uBAAuB,aAAa;AAClE,iBAAS,IAAI,GAAG,IAAI,aAAa,QAAQ,KAAK;AAC5C,uBAAa,CAAC,EAAE,OAAA;AAAA,QAClB;AAAA,MACF,GAAG,GAAG;AASN,WAAK,UAAU,GAAG;AAAA,IACpB;AAWA,cAAU,MAAM;AACd,iBAAA;AAAA,IACF,CAAC;AAED,gBAAY,MAAM;AAChB,UAAI,KAAK;AACP,YAAI,QAAA;AACJ,cAAM;AAAA,MACR;AAAA,IAEF,CAAC;;0BAtHCA,mBAAoD,OAAA;AAAA,QAA9C,IAAI,UAAA;AAAA,QAAW,OAAM;AAAA,MAAA;;;;;;;;;;;;;;;;AC+D7B,UAAM,OAAO;AAMb,UAAM,cAAc,IAAI,KAAK;AAE7B,UAAM,iBAAiB,MAAM;AAC3B,kBAAY,QAAQ,CAAC,YAAY;AAAA,IACnC;AACA,UAAM,eAAe,CAAC,SAAiB;AACrC,WAAK,gBAAgB,IAAI;AAAA,IAC3B;AACA,UAAM,YAAY,MAAM;AACtB,WAAK,OAAO;AAAA,IACd;AAUA,UAAM,eAA2B;AAAA,MAC/B;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,iBAAiB;AAAA;AAAA,MAAA;AAAA,MAEvC;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,kBAAkB;AAAA;AAAA,MAAA;AAAA,MAExC;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,iBAAiB;AAAA;AAAA,MAAA;AAAA,MAEvC;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,YAAY,qBAAqB;AAAA;AAAA,MAAA;AAAA,IACjD;AAGF,UAAM,YAAwB;AAAA,MAC5B;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,eAAe;AAAA;AAAA,QACnC,UAAU;AAAA,MAAA;AAAA,MAEZ;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,UAAU;AAAA;AAAA,QAC9B,UAAU;AAAA,MAAA;AAAA,MAEZ;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,YAAY,iBAAiB;AAAA;AAAA,QAC3C,UAAU;AAAA,MAAA;AAAA,MAEZ;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,WAAW;AAAA;AAAA,QAC/B,UAAU;AAAA,MAAA;AAAA,MAEZ;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,cAAc,WAAW;AAAA;AAAA,QACvC,UAAU;AAAA,MAAA;AAAA,MAEZ;AAAA,QACE,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa,CAAC,MAAM,WAAW;AAAA;AAAA,QAC/B,UAAU;AAAA,MAAA;AAAA,IACZ;;0BAhJAA,mBA+CM,OAAA;AAAA,QA/CD,OAAKC,eAAA,CAAC,iBAAe,EAAA,WAAsB,YAAA,OAAW,CAAA;AAAA,MAAA;QAEzDC,mBAQM,OAAA;AAAA,UARD,OAAM;AAAA,UAAgB,SAAO;AAAA,QAAA;UAChCA,mBAME,KAAA;AAAA,YALC,OAAKD,eAAA;AAAA;;cAA0D,YAAA,QAAW,oBAAA;AAAA,YAAA;;;QAQ/EE,eAAAD,mBAkCM,OAlCNE,cAkCM;AAAA,UAhCJF,mBAUM,OAVNG,cAUM;AAAA,0BATJL,mBAQMM,UAAA,MAAAC,WAPW,cAAY,CAApB,SAAI;qBADbL,mBAQM,OAAA;AAAA,gBANH,KAAK,KAAK;AAAA,gBACX,OAAM;AAAA,gBACL,OAAO,KAAK;AAAA,gBACZ,SAAK,CAAA,WAAE,aAAa,KAAK,IAAI;AAAA,cAAA;gBAE9BA,mBAA+B,KAAA;AAAA,kBAA3B,OAAKD,eAAE,KAAK,WAAW;AAAA,gBAAA;;;;oCAI/BC,mBAAuB,OAAA,EAAlB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,UAGpBA,mBAgBM,OAhBNM,cAgBM;AAAA,0BAfJR,mBASMM,UAAA,MAAAC,WARW,WAAS,CAAjB,SAAI;qBADbL,mBASM,OAAA;AAAA,gBAPH,KAAK,KAAK;AAAA,gBACX,uBAAM,aAAW,EAAA,QACC,2BAAmB,KAAK,SAAA,CAAQ,CAAA;AAAA,gBACjD,OAAO,KAAK;AAAA,gBACZ,SAAK,CAAA,WAAE,aAAa,KAAK,IAAI;AAAA,cAAA;gBAE9BA,mBAA+B,KAAA;AAAA,kBAA3B,OAAKD,eAAE,KAAK,WAAW;AAAA,gBAAA;;;sCAE7BC,mBAAuB,OAAA,EAAlB,OAAM,UAAA,GAAS,MAAA,EAAA;AAAA,YAEpBA,mBAEM,OAAA;AAAA,cAFD,OAAM;AAAA,cAAY,OAAM;AAAA,cAAQ,SAAO;AAAA,YAAA;cAC1CA,mBAAmC,KAAA,EAAhC,OAAM,wBAAA,GAAuB,MAAA,EAAA;AAAA,YAAA;;;mBA/BF,YAAA,KAAW;AAAA,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACoBnD,UAAM,QAAQ;AAQd,UAAM,OAAO;AAKb,UAAM,eAAe,IAAI,KAAK;AAC9B,UAAM,cAAc,MAAM;AAAE,mBAAa,QAAQ,CAAC,aAAa;AAAA,IAAO;AACtE,UAAM,UAAU,CAAC,WAAmB;AAAE,WAAK,iBAAiB,MAAM;AAAA,IAAG;AAWrE,UAAM,cAA4B;AAAA,MAChC;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,QACb,YAAY;AAAA,MAAA;AAAA,MAEd;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,QACP,YAAY;AAAA,MAAA;AAAA,MAEd;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,QACb,YAAY;AAAA,MAAA;AAAA,MAEd;AAAA,QACE,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,QACb,YAAY;AAAA,MAAA;AAAA,IACd;AAGF,UAAM,WAAW,CAAC,SAChB,KAAK,aAAa,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI;AAE/C,UAAM,WAAW,CAAC,SAChB,SAAS,IAAI,KAAK,KAAK,cAAc,KAAK,cAAc,KAAK;;;QA3F7DA,mBAEM,OAAA;AAAA,UAFD,OAAM;AAAA,UAAgB,OAAM;AAAA,UAAQ,SAAO;AAAA,QAAA;UAC9CA,mBAAuB,KAAA,EAApB,OAAM,YAAA,GAAW,MAAA,EAAA;AAAA,QAAA;QAItBO,YAmBaC,YAAA,EAnBD,MAAK,iBAAa;AAAA,2BAC5B,MAiBM;AAAA,YAjBK,aAAA,SAAXC,UAAA,GAAAX,mBAiBM,OAjBNI,cAiBM;AAAA,cAhBJF,mBAGM,OAHNG,cAGM;AAAA,gBAFJ,OAAA,CAAA,MAAA,OAAA,CAAA,IAAAH,mBAAiB,cAAX,QAAI,EAAA;AAAA,gBACVA,mBAAkE,KAAA;AAAA,kBAA/D,OAAM;AAAA,kBAA0B,+CAAO,aAAA,QAAY;AAAA,gBAAA;;cAExDA,mBAWM,OAXNU,cAWM;AAAA,8BAVJZ,mBASMM,UAAA,MAAAC,WARW,aAAW,CAAnB,SAAI;yBADbL,mBASM,OAAA;AAAA,oBAPH,KAAK,KAAK;AAAA,oBACX,OAAKD,eAAA,CAAC,cAAY,EAAA,QACA,SAAS,IAAI,EAAA,CAAA,CAAA;AAAA,oBAC9B,SAAK,CAAA,WAAE,QAAQ,KAAK,MAAM;AAAA,kBAAA;oBAE3BC,mBAAgC,KAAA;AAAA,sBAA5B,OAAKD,eAAA,CAAA,MAAS,KAAK,IAAI,CAAA;AAAA,oBAAA;oBAC3BC,mBAAiC,QAAA,MAAAW,gBAAxB,SAAS,IAAI,CAAA,GAAA,CAAA;AAAA,kBAAA;;;;;;;;;;;;ACdzB,SAAS,SAAS;AACvB,QAAM,SAAS,OAAO;AAGtB,QAAM,SAAS,WAA8B,IAAI;AAGjD,QAAM,eAAe,WAA6C,IAAI;AACtE,QAAM,eAAe,WAA6C,IAAI;AAGtE,QAAM,kBAAkB,IAAS,IAAI;AAGrC,QAAM,oBAAoB,IAAsD,IAAI;AAKpF,WAAS,QAAQ,KAAiB;AAChC,WAAO,QAAQ;AAGf,UAAM,SAAS,IAAI,OAAO,MAAM,aAAA;AAChC,QAAI,SAAS,MAAM;AACnB,iBAAa,QAAQ;AAGrB,UAAM,SAAS,IAAI,OAAO,MAAM,aAAA;AAChC,QAAI,SAAS,MAAM;AACnB,iBAAa,QAAQ;AAGrB,QAAI,GAAG,OAAO,UAAU,OAAO,CAAC,UAAe;AAC7C,UAAI,MAAM,QAAQ;AAChB,0BAAkB,QAAQ,MAAM;AAAA,MAClC,WAAW,MAAM,WAAW;AAC1B,cAAM,QAAQ,OAAO,UAAU,MAAM,wBAAwB,MAAM,SAAS;AAC5E,0BAAkB,QAAQ;AAAA,UACxB,KAAK,OAAO,KAAK,UAAU,MAAM,SAAS;AAAA,UAC1C,KAAK,OAAO,KAAK,UAAU,MAAM,QAAQ;AAAA,UACzC,KAAK,MAAM,SAAS,IAAI,MAAM,SAAS;AAAA,QAAA;AAAA,MAE3C;AAAA,IACF,CAAC;AAGD,WAAO,GAAG,OAAO,UAAU,OAAO,CAAC,UAAe;AAChD,sBAAgB,QAAQ,MAAM;AAAA,IAChC,CAAC;AACD,WAAO,GAAG,OAAO,UAAU,WAAW,CAAC,UAAe;AACpD,UAAI,CAAC,gBAAgB,OAAO;AAC1B,wBAAgB,QAAQ,MAAM;AAAA,MAChC;AAAA,IACF,CAAC;AACD,WAAO,GAAG,OAAO,UAAU,UAAU,CAAC,UAAe;AACnD,UAAI,gBAAgB,UAAU,MAAM,SAAS;AAC3C,wBAAgB,QAAQ;AAAA,MAC1B;AAAA,IACF,CAAC;AAAA,EACH;AAKA,WAAS,aAAa;AACpB,QAAI,OAAO,OAAO;AAChB,aAAO,MAAM,QAAA;AACb,aAAO,QAAQ;AAAA,IACjB;AAAA,EACF;AAKA,WAAS,WAAW,SAAc;;AAChC,uBAAa,UAAb,mBAAoB,WAAW;AAAA,EACjC;AAKA,WAAS,SAAS,OAAY;;AAC5B,iBAAO,UAAP,mBAAc,SAAS;AAAA,EACzB;AAEA,SAAO;AAAA;AAAA,IAEL,KAAK;AAAA;AAAA,IAEL;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;ACtGO,SAAS,WAAW,YAA0B;AACnD,QAAM,eAAe,WAAwC,IAAI;AAGjE,WAAS,cAAc;AACrB,UAAM,MAAM,WAAW,IAAI;AAC3B,UAAM,QAAQ,WAAW,aAAa;AACtC,QAAI,CAAC,OAAO,CAAC,MAAO;AAEpB,UAAM,IAAI,IAAI,OAAO,MAAM,QAAQ,EAAE,cAAc,OAAc;AACjE,QAAI,SAAS,CAAC;AACd,iBAAa,QAAQ;AAAA,EACvB;AAGA,WAAS,gBAAgB,OAA6B;;AACpD,uBAAa,UAAb,mBAAoB,SAAS;AAAA,MAC3B,OAAO,EAAE,OAAO,WAAW,OAAO,GAAG,GAAG,MAAA;AAAA,IAAM;AAAA,EAElD;AAGA,WAAS,YAAY,OAA6B;;AAChD,uBAAa,UAAb,mBAAoB,KAAK;AAAA,MACvB,OAAO,EAAE,OAAO,WAAW,SAAS,KAAK,GAAG,MAAA;AAAA,IAAM;AAAA,EAEtD;AAGA,WAAS,cAAc,OAA6B;;AAClD,uBAAa,UAAb,mBAAoB,OAAO;AAAA,MACzB,OAAO,EAAE,OAAO,WAAW,OAAO,GAAG,GAAG,MAAA;AAAA,IAAM;AAAA,EAElD;AAGA,WAAS,aAAa,OAA6B;;AACjD,uBAAa,UAAb,mBAAoB,MAAM;AAAA,MACxB,OAAO,EAAE,OAAO,WAAW,OAAO,GAAG,GAAG,MAAA;AAAA,IAAM;AAAA,EAElD;AAGA,WAAS,eAAe;;AACtB,uBAAa,UAAb,mBAAoB;AACpB,qBAAW,aAAa,UAAxB,mBAA+B;AAAA,EACjC;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;ACvDO,SAAS,QAAQ,YAA0B;AAChD,QAAM,cAAc,WAAgB,IAAI;AAExC,QAAM,iBAAiB,IAAqB,IAAI;AAGhD,WAAS,WAAW;AAClB,WAAO,WAAW,aAAa;AAAA,EACjC;AAGA,WAAS,UAAU,MAAc,OAA4B,UAAoB;AAC/E,UAAM,QAAQ,SAAA;AACd,QAAI,CAAC,MAAO;AACZ,aAAA;AACA,gBAAY,QAAQ,MAAM,UAAU,EAAE,MAAM,OAAO;AACnD,mBAAe,QAAQ;AAAA,EACzB;AAGA,WAAS,UAAU,OAA6B;AAC9C,cAAU,SAAS,EAAE,WAAW,IAAI,OAAO,WAAW,GAAG,MAAA,GAAS,OAAO;AAAA,EAC3E;AAGA,WAAS,SAAS,OAA6B;AAC7C,cAAU,YAAY,EAAE,OAAO,GAAG,OAAO,WAAW,GAAG,MAAA,GAAS,UAAU;AAAA,EAC5E;AAGA,WAAS,YAAY,OAA6B;AAChD,cAAU,WAAW,EAAE,OAAO,WAAW,SAAS,KAAK,GAAG,MAAA,GAAS,SAAS;AAAA,EAC9E;AAGA,WAAS,WAAW,OAA6B;AAC/C,cAAU,UAAU,EAAE,QAAQ,KAAM,OAAO,WAAW,SAAS,KAAK,GAAG,MAAA,GAAS,QAAQ;AAAA,EAC1F;AAGA,WAAS,cAAc,OAA6B;AAClD,cAAU,aAAa,EAAE,OAAO,WAAW,SAAS,KAAK,GAAG,MAAA,GAAS,WAAW;AAAA,EAClF;AAGA,WAAS,gBAAgB,OAA6B;AACpD;AAAA,MACE;AAAA,MACA,EAAE,OAAO,WAAW,SAAS,KAAK,eAAe,MAAM,GAAG,MAAA;AAAA,MAC1D;AAAA,IAAA;AAAA,EAEJ;AAGA,WAAS,WAAW;;AAClB,QAAI,YAAY,OAAO;AACrB,qBAAA,MAAA,mBAAY;AACZ,kBAAY,QAAQ;AAAA,IACtB;AACA,mBAAe,QAAQ;AAAA,EACzB;AAGA,WAAS,YAAY;;AACnB,aAAA;AACA,mBAAA,MAAA,mBAAY;AAAA,EACd;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AChFO,SAAS,UAAU,YAA0B;AAElD,QAAM,kBAAkB,IAAI,KAAK;AACjC,QAAM,oBAAoB,IAAI,KAAK;AACnC,QAAM,iBAAiB,IAAI,KAAK;AAChC,QAAM,cAAc,IAAI,KAAK;AAG7B,QAAM,cAAc,WAA4C,IAAI;AACpE,QAAM,kBAAkB,WAAgD,IAAI;AAC5E,QAAM,eAAe,WAA6C,IAAI;AACtE,MAAI,oBAAyB;AAG7B,WAAS,SAAS;AAChB,WAAO,WAAW,IAAI;AAAA,EACxB;AAGA,WAAS,kBAAkB;AACzB,UAAM,MAAM,OAAA;AACZ,QAAI,CAAC,IAAK;AAEV,QAAI,YAAY,OAAO;AACrB,UAAI,YAAY,MAAM,SAAS;AAC7B,oBAAY,MAAM,KAAA;AAAA,MACpB;AACA,UAAI,YAAY,YAAY,KAAK;AACjC,kBAAY,QAAQ;AACpB,sBAAgB,QAAQ;AACxB;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,UAAA;AACnB,UAAM,KAAK,IAAI,OAAO,MAAM,YAAY,EAAE,UAAU,KAAM,MAAM,IAAI;AACpE,QAAI,SAAS,EAAE;AACf,OAAG,MAAM,MAAM;AACf,gBAAY,QAAQ;AACpB,oBAAgB,QAAQ;AAAA,EAC1B;AAGA,WAAS,QAAQ;AACf,UAAM,MAAM,OAAA;AACZ,QAAI,CAAC,IAAK;AAEV,gBAAY,QAAQ;AACpB,UAAM,OAAO,MAAM,WAAW,MAAM;AAAE,kBAAY,QAAQ;AAAA,IAAO,GAAG,GAAI;AAExE,UAAM,MAAM,WAAW,kBAAkB;AACzC,QAAI,KAAK;AACP,YAAM,SAAS,EAAE,GAAG,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI,MAAM,IAAA;AACtD,UAAI,cAAc,QAAQ,EAAE,UAAU,GAAG,UAAU,MAAM;AAAA,IAC3D,OAAO;AACL,UAAI,QAAQ,EAAE,UAAU,EAAA,CAAG;AAC3B,WAAA;AAAA,IACF;AAAA,EACF;AAGA,WAAS,oBAAoB;AAC3B,UAAM,MAAM,OAAA;AACZ,QAAI,CAAC,IAAK;AAEV,QAAI,CAAC,gBAAgB,OAAO;AAC1B,YAAM,OAAO,IAAI,OAAO,MAAM,gBAAgB,CAAA,CAAE;AAChD,UAAI,SAAS,IAAI;AACjB,0BAAoB,IAAI,cAAA;AACxB,WAAK,UAAU;AACf,sBAAgB,QAAQ;AACxB,wBAAkB,QAAQ;AAAA,IAC5B,OAAO;AACL,YAAM,OAAO,gBAAgB;AAC7B,WAAK,UAAU,CAAC,KAAK;AACrB,wBAAkB,QAAQ,KAAK;AAC/B,UAAI,CAAC,KAAK,WAAW,mBAAmB;AACtC,YAAI,cAAc,mBAAmB,EAAE,UAAU,GAAG;AAAA,MACtD,WAAW,KAAK,SAAS;AACvB,4BAAoB,IAAI,cAAA;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAGA,WAAS,yBAAyB;AAChC,UAAM,MAAM,OAAA;AACZ,QAAI,CAAC,IAAK;AAEV,QAAI,CAAC,aAAa,OAAO;AACvB,YAAM,OAAO,IAAI,OAAO,MAAM,aAAa,CAAA,CAAE;AAC7C,UAAI,SAAS,IAAI;AACjB,WAAK,UAAU;AACf,mBAAa,QAAQ;AACrB,qBAAe,QAAQ;AAAA,IACzB,OAAO;AACL,YAAM,OAAO,aAAa;AAC1B,WAAK,UAAU,CAAC,KAAK;AACrB,qBAAe,QAAQ,KAAK;AAAA,IAC9B;AAAA,EACF;AAEA,SAAO;AAAA;AAAA,IAEL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;;;;;;;;;;;AC3CA,UAAM,OAAO;AAMb,UAAM,SAAS,OAAA;AACf,UAAM,UAAU,WAAW,MAAM;AACjC,UAAM,OAAO,QAAQ,MAAM;AAC3B,UAAM,SAAS,UAAU,MAAM;AAG/B,YAAQ,cAAc,MAAM;AAC5B,YAAQ,kBAAkB,OAAO;AACjC,YAAQ,eAAe,IAAI;AAC3B,YAAQ,iBAAiB,MAAM;AAG/B,aAAS,UAAU,KAAU;AAC3B,aAAO,QAAQ,GAAG;AAClB,cAAQ,YAAA;AACR,WAAK,UAAU,GAAG;AAAA,IACpB;AAOA,aAAS,mBAAmB,MAAc;AACxC,cAAQ,MAAA;AAAA,QACN,KAAK;AAAoB,kBAAQ,gBAAA;AAAmB;AAAA,QACpD,KAAK;AAAoB,kBAAQ,YAAA;AAAe;AAAA,QAChD,KAAK;AAAoB,kBAAQ,cAAA;AAAiB;AAAA,QAClD,KAAK;AAAoB,kBAAQ,aAAA;AAAgB;AAAA,QACjD,KAAK;AAAoB,eAAK,UAAA;AAAa;AAAA,QAC3C,KAAK;AAAoB,eAAK,SAAA;AAAY;AAAA,QAC1C,KAAK;AAAoB,eAAK,YAAA;AAAe;AAAA,QAC7C,KAAK;AAAoB,eAAK,WAAA;AAAc;AAAA,QAC5C,KAAK;AAAoB,eAAK,cAAA;AAAiB;AAAA,QAC/C,KAAK;AAAoB,eAAK,gBAAA;AAAmB;AAAA,MAAA;AAAA,IAErD;AAEA,aAAS,cAAc;AACrB,cAAQ,aAAA;AACR,WAAK,UAAA;AAAA,IACP;AAKA,aAAS,oBAAoB,QAAgB;AAC3C,cAAQ,QAAA;AAAA,QACN,KAAK;AAAqB,iBAAO,gBAAA;AAAmB;AAAA,QACpD,KAAK;AAAqB,iBAAO,MAAA;AAAS;AAAA,QAC1C,KAAK;AAAqB,iBAAO,kBAAA;AAAqB;AAAA,QACtD,KAAK;AAAqB,iBAAO,uBAAA;AAA0B;AAAA,MAAA;AAAA,IAE/D;AAGA,aAAa;AAAA,MACX,KAAK,OAAO;AAAA,MACZ,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,MACrB,iBAAiB,OAAO;AAAA,MACxB,mBAAmB,OAAO;AAAA,MAC1B,YAAY,OAAO;AAAA,MACnB,UAAU,OAAO;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,IAAA,CACD;;AApIC,aAAAF,UAAA,GAAAX,mBA4BM,OA5BNI,cA4BM;AAAA,QA1BJK,YAIEK,aAAA;AAAA,UAHC,KAAK,QAAA;AAAA,UACL,WAAS,QAAA;AAAA,UACT,UAAQ;AAAA,QAAA;SAKF,QAAA,4BADTC,YAKE,cAAA;AAAA;UAHC,oBAAkBC,MAAA,IAAA,EAAK,eAAe;AAAA,UACtC,gBAAe;AAAA,UACf,SAAO;AAAA,QAAA;SAKD,QAAA,2BADTD,YAOE,aAAA;AAAA;UALC,qBAAmBC,MAAA,MAAA,EAAO,gBAAgB;AAAA,UAC1C,iBAAeA,MAAA,MAAA,EAAO,YAAY;AAAA,UAClC,uBAAqBA,MAAA,MAAA,EAAO,kBAAkB;AAAA,UAC9C,4BAA0BA,MAAA,MAAA,EAAO,eAAe;AAAA,UAChD,iBAAgB;AAAA,QAAA;QAInBC,WAAQ,KAAA,QAAA,WAAA,CAAA,GAAA,QAAA,IAAA;AAAA,MAAA;;;;;ACvBZ,MAAM,gBAAqD;AAAA,EACzD,SAAS;AAAA,EACT,SAAS;AAAA,EACT,MAAS;AACX;AAEA,IAAIC,eAAa;AAEV,SAAS,aAAa,QAAsB;AAEjD,QAAM,WAAW,WAA6C,IAAI;AAGlE,QAAM,UAAU,IAAe,EAAE;AAGjC,QAAM,cAAc,IAAmB,IAAI;AAG3C,WAAS,eAAe;AACtB,UAAM,MAAM,OAAO,IAAI;AACvB,QAAI,CAAC,IAAK;AAEV,UAAM,QAAQ,IAAI,OAAO,MAAM,aAAA;AAC/B,QAAI,SAAS,KAAK;AAClB,aAAS,QAAQ;AAGjB,UAAM,GAAG,OAAO,UAAU,OAAO,CAAC,MAAW;;AAC3C,YAAM,SAAQ,aAAE,YAAF,mBAAW,SAAX,mBAAiB;AAC/B,UAAI,iBAAiB,KAAK;AAAA,IAC5B,CAAC;AAAA,EACH;AAGA,WAAS,OAAO,QAAyC;AACvD,UAAM,QAAQ,SAAS;AACvB,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,KAAK,OAAOA,cAAY;AAG9B,UAAM,UAAU,IAAI,OAAO,QAAQ,gBAAgB;AAAA,MACjD,UAAU,CAAC,OAAO,KAAK,OAAO,KAAK,OAAO,GAAG;AAAA,MAC7C,OAAO;AAAA,QACL,OAAO,cAAc,OAAO,QAAQ;AAAA,QACpC,OAAO;AAAA,QACP,kBAAkB,OAAO,OAAO,iBAAiB;AAAA,QACjD,gBAAgB,OAAO,OAAO,eAAe;AAAA,QAC7C,eAAe;AAAA;AAAA,QAEf,OAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,WAAW;AAAA,UACX,OAAO;AAAA,UACP,SAAS;AAAA,UACT,cAAc;AAAA,UACd,cAAc;AAAA,UACd,aAAa,IAAI,OAAO,OAAO,WAAW,GAAG,GAAG;AAAA,UAChD,cAAc;AAAA,QAAA;AAAA,MAChB;AAAA;AAAA,MAGF,OAAO,eAAe,MAAM;AAAA,MAC5B,MAAM,EAAE,OAAO,IAAI,MAAM,OAAO,KAAA;AAAA,IAAK,CACtC;AAED,UAAM,WAAW,OAAO;AAExB,UAAM,MAAe,EAAE,GAAG,QAAQ,IAAI,QAAA;AACtC,YAAQ,MAAM,KAAK,GAAG;AACtB,WAAO;AAAA,EACT;AAGA,WAAS,UAAU,IAAY;;AAC7B,UAAM,MAAM,QAAQ,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACtD,QAAI,QAAQ,GAAI;AAEhB,UAAM,MAAM,QAAQ,MAAM,GAAG;AAC7B,QAAI,aAAW,cAAS,UAAT,mBAAgB,cAAc,IAAI;AACjD,YAAQ,MAAM,OAAO,KAAK,CAAC;AAE3B,QAAI,YAAY,UAAU,GAAI,aAAY,QAAQ;AAAA,EACpD;AAGA,WAAS,UAAU,IAAY,QAAQ,OAAO;AAC5C,gBAAY,QAAQ;AACpB,UAAM,MAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACjD,QAAI,CAAC,IAAK;AAGV,YAAQ,MAAM,QAAQ,CAAC,MAAM;AAC3B,UAAI,EAAE,SAAS;AACb,UAAE,QAAQ,MAAM,QAAQ,EAAE,OAAO,KAAK,MAAM;AAAA,MAC9C;AAAA,IACF,CAAC;AAED,QAAI,gBAAgB,EAAE;AAAA,EACxB;AAGA,WAAS,cAAc,IAAY,SAAiB;;AAClD,UAAM,MAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACjD,QAAI,CAAC,IAAK;AAEV,QAAI,OAAO;AAGX,QAAI,IAAI,SAAS;AACf,UAAI,QAAQ,OAAO,EAAE,GAAG,IAAI,QAAQ,MAAM,MAAM,QAAA;AAChD,UAAI,QAAQ,QAAQ,eAAe,GAAG;AAEtC,WAAI,SAAI,QAAQ,UAAZ,mBAAmB,OAAO;AAC5B,YAAI,QAAQ,MAAM,MAAM,OAAO;AAAA,MACjC;AACA,sBAAI,SAAQ,eAAZ;AAAA,IACF;AAAA,EACF;AAGA,WAAS,SAAS,IAAY;AAC5B,UAAM,MAAM,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACjD,QAAI,CAAC,OAAO,CAAC,OAAO,IAAI,MAAO;AAE/B,UAAM,MAAM,OAAO,IAAI;AAGvB,UAAM,UAAU,IAAI,MAAM,IAAI,IAAI,MAAM;AACxC,UAAM,SAAS,UAAU;AAGzB,QAAI,cAAc,EAAE,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,KAAK,OAAA,GAAU,EAAE,UAAU,KAAK;AAAA,EAClF;AAGA,WAAS,WAAW;;AAClB,mBAAS,UAAT,mBAAgB;AAChB,YAAQ,QAAQ,CAAA;AAChB,gBAAY,QAAQ;AAAA,EACtB;AAGA,QAAM,YAAY,IAAI,KAAK;AAC3B,MAAI,gBAA2C;AAE/C,WAAS,cACP,SACA,cAAc,OACd,WAAgC,WAChC;AACA,UAAM,MAAM,OAAO,IAAI;AACvB,QAAI,CAAC,IAAK;AAEV,QAAI,UAAU,OAAO;AAEnB,UAAI,eAAe;AACjB,YAAI,IAAI,OAAO,UAAU,OAAO,aAAa;AAC7C,wBAAgB;AAAA,MAClB;AACA,gBAAU,QAAQ;AAAA,IACpB,OAAO;AAEL,gBAAU,QAAQ;AAClB,sBAAgB,CAAC,MAAW;AAE1B,YAAI,KAAa,KAAa;AAE9B,YAAI,EAAE,QAAQ;AACZ,gBAAM,EAAE,OAAO;AACf,gBAAM,EAAE,OAAO;AACf,gBAAM,EAAE,OAAO,OAAO;AAAA,QACxB,WAAW,EAAE,WAAW;AACtB,gBAAM,QAAQ,OAAO,OAAO,aAAa,cAAc,EAAE,SAAS;AAClE,gBAAM,OAAO,OAAO,KAAK,UAAU,MAAM,SAAS;AAClD,gBAAM,OAAO,OAAO,KAAK,UAAU,MAAM,QAAQ;AACjD,gBAAM,MAAM,SAAS,IAAI,MAAM,SAAS;AAAA,QAC1C,OAAO;AACL;AAAA,QACF;AAGA,cAAM,WAAW,MAAM,IAAI,MAAM;AAEjC,cAAM,MAAM,OAAO;AAAA,UACjB,MAAM,GAAG,WAAW,IAAIA,YAAU;AAAA,UAClC;AAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL;AAAA,QAAA,CACD;AACD,YAAI,wCAAe;AAEnB,sBAAA;AAAA,MACF;AACA,UAAI,GAAG,OAAO,UAAU,OAAO,aAAa;AAAA,IAC9C;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;AAGA,SAAS,eAAe,KAAsC;AAC5D,SAAO;AAAA;AAAA,mFAE0E,IAAI,IAAI;AAAA;AAAA,kBAEzE,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,kBAClB,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,kBAClB,IAAI,IAAI,QAAQ,CAAC,CAAC;AAAA,UAC1B,IAAI,cAAc,gCAAgC,IAAI,WAAW,WAAW,EAAE;AAAA;AAAA;AAAA;AAIxF;;;;ACxOA,UAAM,SAAS,OAAqB,YAAY;AAChD,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,4CAA4C;AAGzE,UAAM,MAAM,aAAa,MAAM;AAI/B,UAAM,YAAY;AAAA,MAChB,MAAM,OAAO,IAAI;AAAA,MACjB,CAAC,QAAQ;AACP,YAAI,KAAK;AACP,cAAI,aAAA;AACJ,oBAAA;AAAA,QACF;AAAA,MACF;AAAA,MACA,EAAE,WAAW,KAAA;AAAA,IAAK;AAGpB,gBAAY,MAAM;AAChB,UAAI,SAAA;AAAA,IACN,CAAC;AAGD,YAAQ,cAAc,GAAG;AAGzB,aAAa,GAAG;;aApCdD,WAAQ,KAAA,QAAA,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACqJV,UAAM,MAAM,OAA2B,YAAY;AACnD,QAAI,CAAC,IAAK,OAAM,IAAI,MAAM,0CAA0C;AAGpE,UAAM,cAAc,IAAI,IAAI;AAC5B,UAAM,iBAAiB,MAAM;AAC3B,kBAAY,QAAQ,CAAC,YAAY;AAAA,IACnC;AAGA,UAAM,UAAU,IAAwB,IAAI;AAC5C,UAAM,aAAa,IAAI,KAAK;AAG5B,UAAM,MAAM,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI;AAErC,QAAI,aAAa;AACjB,QAAI,aAAa;AACjB,QAAI,QAAQ;AACZ,QAAI,QAAQ;AAEZ,aAAS,UAAU,GAAe;AAChC,iBAAW,QAAQ;AACnB,mBAAa,EAAE;AACf,mBAAa,EAAE;AACf,cAAQ,IAAI;AACZ,cAAQ,IAAI;AAEZ,eAAS,iBAAiB,aAAa,MAAM;AAC7C,eAAS,iBAAiB,WAAW,QAAQ;AAAA,IAC/C;AAEA,aAAS,OAAO,GAAe;AAC7B,UAAI,CAAC,WAAW,MAAO;AACvB,UAAI,IAAI,SAAS,EAAE,UAAU;AAC7B,UAAI,IAAI,SAAS,EAAE,UAAU;AAAA,IAC/B;AAEA,aAAS,WAAW;AAClB,iBAAW,QAAQ;AACnB,eAAS,oBAAoB,aAAa,MAAM;AAChD,eAAS,oBAAoB,WAAW,QAAQ;AAAA,IAClD;AAGA,UAAM,aAAa;AAAA,MACjB,EAAE,OAAO,OAAO,OAAO,MAAM,MAAM,WAAW,OAAO,OAAA;AAAA,MACrD,EAAE,OAAO,WAAW,OAAO,MAAM,MAAM,iBAAiB,OAAO,UAAA;AAAA,MAC/D;AAAA,QACE,OAAO;AAAA,QACP,OAAO;AAAA,QACP,MAAM;AAAA,QACN,OAAO;AAAA,MAAA;AAAA,MAET,EAAE,OAAO,QAAQ,OAAO,MAAM,MAAM,kBAAkB,OAAO,UAAA;AAAA,IAAU;AAGzE,UAAM,iBAAiB,IAAY,KAAK;AAExC,UAAM,eAAe,SAAS,MAAM;AAClC,UAAI,eAAe,UAAU,MAAO,QAAO,IAAI,QAAQ;AACvD,aAAO,IAAI,QAAQ,MAAM,OAAO,CAAC,MAAM,EAAE,aAAa,eAAe,KAAK;AAAA,IAC5E,CAAC;AAED,UAAM,mBAAmB,CAAC,QAA6B;AACrD,YAAM,MAA8B;AAAA,QAClC,SAAS;AAAA,QACT,SAAS;AAAA,QACT,MAAM;AAAA,MAAA;AAER,aAAO,IAAI,GAAG,KAAK;AAAA,IACrB;AAGA,UAAM,cAAc,IAAyB,SAAS;AAEtD,aAAS,YAAY;AACnB,UAAI;AAAA,QACF;AAAA;AAAA,QACA;AAAA,QACA,YAAY;AAAA,MAAA;AAAA,IAEhB;AAGA,aAAS,SAAS,IAAY;AAC5B,UAAI,UAAU,IAAI,IAAI;AAAA,IACxB;AAEA,aAAS,QAAQ,IAAY;AAC3B,UAAI,SAAS,EAAE;AAAA,IACjB;AAEA,aAAS,SAAS,IAAY;AAC5B,UAAI,UAAU,EAAE;AAAA,IAClB;AAGA,UAAM,YAAY,IAAmB,IAAI;AACzC,UAAM,WAAW,IAAI,EAAE;AACvB,UAAM,cAAc,IAA6B,IAAI;AAErD,aAAS,UAAU,MAAe;AAChC,gBAAU,QAAQ,KAAK;AACvB,eAAS,QAAQ,KAAK;AAEtB,iBAAW,MAAA;;AAAM,iCAAY,UAAZ,mBAAmB;AAAA,SAAU,EAAE;AAAA,IAClD;AAEA,aAAS,WAAW;AAClB,UAAI,UAAU,SAAS,SAAS,MAAM,QAAQ;AAC5C,YAAI,cAAc,UAAU,OAAO,SAAS,MAAM,MAAM;AAAA,MAC1D;AACA,iBAAA;AAAA,IACF;AAEA,aAAS,aAAa;AACpB,gBAAU,QAAQ;AAClB,eAAS,QAAQ;AAAA,IACnB;AAEA,aAAS,eAAe;AACtB,UAAI,OAAO,QAAQ,UAAU,IAAI,QAAQ,MAAM,MAAM,OAAO,GAAG;AAC7D,YAAI,SAAA;AAAA,MACN;AAAA,IACF;;0BAzREjB,mBAoJM,OAAA;AAAA,iBAnJA;AAAA,QAAJ,KAAI;AAAA,QACJ,OAAKC,eAAA,CAAC,aAAW,EAAA,WACI,YAAA,MAAA,CAAW,CAAA;AAAA,QAC/B,OAAKkB;AAAAA,WAAW,YAAA,QAA+B,EAAA,MAAA,IAAI,IAAC,MAAA,KAAc,IAAI,IAAC,SAA6B,EAAA,MAAA,IAAI,IAAC,MAAA,KAAc,IAAI,IAAC,KAAA;AAAA,QAAA;AAAA;QAO7HjB,mBAuBM,OAAA;AAAA,UAtBJ,OAAKD,eAAA,CAAC,qBAAmB,EAAA,eACA,WAAA,MAAA,CAAU,CAAA;AAAA,UAClC,2BAAmB,WAAS,CAAA,SAAA,CAAA;AAAA,UAC5B,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,WAAA,QAAU,OAAU,eAAA;AAAA,QAAc;UAG1B,YAAA,SACdU,UAAA,GAAAX,mBAKM,OALNI,cAKM;AAAA,sCAJJF,mBAA6C,KAAA,EAA1C,OAAM,kCAAA,GAAiC,MAAA,EAAA;AAAA,YAC1CA,mBAES,QAFTG,cAESQ,gBADP,aAAA,MAAa,MAAM,GAAA,CAAA;AAAA,UAAA,oBAIzBb,mBAOWM,UAAA,EAAA,KAAA,KAAA;AAAA,YANTJ,mBAIO,QAJPU,cAIO;AAAA,wCAHLV,mBAA8B,KAAA,EAA3B,OAAM,mBAAA,GAAkB,MAAA,EAAA;AAAA,wDAAG,cAE9B,EAAA;AAAA,cAAAA,mBAAwD,QAAxDM,cAAwDK,gBAA7B,aAAA,MAAa,MAAM,GAAA,CAAA;AAAA,YAAA;sCAEhDX,mBAA8C,KAAA,EAA3C,OAAM,sCAAkC,MAAA,EAAA;AAAA,UAAA;;QAI/CC,eAAAD,mBA+GM,OA/GNkB,cA+GM;AAAA,UA7GJlB,mBAgBM,OAhBNmB,cAgBM;AAAA,YAfJnB,mBAOS,UAAA;AAAA,cANP,uBAAM,OAAK,EAAA,eACcc,WAAI,UAAU,MAAA,CAAK,CAAA;AAAA,cAC3C,SAAO;AAAA,YAAA;cAERd,mBAAmE,KAAA;AAAA,gBAA/D,OAAKD,eAAA,CAAA,MAASe,MAAA,GAAA,EAAI,UAAU,QAAK,aAAA,SAAA,CAAA;AAAA,cAAA;cAA8BM,gBAAA,MACnET,gBAAGG,MAAA,GAAA,EAAI,UAAU,QAAK,SAAA,QAAA,GAAA,CAAA;AAAA,YAAA;YAExBd,mBAMS,UAAA;AAAA,cALP,OAAM;AAAA,cACL,SAAO;AAAA,cACP,UAAUc,MAAA,GAAA,EAAI,QAAQ,MAAM,WAAM;AAAA,YAAA;cAEnCd,mBAA2B,KAAA,EAAxB,OAAM,gBAAA,GAAe,MAAA,EAAA;AAAA,8BAAG,QAC7B,EAAA;AAAA,YAAA;;UAIFA,mBAWM,OAXNqB,cAWM;AAAA,0BAVJvB,mBASOM,UAAA,MAAAC,WARS,YAAU,CAAjB,QAAG;qBADZL,mBASO,QAAA;AAAA,gBAPJ,KAAK,IAAI;AAAA,gBACV,uBAAM,cAAY,EAAA,QACA,yBAAmB,IAAI,MAAA,CAAK,CAAA;AAAA,gBAC7C,SAAK,CAAA,WAAE,eAAA,QAAiB,IAAI;AAAA,cAAA;gBAE7BA,mBAA6D,KAAA;AAAA,kBAAzD,OAAKD,eAAA,CAAA,MAAS,IAAI,IAAI,CAAA;AAAA,kBAAI,OAAKkB,eAAA,EAAA,OAAW,IAAI,OAAK;AAAA,gBAAA;gCAAM,MAC7DN,gBAAG,IAAI,KAAK,GAAA,CAAA;AAAA,cAAA;;;UAKhBX,mBA2EM,OA3ENsB,eA2EM;AAAA,YA1EJf,YA+DkBgB,iBAAA,EA/DD,MAAK,cAAU;AAAA,+BAE5B,MAA4B;AAAA,kCAD9BzB,mBA6DMM,UAAA,MAAAC,WA5DW,aAAA,OAAY,CAApB,SAAI;sCADbP,mBA6DM,OAAA;AAAA,oBA3DH,KAAK,KAAK;AAAA,oBACX,OAAKC,eAAA,CAAC,YAAU,EAAA,oBACce,MAAA,GAAA,EAAI,YAAY,UAAU,KAAK,GAAA,CAAE,CAAA;AAAA,oBAC9D,SAAK,CAAA,WAAE,SAAS,KAAK,EAAE;AAAA,kBAAA;oBAGxBd,mBAGE,QAAA;AAAA,sBAFA,OAAM;AAAA,sBACL,OAAKiB,eAAA,EAAA,YAAgB,iBAAiB,KAAK,QAAQ,GAAA;AAAA,oBAAA;oBAGtDjB,mBAsBM,OAtBNwB,eAsBM;AAAA,sBAnBI,UAAA,UAAc,KAAK,kCAD3B1B,mBAQE,SAAA;AAAA;wBANA,OAAM;AAAA,qFACG,SAAQ,QAAA;AAAA,wBAChB,WAAO;AAAA,mCAAQ,UAAQ,CAAA,OAAA,CAAA;AAAA,mCACP,YAAU,CAAA,QAAA,CAAA;AAAA,wBAAA;AAAA,wBAC1B,iDAAD,MAAA;AAAA,wBAAA,GAAW,CAAA,MAAA,CAAA;AAAA;iCACP;AAAA,wBAAJ,KAAI;AAAA,sBAAA;qCAJK,SAAA,KAAQ;AAAA,sBAAA,mBAOnBA,mBAMM,OAAA;AAAA;wBAJJ,OAAM;AAAA,wBACL,YAAQ2B,cAAA,CAAA,WAAO,UAAU,IAAI,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA,GAE3Bd,gBAAA,KAAK,IAAI,GAAA,IAAAe,aAAA;AAAA,sBAEd1B,mBAEM,OAFN2B,eAEMhB,gBADD,KAAK,IAAI,QAAO,CAAA,CAAA,IAAM,OAAEA,gBAAG,KAAK,IAAI,QAAO,CAAA,CAAA,GAAA,CAAA;AAAA,oBAAA;oBAKlDX,mBAsBM,OAtBN4B,eAsBM;AAAA,sBArBJ5B,mBAMS,UAAA;AAAA,wBALP,OAAM;AAAA,wBACN,OAAM;AAAA,wBACL,SAAKyB,cAAA,CAAA,WAAO,UAAU,IAAI,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA;wBAE3BzB,mBAA0B,KAAA,EAAvB,OAAM,eAAA,GAAc,MAAA,EAAA;AAAA,sBAAA;sBAEzBA,mBAMS,UAAA;AAAA,wBALP,OAAM;AAAA,wBACN,OAAM;AAAA,wBACL,SAAKyB,cAAA,CAAA,WAAO,QAAQ,KAAK,EAAE,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA;wBAE5BzB,mBAA8B,KAAA,EAA3B,OAAM,mBAAA,GAAkB,MAAA,EAAA;AAAA,sBAAA;sBAE7BA,mBAMS,UAAA;AAAA,wBALP,OAAM;AAAA,wBACN,OAAM;AAAA,wBACL,SAAKyB,cAAA,CAAA,WAAO,SAAS,KAAK,EAAE,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA;wBAE7BzB,mBAAyB,KAAA,EAAtB,OAAM,cAAA,GAAa,MAAA,EAAA;AAAA,sBAAA;;;;;;;YAOnB,aAAA,MAAa,WAAM,KAA9BS,aAAAX,mBAOM,OAPN+B,eAOM;AAAA,0CANJ7B,mBAAyB,KAAA,EAAtB,OAAM,cAAA,GAAa,MAAA,EAAA;AAAA,cACtBA,mBAII,KAAA,MAAAW,gBAFAG,MAAA,GAAA,EAAI,UAAU,QAAK,gBAAA,QAAA,GAAA,CAAA;AAAA,YAAA;;;mBA1GS,YAAA,KAAW;AAAA,QAAA;;;;;;ACArD,IAAI,aAAa;AAEV,SAAS,SAAS,QAAsB;AAE7C,QAAM,aAAa,WAA6C,IAAI;AAGpE,QAAM,YAAY,IAAiB,EAAE;AAGrC,QAAM,gBAAgB,IAAmB,IAAI;AAG7C,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,cAAc,IAAI,CAAC;AACzB,QAAM,gBAAgB,IAAI,CAAC;AAC3B,QAAM,mBAAmB,IAAI,CAAC;AAG9B,QAAM,iBAAiB,IAAI,KAAK;AAChC,QAAM,mBAAmB,IAAmB,IAAI;AAGhD,MAAI,gBAAuD;AAI3D,WAAS,iBAAiB;AACxB,UAAM,MAAM,OAAO,IAAI;AACvB,QAAI,CAAC,IAAK;AAEV,UAAM,QAAQ,IAAI,OAAO,MAAM,aAAA;AAC/B,QAAI,SAAS,KAAK;AAClB,eAAW,QAAQ;AAAA,EACrB;AAGA,WAAS,kBAAkB,OAAkB;AAC3C,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,MAAO,QAAO;AAGnB,UAAM,YAAY,MAAM,OAAO,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAA6B;AAE3F,UAAM,OAAO,IAAI,OAAO,QAAQ,kBAAkB;AAAA,MAChD;AAAA,MACA,OAAO;AAAA,QACL,OAAO,OAAO,OAAO,MAAM,mBAAmB,SAAS;AAAA,QACvD,OAAO;AAAA,QACP,SAAS;AAAA,QACT,eAAe;AAAA,MAAA;AAAA,MAEjB,MAAM,EAAE,SAAS,MAAM,GAAA;AAAA,IAAG,CAC3B;AAED,UAAM,WAAW,IAAI;AACrB,WAAO;AAAA,EACT;AAGA,WAAS,oBAAoB,OAAkB,SAAiB,OAAe;AAC7E,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,SAAS,SAAS,QAAS;AAEhC,UAAM,YAAY,MAAM,OAAO,MAAM,SAAS,QAAQ,CAAC,EACpD,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAA6B;AAE/D,UAAM,UAAU,IAAI,OAAO,QAAQ,kBAAkB;AAAA,MACnD;AAAA,MACA,OAAO;AAAA,QACL,OAAO,OAAO,OAAO,MAAM,mBAAmB,SAAS;AAAA,QACvD,OAAO;AAAA,QACP,SAAS;AAAA,QACT,eAAe;AAAA,MAAA;AAAA,IACjB,CACD;AACD,UAAM,WAAW,OAAO;AAExB,QAAI,CAAC,MAAM,sBAAsB;AAC/B,YAAM,uBAAuB,CAAA;AAAA,IAC/B;AACA,UAAM,qBAAqB,KAAK,OAAO;AAAA,EACzC;AAGA,WAAS,sBAAsB,OAAkB;AAC/C,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,MAAO;AAEZ,UAAM,YAAY,MAAM,OAAO,MAAM,gBAAiB;AACtD,QAAI,CAAC,UAAW;AAGhB,QAAI,MAAM,eAAe;AACvB,YAAM,cAAc,WAAW,CAAC,UAAU,KAAK,UAAU,KAAK,UAAU,GAAG;AAAA,IAC7E,OAAO;AACL,YAAM,SAAS,IAAI,OAAO,QAAQ,gBAAgB;AAAA,QAChD,UAAU,CAAC,UAAU,KAAK,UAAU,KAAK,UAAU,GAAG;AAAA,QACtD,OAAO;AAAA,UACL,OAAO;AAAA,UACP,OAAO;AAAA,UACP,kBAAkB,OAAO,OAAO,iBAAiB;AAAA,UACjD,gBAAgB,OAAO,OAAO,eAAe;AAAA,QAAA;AAAA,MAC/C,CACD;AACD,YAAM,WAAW,MAAM;AACvB,YAAM,gBAAgB;AAAA,IACxB;AAAA,EACF;AAGA,WAAS,SAAS,QAAsB,OAAO,MAAM;AACnD,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,KAAK,SAAS,YAAY;AAChC,UAAM,QAAmB,EAAE,IAAI,MAAM,OAAA;AACrC,UAAM,cAAc,kBAAkB,KAAK;AAC3C,cAAU,MAAM,KAAK,KAAK;AAC1B,WAAO;AAAA,EACT;AAGA,WAAS,cAAc,OAAO,QAAQ;AACpC,QAAI,iBAAiB,MAAO,cAAA;AAE5B,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,KAAK,YAAY,YAAY;AACnC,UAAM,QAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA,QAAQ,CAAA;AAAA,MACR,kBAAkB;AAAA,IAAA;AAEpB,eAAW,QAAQ;AACnB,cAAU,MAAM,KAAK,KAAK;AAC1B,qBAAiB,QAAQ;AACzB,mBAAe,QAAQ;AACvB,WAAO;AAAA,EACT;AAGA,WAAS,kBAAkB,IAAY,KAAa,KAAa,MAAM,GAAG;AACxE,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrD,QAAI,CAAC,MAAO;AAEZ,UAAM,QAAoB;AAAA,MACxB,MAAM,KAAK,IAAA;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,IAAA;AAEF,UAAM,OAAO,KAAK,KAAK;AACvB,UAAM,mBAAmB,MAAM,OAAO,SAAS;AAG/C,QAAI,MAAM,OAAO,WAAW,GAAG;AAC7B,YAAM,cAAc,kBAAkB,KAAK;AAC3C,4BAAsB,KAAK;AAAA,IAC7B,OAAO;AAEL,0BAAoB,OAAO,MAAM,OAAO,SAAS,GAAG,MAAM,OAAO,SAAS,CAAC;AAC3E,4BAAsB,KAAK;AAAA,IAC7B;AAGA,QAAI,OAAO,IAAI,OAAO;AACpB,aAAO,IAAI,MAAM;AAAA,QACf,CAAC,KAAK,KAAK,MAAM,EAAE;AAAA,QACnB,EAAE,QAAQ,KAAK,UAAU,IAAA;AAAA,MAAI;AAAA,IAEjC;AAAA,EACF;AAGA,WAAS,aAAa,IAAa;;AACjC,UAAM,WAAW,MAAM,iBAAiB;AACxC,QAAI,CAAC,SAAU;AAEf,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,QAAQ;AAC3D,QAAI,OAAO;AACT,YAAM,mBAAmB;AACzB,UAAI,MAAM,eAAe;AACvB,yBAAW,UAAX,mBAAkB,cAAc,MAAM;AACtC,cAAM,gBAAgB;AAAA,MACxB;AAAA,IACF;AAEA,QAAI,iBAAiB,UAAU,UAAU;AACvC,uBAAiB,QAAQ;AACzB,qBAAe,QAAQ;AAAA,IACzB;AAAA,EACF;AAGA,WAAS,KAAK,SAAkB;AAC9B,UAAM,KAAK,WAAW,cAAc;AACpC,QAAI,CAAC,GAAI;AAET,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrD,QAAI,CAAC,SAAS,MAAM,OAAO,SAAS,EAAG;AAEvC,QAAI,cAAc,UAAU,IAAI;AAC9B,kBAAY,EAAE;AAAA,IAChB;AAEA,cAAU,QAAQ;AAClB,uBAAA;AAEA,UAAM,QAAQ,MAAM,OAAO,CAAC,EAAE;AAC9B,UAAM,MAAM,MAAM,OAAO,MAAM,OAAO,SAAS,CAAC,EAAE;AAIlD,oBAAgB,YAAY,MAAM;AAChC,YAAMgB,SAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc,KAAK;AACtE,UAAI,CAACA,UAAS,CAAC,UAAU,MAAO;AAEhC,YAAM,UAAU,KAAK,IAAA,KAASA,OAAM,kBAAkB,KAAK;AAC3D,YAAM,QAAQ,MAAM;AACpB,YAAM,WAAW,KAAK,IAAI,UAAU,OAAO,CAAC;AAG5C,kBAAY,QAAQ,QAAQ,WAAW;AACvC,uBAAiB,QAAQ,WAAW;AAGpC,YAAM,YAAY,KAAK,MAAM,YAAYA,OAAM,OAAO,SAAS,EAAE;AACjE,0BAAoBA,QAAO,SAAS;AAAA,IACtC,GAAG,EAAE;AAAA,EACP;AAEA,WAAS,oBAAoB,OAAkB,OAAe;;AAC5D,UAAM,QAAQ,WAAW;AACzB,QAAI,CAAC,MAAO;AAGZ,QAAI,MAAM,aAAa;AACrB,YAAM,cAAc,MAAM,WAAW;AAAA,IACvC;AAGA,UAAM,YAAY,MAAM,OAAO,MAAM,GAAG,QAAQ,CAAC,EAC9C,IAAI,CAAC,MAAM,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAA6B;AAE/D,UAAM,cAAc,IAAI,OAAO,QAAQ,kBAAkB;AAAA,MACvD;AAAA,MACA,OAAO;AAAA,QACL,OAAO,OAAO,OAAO,MAAM,mBAAmB,SAAS;AAAA,QACvD,OAAO;AAAA,QACP,SAAS;AAAA,QACT,eAAe;AAAA,MAAA;AAAA,IACjB,CACD;AACD,UAAM,WAAW,MAAM,WAAW;AAGlC,UAAM,KAAK,MAAM,OAAO,KAAK;AAC7B,iBAAO,IAAI,UAAX,mBAAkB;AAAA,MAChB,CAAC,GAAG,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG;AAAA,MAC7B,EAAE,QAAQ,KAAK,UAAU,EAAA;AAAA;AAAA,EAE7B;AAEA,WAAS,QAAQ;AACf,cAAU,QAAQ;AAClB,uBAAA;AAAA,EACF;AAEA,WAAS,OAAO;AACd,cAAU,QAAQ;AAClB,qBAAiB,QAAQ;AACzB,gBAAY,QAAQ;AACpB,uBAAA;AAGA,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc,KAAK;AACtE,QAAI,SAAS,WAAW,OAAO;AAC7B,UAAI,MAAM,YAAa,YAAW,MAAM,cAAc,MAAM,WAAW;AACvE,YAAM,cAAc,kBAAkB,KAAK;AAAA,IAC7C;AAAA,EACF;AAEA,WAAS,SAAS,OAAe;AAC/B,kBAAc,QAAQ;AACtB,QAAI,UAAU,OAAO;AACnB,YAAA;AACA,WAAA;AAAA,IACF;AAAA,EACF;AAGA,WAAS,KAAK,UAAkB;AAC9B,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,cAAc,KAAK;AACtE,QAAI,CAAC,MAAO;AAEZ,UAAM,YAAY,KAAK,MAAO,WAAW,OAAQ,MAAM,OAAO,SAAS,EAAE;AACzE,gBAAY,QAAQ,MAAM,OAAO,SAAS,EAAE;AAC5C,qBAAiB,QAAQ;AACzB,wBAAoB,OAAO,SAAS;AAAA,EACtC;AAGA,WAAS,YAAY,IAAY;AAC/B,kBAAc,QAAQ;AACtB,SAAA;AAAA,EACF;AAGA,WAAS,WAAW,IAAY;AAC9B,UAAM,QAAQ,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE;AACrD,QAAI,CAAC,SAAS,CAAC,OAAO,IAAI,MAAO;AAEjC,UAAM,QAAQ,MAAM,OAAO,CAAC;AAC5B,WAAO,IAAI,MAAM;AAAA,MACf,CAAC,MAAM,KAAK,MAAM,KAAK,MAAM,MAAM,GAAI;AAAA,MACvC,EAAE,QAAQ,KAAM,UAAU,IAAA;AAAA,IAAI;AAAA,EAElC;AAGA,WAAS,YAAY,IAAY;;AAC/B,UAAM,MAAM,UAAU,MAAM,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE;AACxD,QAAI,QAAQ,GAAI;AAEhB,UAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,QAAI,MAAM,YAAa,kBAAW,UAAX,mBAAkB,cAAc,MAAM;AAC7D,QAAI,MAAM,cAAe,kBAAW,UAAX,mBAAkB,cAAc,MAAM;AAE/D,QAAI,MAAM,sBAAsB;AAC9B,YAAM,qBAAqB,QAAQ,CAAC,QAAQ;;AAC1C,SAAAC,MAAA,WAAW,UAAX,gBAAAA,IAAkB,cAAc;AAAA,MAClC,CAAC;AAAA,IACH;AACA,cAAU,MAAM,OAAO,KAAK,CAAC;AAE7B,QAAI,cAAc,UAAU,IAAI;AAC9B,oBAAc,QAAQ;AACtB,WAAA;AAAA,IACF;AACA,QAAI,iBAAiB,UAAU,IAAI;AACjC,uBAAiB,QAAQ;AACzB,qBAAe,QAAQ;AAAA,IACzB;AAAA,EACF;AAEA,WAAS,WAAW;;AAClB,SAAA;AACA,iBAAA;AACA,qBAAW,UAAX,mBAAkB;AAClB,cAAU,QAAQ,CAAA;AAClB,kBAAc,QAAQ;AAAA,EACxB;AAGA,WAAS,qBAAqB;AAC5B,QAAI,eAAe;AACjB,oBAAc,aAAa;AAC3B,sBAAgB;AAAA,IAClB;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EAAA;AAEJ;;;;AC3ZA,UAAM,SAAS,OAAqB,YAAY;AAChD,QAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,wCAAwC;AAGrE,UAAM,QAAQ,SAAS,MAAM;AAG7B,UAAM,YAAY;AAAA,MAChB,MAAM,OAAO,IAAI;AAAA,MACjB,CAAC,QAAQ;AACP,YAAI,KAAK;AACP,gBAAM,eAAA;AACN,oBAAA;AAAA,QACF;AAAA,MACF;AAAA,MACA,EAAE,WAAW,KAAA;AAAA,IAAK;AAGpB,gBAAY,MAAM;AAChB,YAAM,SAAA;AAAA,IACR,CAAC;AAGD,YAAQ,gBAAgB,KAAK;AAG7B,aAAa,KAAK;;aAnChBhB,WAAQ,KAAA,QAAA,SAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC2MV,UAAM,QAAQ,OAAuB,cAAc;AACnD,QAAI,CAAC,MAAO,OAAM,IAAI,MAAM,kCAAkC;AAG9D,UAAM,cAAc,IAAI,IAAI;AAC5B,UAAM,aAAa,IAAI,KAAK;AAC5B,UAAM,MAAM,SAAS,EAAE,GAAG,IAAI,GAAG,IAAI;AAErC,QAAI,aAAa,GACf,aAAa,GACb,QAAQ,GACR,QAAQ;AAEV,aAAS,iBAAiB;AACxB,kBAAY,QAAQ,CAAC,YAAY;AAAA,IACnC;AAEA,aAAS,UAAU,GAAe;AAChC,iBAAW,QAAQ;AACnB,mBAAa,EAAE;AACf,mBAAa,EAAE;AACf,cAAQ,IAAI;AACZ,cAAQ,IAAI;AACZ,eAAS,iBAAiB,aAAa,MAAM;AAC7C,eAAS,iBAAiB,WAAW,QAAQ;AAAA,IAC/C;AACA,aAAS,OAAO,GAAe;AAC7B,UAAI,CAAC,WAAW,MAAO;AACvB,UAAI,IAAI,SAAS,EAAE,UAAU;AAC7B,UAAI,IAAI,SAAS,EAAE,UAAU;AAAA,IAC/B;AACA,aAAS,WAAW;AAClB,iBAAW,QAAQ;AACnB,eAAS,oBAAoB,aAAa,MAAM;AAChD,eAAS,oBAAoB,WAAW,QAAQ;AAAA,IAClD;AAGA,aAAS,cAAc,IAAY;AACjC,UAAI,MAAM,cAAc,UAAU,GAAI;AACtC,YAAM,YAAY,EAAE;AACpB,YAAM,KAAA;AAAA,IACR;AAEA,UAAM,kBAAkB,SAAS,MAAM;AACrC,YAAM,IAAI,MAAM,UAAU,MAAM;AAAA,QAC9B,CAAC,MAAM,EAAE,OAAO,MAAM,cAAc;AAAA,MAAA;AAEtC,cAAO,uBAAG,SAAQ;AAAA,IACpB,CAAC;AAED,UAAM,eAAe,SAAS,MAAM;AAClC,YAAM,IAAI,MAAM,UAAU,MAAM;AAAA,QAC9B,CAAC,MAAM,EAAE,OAAO,MAAM,cAAc;AAAA,MAAA;AAEtC,UAAI,CAAC,KAAK,EAAE,OAAO,SAAS,EAAG,QAAO;AACtC,aAAO,EAAE,OAAO,EAAE,OAAO,SAAS,CAAC,EAAE;AAAA,IACvC,CAAC;AAGD,UAAM,eAAe,CAAC,GAAG,GAAG,GAAG,CAAC;AAGhC,aAAS,OAAO,GAAU;AACxB,YAAM,MAAM,WAAY,EAAE,OAA4B,KAAK;AAC3D,YAAM,KAAK,GAAG;AAAA,IAChB;AAGA,aAAS,WAAW,IAAoB;AACtC,UAAI,CAAC,GAAI,QAAO;AAChB,YAAM,IAAI,IAAI,KAAK,EAAE;AACrB,aAAO,GAAG,OAAO,EAAE,YAAY,EAAE,SAAS,GAAG,GAAG,CAAC,IAAI,OAAO,EAAE,WAAA,CAAY,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,IAC9F;AAGA,aAAS,eAAe;AAEtB,YAAM,UAAU;AAChB,YAAM,UAAU;AAChB,YAAM,SAAS,CAAA;AACf,UAAI,IAAI,KAAK,IAAA;AAGb,UAAI,UAAU,KAAK,OAAA,IAAW,KAAK,KAAK;AACxC,YAAM,OAAO;AAEb,eAAS,IAAI,GAAG,IAAI,MAAM,KAAK;AAC7B,aAAK,MAAO,KAAK,OAAA,IAAW;AAE5B,oBAAY,KAAK,OAAA,IAAW,QAAQ,KAAK,KAAK;AAC9C,cAAM,UAAU,UAAU,KAAK,IAAI,OAAO,IAAI;AAC9C,cAAM,UAAU,UAAU,KAAK,IAAI,OAAO,IAAI;AAC9C,cAAM,MAAM,KAAK,KAAK,IAAK,IAAI,OAAQ,KAAK,EAAE,IAAI;AAClD,eAAO,KAAK,EAAE,MAAM,GAAG,KAAK,SAAS,KAAK,SAAS,KAAK;AAAA,MAC1D;AAEA,YAAM,SAAS,QAAQ,MAAM,UAAU,EAAE;AAAA,IAC3C;AAEA,QAAI,WAAW;AAGf,QAAI,iBAAwD;AAC5D,QAAI,qBAAoC;AAExC,aAAS,iBAAiB;AACxB,UAAI,MAAM,eAAe,OAAO;AAC9B,qBAAA;AAAA,MACF,OAAO;AACL,sBAAA;AAAA,MACF;AAAA,IACF;AAEA,aAAS,gBAAgB;;AACvB,YAAM,MAAK,WAAM,cAAc,QAAQ,UAAU,EAAE,MAAxC,mBAA2C;AACtD,UAAI,CAAC,GAAI;AACT,2BAAqB;AAGrB,YAAM,aAAa;AACnB,YAAM,aAAa;AAEnB,YAAM,aAAa;AACnB,YAAM,aAAa;AAEnB,YAAM,eAAe;AACrB,YAAM,aAAc,IAAI,KAAK,KAAM;AAEnC,UAAI,QAAQ,KAAK,OAAA,IAAW,IAAI,KAAK;AACrC,UAAI,YAAY;AAEhB,uBAAiB,YAAY,MAAM;AACjC;AAEA,cAAM,MAAM,aAAa,KAAK,IAAI,KAAK,IAAI;AAC3C,cAAM,MAAM,aAAa,KAAK,IAAI,KAAK,IAAI;AAC3C,cAAM,MAAM,KAAK,KAAK,IAAI,QAAQ,CAAC,IAAI;AACvC,cAAM,kBAAkB,IAAI,KAAK,KAAK,GAAG;AAGzC,iBAAS;AAGT,YAAI,aAAa,cAAc;AAC7B,uBAAA;AAAA,QACF;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAEA,aAAS,eAAe;AACtB,UAAI,gBAAgB;AAClB,sBAAc,cAAc;AAC5B,yBAAiB;AAAA,MACnB;AACA,UAAI,oBAAoB;AACtB,cAAM,aAAa,kBAAkB;AACrC,6BAAqB;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,qBAAqB,SAAS,MAAM;AACxC,YAAM,IAAI,MAAM,UAAU,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,kBAAkB;AACvE,cAAO,uBAAG,OAAO,WAAU;AAAA,IAC7B,CAAC;AAGD,aAAS,eAAe;AACtB,UAAI,OAAO,QAAQ,UAAU,MAAM,UAAU,MAAM,MAAM,OAAO,GAAG;AACjE,qBAAA;AACA,cAAM,SAAA;AAAA,MACR;AAAA,IACF;;0BA5XEjB,mBAwMM,OAAA;AAAA,QAvMJ,OAAKC,eAAA,CAAC,eAAa,EAAA,WACE,YAAA,MAAA,CAAW,CAAA;AAAA,QAC/B,8BAAe,IAAI,IAAC,MAAA,KAAc,IAAI,IAAC,KAAA,CAAA;AAAA,MAAA;QAGxCC,mBAoBM,OAAA;AAAA,UAnBJ,OAAKD,eAAA,CAAC,uBAAqB,EAAA,eACF,WAAA,MAAA,CAAU,CAAA;AAAA,UAClC,2BAAmB,WAAS,CAAA,SAAA,CAAA;AAAA,UAC5B,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAE,WAAA,QAAU,OAAU,eAAA;AAAA,QAAc;UAE1B,YAAA,SACdU,UAAA,GAAAX,mBAGM,OAHN,YAGM;AAAA,sCAFJE,mBAA4C,KAAA,EAAzC,OAAM,iCAAA,GAAgC,MAAA,EAAA;AAAA,YACzCA,mBAAmE,QAAnE,YAAmEW,gBAAtCG,MAAA,KAAA,EAAM,UAAU,MAAM,MAAM,GAAA,CAAA;AAAA,UAAA,oBAG7DhB,mBAOWM,UAAA,EAAA,KAAA,KAAA;AAAA,YANTJ,mBAIO,QAJP,YAIO;AAAA,wCAHLA,mBAA6B,KAAA,EAA1B,OAAM,kBAAA,GAAiB,MAAA,EAAA;AAAA,wDAAG,UAE7B,EAAA;AAAA,cAAAA,mBAAmE,QAAnE,YAAmEW,gBAAtCG,MAAA,KAAA,EAAM,UAAU,MAAM,MAAM,GAAA,CAAA;AAAA,YAAA;sCAE3Dd,mBAA8C,KAAA,EAA3C,OAAM,sCAAkC,MAAA,EAAA;AAAA,UAAA;;QAK/CC,eAAAD,mBA0KM,OA1KN,YA0KM;AAAA,UAxKJA,mBAqBM,OArBN,YAqBM;AAAA,YApBJA,mBAES,UAAA;AAAA,cAFD,OAAM;AAAA,cAAoB,SAAO;AAAA,YAAA;cACvCA,mBAAwB,KAAA,EAArB,OAAM,aAAA,GAAY,MAAA,EAAA;AAAA,8BAAG,UAC1B,EAAA;AAAA,YAAA;YACAA,mBASS,UAAA;AAAA,cARP,uBAAM,OACEc,aAAM,eAAe,QAAK,gBAAA,WAAA,CAAA;AAAA,cACjC,SAAO;AAAA,YAAA;cAERd,mBAEE,KAAA;AAAA,gBADC,OAAKD,eAAA,CAAA,MAASe,MAAA,KAAA,EAAM,eAAe,QAAK,YAAA,SAAA,CAAA;AAAA,cAAA;cACzCM,gBAAA,MACFT,gBAAGG,MAAA,KAAA,EAAM,eAAe,QAAK,SAAA,MAAA,GAAA,CAAA;AAAA,YAAA;YAE/Bd,mBAMS,UAAA;AAAA,cALP,OAAM;AAAA,cACL,SAAO;AAAA,cACP,UAAUc,MAAA,KAAA,EAAM,UAAU,MAAM,WAAM;AAAA,YAAA;cAEvCd,mBAA2B,KAAA,EAAxB,OAAM,gBAAA,GAAe,MAAA,EAAA;AAAA,YAAA;;UAKac,MAAA,KAAA,EAAM,cAAc,SAA7DL,aAAAX,mBA0DM,OA1DN,YA0DM;AAAA,YAxDJE,mBAIM,OAJN,YAIM;AAAA,0CAHJA,mBAAwB,KAAA,EAArB,OAAM,aAAA,GAAY,MAAA,EAAA;AAAA,8BAAG,MACxBW,gBAAG,gBAAA,KAAe,IAAG,KACrB,CAAA;AAAA,cAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAX,mBAA8C,QAAA,EAAxC,OAAM,0BAAuB,QAAI,EAAA;AAAA,YAAA;YAIzCA,mBAeM,OAfN,aAeM;AAAA,cAdJA,mBAES,UAAA;AAAA,gBAFD,OAAM;AAAA,gBAAY,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAEc,MAAA,KAAA,EAAM,KAAA;AAAA,cAAI;gBACzCd,mBAAwB,KAAA,EAArB,OAAM,aAAA,GAAY,MAAA,EAAA;AAAA,cAAA;cAEvBA,mBAOS,UAAA;AAAA,gBANP,OAAM;AAAA,gBACL,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAEc,MAAA,KAAA,EAAM,UAAU,QAAQA,MAAA,KAAA,EAAM,UAAUA,MAAA,KAAA,EAAM,KAAA;AAAA,cAAI;gBAE1Dd,mBAEE,KAAA;AAAA,kBADC,OAAKD,eAAA,CAAA,MAASe,MAAA,KAAA,EAAM,UAAU,QAAK,aAAA,SAAA,CAAA;AAAA,gBAAA;;cAGxCd,mBAES,UAAA;AAAA,gBAFD,OAAM;AAAA,gBAAY,SAAK,OAAA,CAAA,MAAA,OAAA,CAAA,IAAA,CAAA,WAAEc,MAAA,KAAA,EAAM,KAAA;AAAA,cAAI;gBACzCd,mBAA2B,KAAA,EAAxB,OAAM,gBAAA,GAAe,MAAA,EAAA;AAAA,cAAA;;YAK5BA,mBAaM,OAbN,aAaM;AAAA,cAZJ,OAAA,EAAA,MAAA,OAAA,EAAA,IAAAA,mBAAmC,QAAA,EAA7B,OAAM,cAAA,GAAc,MAAE,EAAA;AAAA,cAC5BA,mBAUM,OAVN,aAUM;AAAA,8BATJF,mBAQSM,UAAA,MAAAC,WAPK,cAAY,CAAjB,MAAC;yBADVL,mBAQS,UAAA;AAAA,oBANN,KAAK;AAAA,oBACN,OAAKD,eAAA,CAAC,aAAW,EAAA,QACCe,MAAA,KAAA,EAAM,cAAc,UAAU,EAAA,CAAC,CAAA;AAAA,oBAChD,SAAK,CAAA,WAAEA,MAAA,KAAA,EAAM,SAAS,CAAC;AAAA,kBAAA,GAErBH,gBAAA,CAAC,IAAG,MACT,IAAA,WAAA;AAAA;;;YAKJX,mBAcM,OAdN,aAcM;AAAA,cAbJA,mBAES,QAFT,aAESW,gBADP,WAAWG,MAAA,KAAA,EAAM,YAAY,KAAK,CAAA,GAAA,CAAA;AAAA,cAEpCd,mBAQE,SAAA;AAAA,gBAPA,MAAK;AAAA,gBACL,OAAM;AAAA,gBACN,KAAI;AAAA,gBACJ,KAAI;AAAA,gBACJ,MAAK;AAAA,gBACJ,OAAOc,MAAA,KAAA,EAAM,iBAAiB;AAAA,gBAC9B,SAAO;AAAA,cAAA;cAEVd,mBAA8D,QAA9D,aAA8DW,gBAAlC,WAAW,aAAA,KAAY,CAAA,GAAA,CAAA;AAAA,YAAA;;UAO/CG,MAAA,KAAA,EAAM,eAAe,UAAUA,MAAA,KAAA,EAAM,cAAc,SAF3DL,UAAA,GAAAX,mBAYM,OAZN,aAYM;AAAA,wCARJE,mBAIM,OAAA,EAJD,OAAM,oBAAgB;AAAA,cACzBA,mBAAwB,KAAA,EAArB,OAAM,cAAY;AAAA,8BAAG,SAExB;AAAA,cAAAA,mBAA0B,QAAA,EAApB,OAAM,aAAW;AAAA,YAAA;YAEzBA,mBAEM,OAFN,aAEM;AAAA,0DAFsB,SACtB,EAAA;AAAA,cAAAA,mBAAyC,gCAA9B,mBAAA,KAAkB,GAAA,CAAA;AAAA,0DAAY,UAC/C,EAAA;AAAA,YAAA;;UAIFA,mBAmEM,OAnEN,aAmEM;AAAA,YAlEJO,YAwDkBgB,iBAAA,EAxDD,MAAK,gBAAY;AAAA,+BAE9B,MAAqC;AAAA,iBADvCd,UAAA,IAAA,GAAAX,mBAsDMM,2BArDWU,MAAA,KAAA,EAAM,UAAU,QAAxB,SAAI;sCADbhB,mBAsDM,OAAA;AAAA,oBApDH,KAAK,KAAK;AAAA,oBACX,uBAAM,cAAY;AAAA,sBAC6B,sBAAAgB,MAAA,KAAA,EAAM,cAAc,UAAU,KAAK;AAAA,8CAA2C,KAAK,GAAG,WAAU,UAAA;AAAA,oBAAA;oBAI9I,SAAK,CAAA,WAAE,cAAc,KAAK,EAAE;AAAA,kBAAA;oBAG7Bd,mBAOE,QAAA;AAAA,sBANA,OAAM;AAAA,sBACL,OAAKiB,eAAA;AAAA,oCAAiC,KAAK,GAAG,WAAU,UAAA;;;oBAO3DjB,mBAgBM,OAhBN,aAgBM;AAAA,sBAfJA,mBAQM,OARN,aAQM;AAAA,wBAPJA,mBAKE,KAAA;AAAA,0BAJC,OAAKD,eAAA;AAAA;4BAAoD,KAAK,GAAG,WAAU,UAAA,IAAA,YAAA;AAAA,0BAAA;;wCAI5E,MACFY,gBAAG,KAAK,IAAI,GAAA,CAAA;AAAA,sBAAA;sBAEdX,mBAKM,OALN,aAKM;AAAA,wBAJDoB,gBAAAT,gBAAA,KAAK,OAAO,MAAM,IAAG,QACxB,CAAA;AAAA,wBAAY,KAAK,GAAG,WAAU,UAAA,kBAA9Bb,mBAC8B,QAD9B,aACG,IAAE;;;oBAKTE,mBAeM,OAfN,aAeM;AAAA,sBAdJA,mBAMS,UAAA;AAAA,wBALP,OAAM;AAAA,wBACN,OAAM;AAAA,wBACL,mCAAYc,MAAA,KAAA,EAAM,WAAW,KAAK,EAAE,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA;wBAErCd,mBAA8B,KAAA,EAA3B,OAAM,mBAAA,GAAkB,MAAA,EAAA;AAAA,sBAAA;sBAE7BA,mBAMS,UAAA;AAAA,wBALP,OAAM;AAAA,wBACN,OAAM;AAAA,wBACL,mCAAYc,MAAA,KAAA,EAAM,YAAY,KAAK,EAAE,GAAA,CAAA,MAAA,CAAA;AAAA,sBAAA;wBAEtCd,mBAAyB,KAAA,EAAtB,OAAM,cAAA,GAAa,MAAA,EAAA;AAAA,sBAAA;;;;;;;YAQtBc,MAAA,KAAA,EAAM,UAAU,MAAM,WAAM,KADpCL,UAAA,GAAAX,mBAMM,OANN,aAMM,CAAA,GAAA,OAAA,EAAA,MAAA,OAAA,EAAA,IAAA;AAAA,cAFJE,mBAAyB,KAAA,EAAtB,OAAM,cAAA,GAAa,MAAA,EAAA;AAAA,cACtBA,mBAAa,WAAV,UAAM,EAAA;AAAA,YAAA;;;mBAvKyB,YAAA,KAAW;AAAA,QAAA;;;;;;ACyBvD,MAAM,aAAwC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EAAA,gBACAgC;AAAAA,EACA;AAAA,EAAA,YACAC;AAAAA,EACA;AACF;AAEA,MAAM,WAAW;AAAA,EACf,QAAQ,KAAU,SAA+B;AAC/C,UAAM,UAAS,mCAAS,WAAU;AAClC,eAAW,CAAC,MAAM,SAAS,KAAK,OAAO,QAAQ,UAAU,GAAG;AAC1D,UAAI,UAAU,SAAS,GAAG,MAAM,GAAG,IAAI,KAAK,MAAM,SAAS;AAAA,IAC7D;AAAA,EACF;AACF;"}
1
+ {"version":3,"file":"yi-map-web.mjs","sources":["../src/components/mars-work/expand/task/CameraList.js","../src/components/mars-work/expand/task/CameraView.js","../src/components/mars-work/expand/task/MapRotate.js","../src/components/mars-work/expand/task/PointRotate.js","../src/components/mars-work/expand/task/RouteLine.js","../src/components/mars-work/expand/task/ZoomIn.js","../src/components/mars-work/expand/task/ZoomOut.js","../src/components/mars-work/expand/task/FlickerEntity.js","../src/components/mars-work/expand/graphic/CanvasBillboard.js","../src/components/mars-work/mars-map.vue","../src/components/mars-map/panels/ToolbarPanel.vue","../src/components/mars-map/panels/VisionPanel.vue","../src/components/mars-map/composables/useMap.ts","../src/components/mars-map/composables/useMeasure.ts","../src/components/mars-map/composables/useDraw.ts","../src/components/mars-map/composables/useVision.ts","../src/components/mars-map/MarsMapContainer.vue","../src/components/business/poi-marker/usePoiMarker.ts","../src/components/business/poi-marker/PoiMarkerLayer.vue","../src/components/business/poi-marker/PoiMarkerPanel.vue","../src/components/business/track/useTrack.ts","../src/components/business/track/TrackLayer.vue","../src/components/business/track/TrackPanel.vue","../src/index.ts"],"sourcesContent":["import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 视角列表播放(分步执行)\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n * @param {object[]} [options.list] 视角数组\r\n */\r\nexport class CameraList extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraViewList(this.options.list)\r\n }\r\n\r\n // 暂停(非必须)\r\n _pauseWork() {\r\n this._disableWork()\r\n }\r\n}\r\nmars3d.thing.Task.register(\"cameraList\", CameraList)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 单个视角定位\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.center] 视角参数\r\n */\r\nexport class CameraView extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraView(this.options.center, { duration: this._duration })\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n this._map.cancelFlyTo()\r\n }\r\n}\r\nmars3d.thing.Task.register(\"camera\", CameraView)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 地球自旋转\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.center] 初始视角\r\n * @param {number} [options.speed] 旋转速度\r\n */\r\nexport class MapRotate extends mars3d.TaskItem {\r\n constructor(options = {}) {\r\n super(options)\r\n\r\n this._speed = this.options.speed || 0.01\r\n this._center = this.options.center || { lat: 29.093038, lng: 108.804459, alt: 23321232.7, heading: 0, pitch: -90 }\r\n }\r\n\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.setCameraView(this._center, {\r\n duration: 1,\r\n complete: () => {\r\n this._map.on(mars3d.EventType.clockTick, this._map_onClockTick, this)\r\n }\r\n })\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n this._map.off(mars3d.EventType.clockTick, this._map_onClockTick, this)\r\n }\r\n\r\n _map_onClockTick() {\r\n if (this.isPause) {\r\n return // 暂停时不执行\r\n }\r\n\r\n this._map.scene.camera.rotate(mars3d.Cesium.Cartesian3.UNIT_Z, this._speed)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"mapRotate\", MapRotate)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 内或外旋转\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {boolean} [options.isRotateOut] true:绕外旋转 ,false:绕内旋转\r\n * @param {boolean} [options.direction=false] 旋转方向, true逆时针,false顺时针\r\n * @param {number} [options.time=60] 飞行一周所需时间(单位 秒),控制速度\r\n * @param {boolean} [options.autoStop] 是否自动停止\r\n * @param {number} [options.autoStopAngle] 自动停止的角度值(0-360度),未设置时不自动停止\r\n * @param {object} [options.point] 绕点旋转对应的中心点位置\r\n */\r\nexport class PointRotate extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n if (this.options.center) {\r\n this._map.setCameraView(this.options.center, { duration: 0 })\r\n }\r\n\r\n if (this.options.autoStop) {\r\n delete this.options.autoStopAngle // 是否自动停止\r\n }\r\n\r\n if (this.options.isRotateOut) {\r\n this._rotateOut = new mars3d.thing.RotateOut(this.options)\r\n this._map.addThing(this._rotateOut)\r\n } else {\r\n this._rotatePoint = new mars3d.thing.RotatePoint(this.options)\r\n this._map.addThing(this._rotatePoint)\r\n }\r\n\r\n if (this.options.isRotateOut) {\r\n this._rotateOut.start()\r\n } else {\r\n this._rotatePoint.start(this.options.point)\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._rotatePoint) {\r\n this._rotatePoint.stop()\r\n this._rotatePoint.destroy()\r\n delete this._rotatePoint\r\n }\r\n if (this._rotateOut) {\r\n this._rotateOut.stop()\r\n this._rotateOut.destroy()\r\n delete this._rotateOut\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"pointRotate\", PointRotate)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 按路线漫游\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {object} [options.route] FixedRoute对应的构造参数\r\n */\r\nexport class RouteLine extends mars3d.TaskItem {\r\n // constructor(options) {\r\n // super(options)\r\n // }\r\n\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._graphicLayer = new mars3d.layer.GraphicLayer()\r\n this._map.addLayer(this._graphicLayer)\r\n\r\n const fixedRoute = new mars3d.graphic.FixedRoute(this.options.route)\r\n this._graphicLayer.addGraphic(fixedRoute)\r\n this._fixedRoute = fixedRoute\r\n\r\n fixedRoute.start()\r\n }\r\n\r\n // 暂停(非必须)\r\n _pauseWork(options) {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.pause()\r\n }\r\n }\r\n\r\n // 继续(非必须)\r\n _proceedWork() {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.proceed()\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._fixedRoute) {\r\n this._fixedRoute.stop()\r\n delete this._fixedRoute\r\n }\r\n\r\n if (this._graphicLayer) {\r\n this._graphicLayer.destroy()\r\n delete this._graphicLayer\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"routeLine\", RouteLine)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 放大地图\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {number} [options.relativeAmount=2] 相对量\r\n */\r\nexport class ZoomIn extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.zoomIn(this.options.relativeAmount)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"zoomIn\", ZoomIn)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 缩小地图\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {number} [options.relativeAmount=2] 相对量\r\n */\r\nexport class ZoomOut extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n this._map.zoomOut(this.options.relativeAmount)\r\n }\r\n}\r\nmars3d.thing.Task.register(\"zoomOut\", ZoomOut)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n/**\r\n * 矢量对象高亮闪烁(仅Entity)\r\n *\r\n * @param {object} [options] 参数对象,包括以下:\r\n * @param {string} [options.name] 标题名称\r\n * @param {string} [options.type] 类型标识,自动赋值的,无需手动传入\r\n * @param {number} [options.start] 开始时间,相当于map.clock.startTime的秒数\r\n * @param {number} [options.duration] 时长\r\n *\r\n * @param {string|number} [options.layerId] 图层ID\r\n * @param {string|number} [options.graphicId] 矢量对象ID\r\n *\r\n * @param {number} [options.step=10] 闪烁增量, 控制速度\r\n * @param {string} [options.color] 高亮的颜色\r\n * @param {number} [options.maxAlpha=0.3] 闪烁的最大透明度,从 0 到 maxAlpha 渐变\r\n */\r\nexport class FlickerEntity extends mars3d.TaskItem {\r\n // 进入,激活开始处理事务\r\n _activateWork() {\r\n const layer = this._map.getLayerById(this.options.layerId)\r\n if (layer) {\r\n layer.show = true\r\n layer.readyPromise.then(() => {\r\n this._graphic = layer.getGraphicById(this.options.graphicId)\r\n if (this._graphic) {\r\n this._graphic.show = true\r\n this._graphic.startFlicker({\r\n time: this._duration,\r\n step: this.options.step,\r\n maxAlpha: this.options.maxAlpha,\r\n color: this.options.color\r\n })\r\n }\r\n })\r\n }\r\n }\r\n\r\n // 离开,释放相关对象\r\n _disableWork() {\r\n if (this._graphic) {\r\n this._graphic.stopFlicker()\r\n }\r\n }\r\n}\r\nmars3d.thing.Task.register(\"flickerEntity\", FlickerEntity)\r\n","import * as mars3d from \"mars3d\"\r\n\r\n// 通过Canvas绘制复杂或动态对象的图标点Graphic\r\nexport class CanvasBillboard extends mars3d.graphic.BillboardPrimitive {\r\n /**\r\n * 文字\r\n * @type {string}\r\n */\r\n get text() {\r\n return this.style.text\r\n }\r\n\r\n set text(val) {\r\n this.style.text = val\r\n\r\n this.label.text = val\r\n }\r\n\r\n /**\r\n * 对象添加到图层前创建一些对象的钩子方法,\r\n * 只会调用一次\r\n * @return {Promise<object>} 无\r\n * @private\r\n */\r\n _addedHook(style) {\r\n style.image = \"//data.mars3d.cn/img/marker/bg/textPnl.png\"\r\n style.label = {\r\n ...style,\r\n text: this.style.text,\r\n font_size: 55,\r\n color: style.textColor ?? \"#ffffff\",\r\n hasPixelOffset: true,\r\n pixelOffsetX: 0,\r\n pixelOffsetY: -36 * (style.scale ?? 1)\r\n }\r\n if (style.scaleByDistance) {\r\n style.label.pixelOffsetScaleByDistance = style.scaleByDistance\r\n }\r\n\r\n super._addedHook(style)\r\n }\r\n}\r\n\r\n// 注册下\r\nmars3d.GraphicUtil.register(\"canvasBillboard\", CanvasBillboard)\r\n","<!--\r\n 地图渲染组件\r\n-->\r\n\r\n<template>\r\n <div :id=\"withKeyId\" class=\"mars3d-container\"></div>\r\n</template>\r\n<script setup lang=\"ts\">\r\nimport * as mars3d from \"mars3d\";\r\nimport \"./expand/index\"; // 引入插件或注册扩展js\r\n\r\nimport { computed, onUnmounted, onMounted, toRaw } from \"vue\";\r\n// import { $alert, $message } from \"@mars/components/mars-ui/index\"\r\n\r\nconst props = withDefaults(\r\n defineProps<{\r\n mapKey?: string; // 多个地图时,可传入key区分地图\r\n url?: string; // 传入的地图构造参数url,可为空,只传options\r\n options?: any; // 传入的地图构造参数options,可覆盖url内的参数\r\n }>(),\r\n {\r\n mapKey: \"default\",\r\n url: undefined,\r\n options: undefined,\r\n },\r\n);\r\n\r\n// 用于存放地球组件实例\r\nlet map: mars3d.Map; // 地图对象\r\n\r\n// 使用用户传入的 mapKey 拼接生成 withKeyId 作为当前显示容器的id\r\nconst withKeyId = computed(() => `mars3d-container-${props.mapKey}`);\r\n\r\n// onload事件将在地图渲染后触发\r\nconst emit = defineEmits([\"onload\"]);\r\n\r\nconst initMars3d = async () => {\r\n // 获取配置\r\n let mapOptions;\r\n if (props.url) {\r\n // 存在url时才读取\r\n mapOptions = await mars3d.Util.fetchJson({ url: props.url });\r\n if (props.options) {\r\n mapOptions = mars3d.Util.merge(mapOptions, toRaw(props.options)); // 合并配置\r\n }\r\n } else if (props.options) {\r\n mapOptions = toRaw(props.options);\r\n }\r\n // console.log(\"Map地图构造参数\", mapOptions);\r\n\r\n // 禁用控制台版权信息输出\r\n (mars3d as any).Util.showCopyright = false;\r\n\r\n map = new mars3d.Map(withKeyId.value, mapOptions);\r\n\r\n // 针对不同终端的优化配置\r\n if (mars3d.Util.isPCBroswer()) {\r\n map.zoomFactor = 2.0; // 鼠标滚轮放大的步长参数\r\n\r\n // IE浏览器优化\r\n if (window.navigator.userAgent.toLowerCase().indexOf(\"msie\") >= 0) {\r\n map.viewer.targetFrameRate = 20; // 限制帧率\r\n map.scene.requestRenderMode = false; // 取消实时渲染\r\n }\r\n } else {\r\n map.zoomFactor = 5.0; // 鼠标滚轮放大的步长参数\r\n\r\n // 移动设备上禁掉以下几个选项,可以相对更加流畅\r\n map.scene.requestRenderMode = false; // 取消实时渲染\r\n map.scene.fog.enabled = false;\r\n map.scene.skyAtmosphere.show = false;\r\n map.scene.globe.showGroundAtmosphere = false;\r\n }\r\n\r\n // 二三维切换不用动画\r\n if (map.viewer.sceneModePicker) {\r\n map.viewer.sceneModePicker.viewModel.duration = 0.0;\r\n }\r\n\r\n // 绑定当前项目的默认右键菜单\r\n // map.bindContextMenu(getContextMenu())\r\n\r\n // 隐藏右下角的Mars3D logo\r\n if ((map as any).mars3dLogo) {\r\n (map as any).mars3dLogo.show = false;\r\n }\r\n // 强制从DOM中移除logo元素\r\n setTimeout(() => {\r\n const logoElements = document.getElementsByClassName(\"mars3d-logo\");\r\n for (let i = 0; i < logoElements.length; i++) {\r\n logoElements[i].remove();\r\n }\r\n }, 100);\r\n\r\n // webgl渲染失败后,刷新页面\r\n // map.on(mars3d.EventType.renderError, async () => {\r\n // await $alert(\"程序内存消耗过大,请重启浏览器\")\r\n // window.location.reload()\r\n // })\r\n\r\n onMapLoad(); // map构造完成后的一些处理\r\n emit(\"onload\", map);\r\n};\r\n\r\n// map构造完成后的一些处理,可以按需注释和选用\r\nfunction onMapLoad() {\r\n // Mars3D地图内部使用,如右键菜单弹窗\r\n // @ts-ignore\r\n // window.globalAlert = $alert;\r\n // // @ts-ignore\r\n // window.globalMsg = $message;\r\n}\r\n\r\nonMounted(() => {\r\n initMars3d();\r\n});\r\n// 组件卸载之前销毁mars3d实例\r\nonUnmounted(() => {\r\n if (map) {\r\n map.destroy();\r\n map = null;\r\n }\r\n // console.log(\"map销毁完成\", map);\r\n});\r\n</script>\r\n\r\n<style lang=\"less\">\r\n/**cesium 工具按钮栏*/\r\n.cesium-viewer-toolbar {\r\n top: auto !important;\r\n bottom: 35px !important;\r\n left: 12px !important;\r\n right: auto !important;\r\n}\r\n\r\n.cesium-toolbar-button img {\r\n width: 22px;\r\n height: 100%;\r\n}\r\n.cesium-toolbar-button:hover img {\r\n width: 28px;\r\n}\r\n.cesium-svgPath-svg {\r\n scale: 0.8;\r\n}\r\n.cesium-svgPath-svg:hover {\r\n scale: 1;\r\n}\r\n.cesium-button .cesium-baseLayerPicker-selected {\r\n width: 100%;\r\n}\r\n\r\n.cesium-button:hover .cesium-baseLayerPicker-selected {\r\n width: 100%;\r\n}\r\n\r\n.cesium-viewer-toolbar > .cesium-toolbar-button,\r\n.cesium-navigationHelpButton-wrapper,\r\n.cesium-viewer-geocoderContainer {\r\n margin-bottom: 5px;\r\n float: left;\r\n clear: both;\r\n text-align: center;\r\n}\r\n\r\n.cesium-viewer-geocoderContainer form .cesium-geocoder-input {\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n}\r\n\r\n.cesium-button {\r\n background-color: rgba(39, 44, 54, 0.8);\r\n\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n\r\n color: #ffffff;\r\n fill: #e6e6e6;\r\n line-height: 38px;\r\n}\r\n\r\n.cesium-button:hover {\r\n background-color: rgba(51, 133, 255, 1);\r\n box-shadow: none;\r\n border: none;\r\n}\r\n\r\n/**cesium 底图切换面板*/\r\n.cesium-baseLayerPicker-dropDown {\r\n bottom: 0;\r\n left: 40px;\r\n max-height: 700px;\r\n margin-bottom: 5px;\r\n background-color: rgba(23, 49, 71, 0.7);\r\n}\r\n\r\n/**cesium 帮助面板*/\r\n.cesium-navigation-help {\r\n top: auto;\r\n bottom: 0;\r\n left: 40px;\r\n transform-origin: left bottom;\r\n background: none;\r\n background-color: rgba(23, 49, 71, 0.8);\r\n\r\n .cesium-navigation-help-instructions,\r\n .cesium-navigation-button {\r\n background: none;\r\n }\r\n\r\n .cesium-navigation-button-selected,\r\n .cesium-navigation-button-unselected:hover {\r\n background-color: rgba(1, 35, 22, 1);\r\n }\r\n}\r\n\r\n/**cesium 二维三维切换*/\r\n.cesium-sceneModePicker-wrapper {\r\n width: auto;\r\n}\r\n\r\n.cesium-sceneModePicker-wrapper .cesium-sceneModePicker-dropDown-icon {\r\n float: right;\r\n margin: 0 3px;\r\n}\r\n\r\n/**cesium POI查询输入框*/\r\n.cesium-viewer-geocoderContainer .search-results {\r\n left: 0;\r\n right: 40px;\r\n width: auto;\r\n z-index: 9999;\r\n}\r\n\r\n.cesium-geocoder-searchButton {\r\n width: 38px;\r\n height: 38px;\r\n background-color: rgba(39, 44, 54, 0.8);\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n fill: #e6e6e6;\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .cesium-geocoder-input {\r\n height: 40px;\r\n width: 40px;\r\n background-color: rgba(63, 72, 84, 0.7);\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .cesium-geocoder-input:focus {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.cesium-viewer-geocoderContainer .search-results {\r\n background-color: rgba(23, 49, 71, 0.8);\r\n}\r\n\r\n/**cesium info信息框*/\r\n.cesium-infoBox {\r\n top: 50px;\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.cesium-infoBox-title {\r\n background-color: rgba(23, 49, 71, 0.8);\r\n}\r\n\r\n/**cesium 任务栏的FPS信息*/\r\n.cesium-performanceDisplay-defaultContainer {\r\n top: auto;\r\n bottom: 35px;\r\n right: 50px;\r\n}\r\n\r\n.cesium-performanceDisplay-ms,\r\n.cesium-performanceDisplay-fps {\r\n color: #fff;\r\n}\r\n\r\n/**cesium tileset调试信息面板*/\r\n.cesium-viewer-cesiumInspectorContainer {\r\n top: 10px;\r\n left: 10px;\r\n right: auto;\r\n}\r\n\r\n.cesium-cesiumInspector {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n/**覆盖mars3d内部控件的颜色等样式*/\r\n.mars3d-compass .mars3d-compass-outer {\r\n fill: rgba(39, 44, 54, 0.8);\r\n}\r\n.mars3d-compass .mars3d-compass-inner {\r\n background: rgba(39, 44, 54, 0.8);\r\n fill: #fff;\r\n}\r\n\r\n.mars3d-contextmenu-ul,\r\n.mars3d-sub-menu {\r\n background-color: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n.mars3d-contextmenu-ul {\r\n border-radius: 2px;\r\n border-width: 1px;\r\n border-image: url(\"//data.mars3d.cn/img/control/border.svg\") 1 round stretch;\r\n}\r\n\r\n.mars3d-contextmenu-ul > li > a:hover,\r\n.mars3d-sub-menu > li > a:hover,\r\n.mars3d-contextmenu-ul > li > a:focus,\r\n.mars3d-sub-menu > li > a:focus,\r\n.mars3d-contextmenu-ul > li > .active,\r\n.mars3d-sub-menu > li > .active {\r\n background-color: var(--mars-hover-color, #3ea6ff);\r\n}\r\n\r\n.mars3d-contextmenu-ul > .active > a,\r\n.mars3d-sub-menu > .active > a,\r\n.mars3d-contextmenu-ul > .active > a:hover,\r\n.mars3d-sub-menu > .active > a:hover,\r\n.mars3d-contextmenu-ul > .active > a:focus,\r\n.mars3d-sub-menu > .active > a:focus {\r\n background-color: var(--mars-hover-color, #3ea6ff);\r\n}\r\n\r\n/* Popup样式*/\r\n.mars3d-popup-color {\r\n color: var(--mars-text-color, #ffffff);\r\n}\r\n\r\n.mars3d-popup-background {\r\n // background: none会导致剖面的popup没有颜色\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n// .mars3d-popup-content-wrapper {\r\n// box-shadow: none !important;\r\n// padding: 0 !important;\r\n// background: var(--mars-base-border) !important;\r\n// border-radius: 4px;\r\n// }\r\n\r\n.mars3d-popup-content {\r\n margin: 15px;\r\n}\r\n.mars3d-popup-btn-custom {\r\n padding: 3px 10px;\r\n border: 1px solid #209ffd;\r\n background: #209ffd1c;\r\n color: var(--mars-text-color);\r\n}\r\n\r\n.mars3d-tooltip {\r\n color: var(--mars-text-color, #ffffff);\r\n background: var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n border: 1px solid var(--mars-base-bg, rgba(63, 72, 84, 0.9));\r\n}\r\n\r\n.mars3d-tooltip-top:before {\r\n border-top-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-bottom:before {\r\n border-bottom-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-left:before {\r\n border-left-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n\r\n.mars3d-tooltip-right:before {\r\n border-right-color: var(--mars-bg-base, rgba(23, 49, 71, 0.8));\r\n}\r\n.mars3d-template-content label {\r\n padding-right: 6px;\r\n}\r\n\r\n/* all 中的html样式 */\r\n.mars3d-template-titile {\r\n height: 33px;\r\n line-height: 33px;\r\n padding-left: 10px;\r\n border-radius: 4px 4px 0px 0px;\r\n box-shadow:\r\n 0px 6px 12px -2px rgba(50, 50, 93, 0.15),\r\n 0px 3px 7px -3px rgba(0, 0, 0, 0.2);\r\n color: var(--mars-control-text) !important;\r\n background: var(--mars-msg-title-bg);\r\n font-family: var(--mars-font-family);\r\n\r\n a {\r\n font-size: 16px;\r\n color: var(--mars-msg-title-color, #479be0);\r\n text-decoration: none;\r\n }\r\n}\r\n\r\n.mars3d-template-content {\r\n margin-top: 0 !important;\r\n background-color: var(--mars-dropdown-bg);\r\n padding: 10px;\r\n color: #eaf2ff;\r\n\r\n label {\r\n padding-right: 6px;\r\n }\r\n\r\n input {\r\n color: var(--mars-text-color);\r\n background-color: transparent !important;\r\n padding: 4px 5px;\r\n }\r\n\r\n input::placeholder {\r\n color: #cdcdcd !important;\r\n }\r\n\r\n textarea {\r\n color: var(--mars-base-color);\r\n background-color: transparent !important;\r\n padding: 4px 5px;\r\n }\r\n\r\n textarea::placeholder {\r\n color: #cdcdcd !important;\r\n }\r\n}\r\n\r\n.mars3d-popup-btn-custom {\r\n padding: 3px 10px;\r\n border: 1px solid #209ffd;\r\n background: #209ffd1c;\r\n color: var(--mars-text-color, #ffffff);\r\n}\r\n\r\n.mars3d-popup-content {\r\n margin: 15px;\r\n}\r\n\r\n.mars3d-divGraphic:hover {\r\n z-index: 999 !important;\r\n}\r\n\r\n/* 隐藏Mars3D logo */\r\n.mars3d-logo {\r\n display: none !important;\r\n visibility: hidden !important;\r\n opacity: 0 !important;\r\n pointer-events: none;\r\n}\r\n</style>\r\n","<!--\r\n ToolbarPanel — 测量 & 绘制工具栏\r\n\r\n 改进点(相对原 RightPanel):\r\n - 测量与绘制合并为统一工具栏,去掉冗余的 selectedGraphic 等未使用 prop\r\n - 新增激活态高亮(activeDrawType prop)\r\n - 图标语义更准确(使用 title 提示用户功能)\r\n-->\r\n<template>\r\n <div class=\"toolbar-panel\" :class=\"{ collapsed: isCollapsed }\">\r\n <!-- 收起/展开 header -->\r\n <div class=\"panel-header\" @click=\"toggleCollapse\">\r\n <i\r\n :class=\"[\r\n 'toggle-icon',\r\n 'fa',\r\n isCollapsed ? 'fa-chevron-down' : 'fa-chevron-up',\r\n ]\"\r\n />\r\n </div>\r\n\r\n <div class=\"panel-content\" v-show=\"!isCollapsed\">\r\n <!-- 测量工具组 -->\r\n <div class=\"menu-group\">\r\n <div\r\n v-for=\"item in measureTools\"\r\n :key=\"item.tool\"\r\n class=\"menu-item\"\r\n :title=\"item.title\"\r\n @click=\"activateTool(item.tool)\"\r\n >\r\n <i :class=\"item.iconClasses\" />\r\n </div>\r\n </div>\r\n\r\n <div class=\"divider\" />\r\n\r\n <!-- 绘制工具组 -->\r\n <div class=\"menu-group\">\r\n <div\r\n v-for=\"item in drawTools\"\r\n :key=\"item.tool\"\r\n class=\"menu-item\"\r\n :class=\"{ active: activeDrawType === item.drawType }\"\r\n :title=\"item.title\"\r\n @click=\"activateTool(item.tool)\"\r\n >\r\n <i :class=\"item.iconClasses\" />\r\n </div>\r\n <div class=\"divider\" />\r\n <!-- 清除按钮 -->\r\n <div class=\"menu-item\" title=\"清除全部\" @click=\"emitClear\">\r\n <i class=\"fa-solid fa-trash-can\" />\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\n\r\n// ─── Props ───────────────────────────────────────────────────────────────────\r\ndefineProps<{\r\n activeDrawType?: string | null;\r\n}>();\r\n\r\n// ─── Emits ───────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n toolActivate: [tool: string];\r\n clear: [];\r\n}>();\r\n\r\n// ─── State ───────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(false);\r\n\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\nconst activateTool = (tool: string) => {\r\n emit(\"toolActivate\", tool);\r\n};\r\nconst emitClear = () => {\r\n emit(\"clear\");\r\n};\r\n\r\n// ─── 工具配置 ─────────────────────────────────────────────────────────────────\r\ninterface ToolItem {\r\n tool: string;\r\n title: string;\r\n iconClasses: string[];\r\n drawType?: string;\r\n}\r\n\r\nconst measureTools: ToolItem[] = [\r\n {\r\n tool: \"measureDistance\",\r\n title: \"测量距离\",\r\n iconClasses: [\"fa\", \"fa-arrows-alt-h\"], // 水平双向箭头,更准确表达距离\r\n },\r\n {\r\n tool: \"measureArea\",\r\n title: \"测量面积\",\r\n iconClasses: [\"fa\", \"fa-vector-square\"], // 矢量方块,更几何感、专业感\r\n },\r\n {\r\n tool: \"measureHeight\",\r\n title: \"测量高度差\",\r\n iconClasses: [\"fa\", \"fa-arrows-alt-v\"], // 垂直双向箭头,清晰表达高度\r\n },\r\n {\r\n tool: \"measureAngle\",\r\n title: \"测量角度\",\r\n iconClasses: [\"fa-solid\", \"fa-compass-drafting\"], // 绘图圆规图标,专业表达角度测量\r\n },\r\n];\r\n\r\nconst drawTools: ToolItem[] = [\r\n {\r\n tool: \"drawPoint\",\r\n title: \"点标记\",\r\n iconClasses: [\"fa\", \"fa-map-marker\"], // 地图标记点,比空心圆更直观\r\n drawType: \"point\",\r\n },\r\n {\r\n tool: \"drawLine\",\r\n title: \"线标记\",\r\n iconClasses: [\"fa\", \"fa-slash\"], // 斜线比短横线更像\"线\"的概念\r\n drawType: \"polyline\",\r\n },\r\n {\r\n tool: \"drawPolygon\",\r\n title: \"面标记\",\r\n iconClasses: [\"fa-solid\", \"fa-draw-polygon\"], // 多边形绘制图标,语义明确\r\n drawType: \"polygon\",\r\n },\r\n {\r\n tool: \"drawCircle\",\r\n title: \"圆标记\",\r\n iconClasses: [\"fa\", \"fa-circle\"], // 实心圆表示圆\r\n drawType: \"circle\",\r\n },\r\n {\r\n tool: \"drawRectangle\",\r\n title: \"矩形标记\",\r\n iconClasses: [\"fa-regular\", \"fa-square\"], // 空心方块,与圆标记风格统一\r\n drawType: \"rectangle\",\r\n },\r\n {\r\n tool: \"drawFreePolygon\",\r\n title: \"自由多边形\",\r\n iconClasses: [\"fa\", \"fa-pencil\"], // 铅笔表示自由绘制\r\n drawType: \"freePolygon\",\r\n },\r\n];\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n.toolbar-panel {\r\n position: absolute;\r\n top: 10px;\r\n right: 0;\r\n width: 42px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px 0 0 6px;\r\n border-right: none;\r\n z-index: 999;\r\n transition: max-height 0.3s ease;\r\n max-height: calc(100vh - 120px);\r\n overflow-y: auto;\r\n backdrop-filter: blur(4px);\r\n\r\n &.collapsed {\r\n max-height: 38px;\r\n .panel-content {\r\n display: none;\r\n }\r\n .panel-header {\r\n padding: 8px;\r\n justify-content: center;\r\n border-radius: 6px 0 0 6px;\r\n }\r\n }\r\n\r\n .panel-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 8px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 0 0 0;\r\n cursor: pointer;\r\n user-select: none;\r\n\r\n .toggle-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n transition: all 0.3s ease;\r\n }\r\n\r\n &:hover .toggle-icon {\r\n color: #3ea6ff;\r\n }\r\n }\r\n\r\n .panel-content {\r\n padding: 6px 0;\r\n }\r\n\r\n .menu-group {\r\n display: flex;\r\n flex-direction: column;\r\n gap: 2px;\r\n }\r\n\r\n .menu-item {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 8px;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n border-radius: 3px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n\r\n &.active {\r\n background: rgba(62, 166, 255, 0.4);\r\n color: #fff;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n i {\r\n font-size: 14px;\r\n line-height: 1;\r\n }\r\n }\r\n\r\n .divider {\r\n height: 1px;\r\n background: rgba(255, 255, 255, 0.08);\r\n margin: 6px 8px;\r\n }\r\n\r\n &::-webkit-scrollbar {\r\n width: 3px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n</style>\r\n","<!--\r\n VisionPanel — 视角控制面板\r\n\r\n 职责:\r\n - 右下角悬浮按钮 + 弹出浮层\r\n - 四个功能:环绕飞行 / 移动到此处 / 第一视角 / 键盘漫游\r\n - 激活态通过 prop 传入,不在此处维护逻辑\r\n-->\r\n<template>\r\n <!-- 触发按钮 -->\r\n <div class=\"vision-button\" title=\"视觉功能\" @click=\"togglePopup\">\r\n <i class=\"fa fa-eye\" />\r\n </div>\r\n\r\n <!-- 弹出面板 -->\r\n <Transition name=\"vision-fade\">\r\n <div v-if=\"popupVisible\" class=\"vision-popup\">\r\n <div class=\"popup-header\">\r\n <span>视觉功能</span>\r\n <i class=\"fa fa-times close-icon\" @click=\"popupVisible = false\" />\r\n </div>\r\n <div class=\"popup-content\">\r\n <div\r\n v-for=\"item in visionItems\"\r\n :key=\"item.action\"\r\n class=\"popup-item\"\r\n :class=\"{ active: isActive(item) }\"\r\n @click=\"execute(item.action)\"\r\n >\r\n <i :class=\"['fa', item.icon]\" />\r\n <span>{{ getLabel(item) }}</span>\r\n </div>\r\n </div>\r\n </div>\r\n </Transition>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref } from \"vue\";\r\n\r\n// ─── Props ───────────────────────────────────────────────────────────────────\r\nconst props = defineProps<{\r\n circleFlyActive?: boolean;\r\n flyToActive?: boolean;\r\n firstPersonActive?: boolean;\r\n keyboardNavigateActive?: boolean;\r\n}>();\r\n\r\n// ─── Emits ───────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n visionExecute: [action: string];\r\n}>();\r\n\r\n// ─── State ───────────────────────────────────────────────────────────────────\r\nconst popupVisible = ref(false);\r\nconst togglePopup = () => { popupVisible.value = !popupVisible.value; };\r\nconst execute = (action: string) => { emit(\"visionExecute\", action); };\r\n\r\n// ─── 功能配置表 ───────────────────────────────────────────────────────────────\r\ninterface VisionItem {\r\n action: string;\r\n icon: string;\r\n label: string;\r\n activeLabel?: string;\r\n activeProp?: keyof typeof props;\r\n}\r\n\r\nconst visionItems: VisionItem[] = [\r\n {\r\n action: \"circleFly\",\r\n icon: \"fa-refresh\",\r\n label: \"环绕飞行\",\r\n activeLabel: \"关闭环绕飞行\",\r\n activeProp: \"circleFlyActive\",\r\n },\r\n {\r\n action: \"flyTo\",\r\n icon: \"fa-location-arrow\",\r\n label: \"移动到此处\",\r\n activeProp: \"flyToActive\",\r\n },\r\n {\r\n action: \"firstPerson\",\r\n icon: \"fa-user\",\r\n label: \"开启第一视角\",\r\n activeLabel: \"关闭第一视角\",\r\n activeProp: \"firstPersonActive\",\r\n },\r\n {\r\n action: \"keyboardNavigate\",\r\n icon: \"fa-keyboard-o\",\r\n label: \"开启键盘漫游\",\r\n activeLabel: \"关闭键盘漫游\",\r\n activeProp: \"keyboardNavigateActive\",\r\n },\r\n];\r\n\r\nconst isActive = (item: VisionItem) =>\r\n item.activeProp ? !!props[item.activeProp] : false;\r\n\r\nconst getLabel = (item: VisionItem) =>\r\n isActive(item) && item.activeLabel ? item.activeLabel : item.label;\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n.vision-button {\r\n position: absolute;\r\n bottom: 80px;\r\n right: 0;\r\n width: 42px;\r\n height: 42px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border-radius: 6px 0 0 6px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-right: none;\r\n z-index: 999;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n backdrop-filter: blur(4px);\r\n transition: all 0.2s ease;\r\n\r\n &:hover { \r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n i { font-size: 14px; }\r\n}\r\n\r\n.vision-popup {\r\n position: absolute;\r\n bottom: 80px;\r\n right: 48px;\r\n width: 170px;\r\n background: rgba(23, 35, 50, 0.92);\r\n border-radius: 6px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n backdrop-filter: blur(4px);\r\n z-index: 998;\r\n\r\n .popup-header {\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 8px 12px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 5px 5px 0 0;\r\n\r\n span { color: #e8f4ff; font-size: 13px; font-weight: 600; }\r\n\r\n .close-icon {\r\n color: #7a9ec0;\r\n font-size: 14px;\r\n cursor: pointer;\r\n transition: color 0.2s ease;\r\n &:hover { color: #3ea6ff; }\r\n }\r\n }\r\n\r\n .popup-content { padding: 6px 0; }\r\n\r\n .popup-item {\r\n display: flex;\r\n align-items: center;\r\n padding: 8px 12px;\r\n color: #e8f4ff;\r\n cursor: pointer;\r\n transition: all 0.2s ease;\r\n border-radius: 3px;\r\n margin: 0 4px;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &.active { \r\n background: rgba(62, 166, 255, 0.4);\r\n color: #fff;\r\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.2);\r\n }\r\n\r\n i { margin-right: 10px; width: 16px; text-align: center; font-size: 14px; }\r\n span { font-size: 12px; }\r\n }\r\n}\r\n\r\n// 过渡动画\r\n.vision-fade-enter-active,\r\n.vision-fade-leave-active {\r\n transition: opacity 0.25s ease, transform 0.25s ease;\r\n}\r\n.vision-fade-enter-from,\r\n.vision-fade-leave-to {\r\n opacity: 0;\r\n transform: translateX(15px);\r\n}\r\n</style>\r\n","/**\r\n * useMap — 地图核心 composable\r\n *\r\n * 职责:\r\n * - 持有 mars3d.Map 实例\r\n * - 管理业务 GraphicLayer(绘图层)和 measureLayer(测量层)\r\n * - 暴露地图事件回调(点击坐标记录)\r\n * - 提供统一的图层/thing 注册接口,方便后续业务扩展\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\n\r\n// 使用 any 避免 Mars3D 类型定义过深导致的 TS 推断溢出\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\ntype AnyShallowRef<T> = { readonly value: T | null };\r\n\r\nexport function useMap() {\r\n const Cesium = mars3d.Cesium;\r\n\r\n // ─── 地图实例(shallowRef 避免深响应代理 Cesium 对象) ───────────────\r\n const mapRef = shallowRef<mars3d.Map | null>(null);\r\n\r\n // ─── 核心图层 ─────────────────────────────────────────────────────────\r\n const graphicLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n const measureLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── 选中图形 ─────────────────────────────────────────────────────────\r\n const selectedGraphic = ref<any>(null);\r\n\r\n // ─── 最后点击位置(视角跳转等功能共享) ──────────────────────────────\r\n const lastClickPosition = ref<{ lng: number; lat: number; alt: number } | null>(null);\r\n\r\n /**\r\n * 在地图加载完毕后调用,完成图层、事件的初始化\r\n */\r\n function initMap(map: mars3d.Map) {\r\n mapRef.value = map;\r\n\r\n // 业务绘图层\r\n const gLayer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(gLayer);\r\n graphicLayer.value = gLayer;\r\n\r\n // 测量专用图层\r\n const mLayer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(mLayer);\r\n measureLayer.value = mLayer;\r\n\r\n // ── 地图点击:记录坐标 ──────────────────────────────────────────\r\n map.on(mars3d.EventType.click, (event: any) => {\r\n if (event.lnglat) {\r\n lastClickPosition.value = event.lnglat;\r\n } else if (event.cartesian) {\r\n const carto = Cesium.Ellipsoid.WGS84.cartesianToCartographic(event.cartesian);\r\n lastClickPosition.value = {\r\n lng: Cesium.Math.toDegrees(carto.longitude),\r\n lat: Cesium.Math.toDegrees(carto.latitude),\r\n alt: carto.height > 0 ? carto.height : 5000,\r\n };\r\n }\r\n });\r\n\r\n // ── 图形层交互事件 ────────────────────────────────────────────────\r\n gLayer.on(mars3d.EventType.click, (event: any) => {\r\n selectedGraphic.value = event.graphic;\r\n });\r\n gLayer.on(mars3d.EventType.mouseOver, (event: any) => {\r\n if (!selectedGraphic.value) {\r\n selectedGraphic.value = event.graphic;\r\n }\r\n });\r\n gLayer.on(mars3d.EventType.mouseOut, (event: any) => {\r\n if (selectedGraphic.value === event.graphic) {\r\n selectedGraphic.value = null;\r\n }\r\n });\r\n }\r\n\r\n /**\r\n * 销毁地图(组件卸载时调用)\r\n */\r\n function destroyMap() {\r\n if (mapRef.value) {\r\n mapRef.value.destroy();\r\n mapRef.value = null;\r\n }\r\n }\r\n\r\n /**\r\n * 便捷方法:向业务图层添加 Graphic\r\n */\r\n function addGraphic(graphic: any) {\r\n graphicLayer.value?.addGraphic(graphic);\r\n }\r\n\r\n /**\r\n * 向地图添加自定义 Thing(供业务扩展)\r\n */\r\n function addThing(thing: any) {\r\n mapRef.value?.addThing(thing);\r\n }\r\n\r\n return {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n map: mapRef as AnyShallowRef<any>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n graphicLayer: graphicLayer as AnyShallowRef<any>,\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n measureLayer: measureLayer as AnyShallowRef<any>,\r\n selectedGraphic,\r\n lastClickPosition,\r\n initMap,\r\n destroyMap,\r\n addGraphic,\r\n addThing,\r\n };\r\n}\r\n\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport type UseMapReturn = ReturnType<typeof useMap>;\r\n","/**\r\n * useMeasure — 测量工具 composable\r\n *\r\n * 职责:\r\n * - 封装 mars3d.thing.Measure 的生命周期\r\n * - 提供 距离 / 面积 / 高度差 / 角度 四种测量方法\r\n * - 提供 clear 清除方法\r\n *\r\n * 依赖:useMap 返回的 map 与 measureLayer\r\n */\r\nimport { shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\nexport function useMeasure(mapContext: UseMapReturn) {\r\n const measureThing = shallowRef<mars3d.thing.Measure | null>(null);\r\n\r\n /** 在地图初始化后调用,注册 Measure thing */\r\n function initMeasure() {\r\n const map = mapContext.map.value;\r\n const layer = mapContext.measureLayer.value;\r\n if (!map || !layer) return;\r\n\r\n const m = new mars3d.thing.Measure({ graphicLayer: layer } as any);\r\n map.addThing(m);\r\n measureThing.value = m;\r\n }\r\n\r\n /** 测量距离 */\r\n function measureDistance(style?: Record<string, any>) {\r\n measureThing.value?.distance({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 测量面积 */\r\n function measureArea(style?: Record<string, any>) {\r\n measureThing.value?.area({\r\n style: { color: \"#3388ff\", opacity: 0.5, ...style },\r\n });\r\n }\r\n\r\n /** 测量高度差 */\r\n function measureHeight(style?: Record<string, any>) {\r\n measureThing.value?.height({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 测量角度 */\r\n function measureAngle(style?: Record<string, any>) {\r\n measureThing.value?.angle({\r\n style: { color: \"#3388ff\", width: 3, ...style },\r\n });\r\n }\r\n\r\n /** 清除所有测量结果 */\r\n function clearMeasure() {\r\n measureThing.value?.clear();\r\n mapContext.measureLayer.value?.clear();\r\n }\r\n\r\n return {\r\n measureThing,\r\n initMeasure,\r\n measureDistance,\r\n measureArea,\r\n measureHeight,\r\n measureAngle,\r\n clearMeasure,\r\n };\r\n}\r\n","/**\r\n * useDraw — 绘制工具 composable\r\n *\r\n * 职责:\r\n * - 封装六种图形绘制(点/线/面/圆/矩形/自由多边形)\r\n * - 统一管理 currentDraw 引用,保证绘制互斥\r\n * - 提供 stopDraw / clearDraw 方法\r\n *\r\n * 依赖:useMap 返回的 measureLayer(绘图结果复用测量层,也可传独立图层)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\n/** 支持的绘制类型枚举,方便外部类型提示 */\r\nexport type DrawType = \"point\" | \"polyline\" | \"polygon\" | \"circle\" | \"rectangle\" | \"freePolygon\";\r\n\r\nexport function useDraw(mapContext: UseMapReturn) {\r\n const currentDraw = shallowRef<any>(null);\r\n /** 当前激活的绘制类型,用于 UI 高亮 */\r\n const activeDrawType = ref<DrawType | null>(null);\r\n\r\n /** 获取绘制目标图层(复用 measureLayer,也可按需传其他层) */\r\n function getLayer() {\r\n return mapContext.measureLayer.value;\r\n }\r\n\r\n /** 内部启动绘制 */\r\n function startDraw(type: string, style: Record<string, any>, drawType: DrawType) {\r\n const layer = getLayer();\r\n if (!layer) return;\r\n stopDraw(); // 先停止上一次未完成的绘制\r\n currentDraw.value = layer.startDraw({ type, style });\r\n activeDrawType.value = drawType;\r\n }\r\n\r\n /** 绘制点 */\r\n function drawPoint(style?: Record<string, any>) {\r\n startDraw(\"point\", { pixelSize: 10, color: \"#ff0000\", ...style }, \"point\");\r\n }\r\n\r\n /** 绘制折线 */\r\n function drawLine(style?: Record<string, any>) {\r\n startDraw(\"polyline\", { width: 3, color: \"#3388ff\", ...style }, \"polyline\");\r\n }\r\n\r\n /** 绘制多边形 */\r\n function drawPolygon(style?: Record<string, any>) {\r\n startDraw(\"polygon\", { color: \"#3388ff\", opacity: 0.5, ...style }, \"polygon\");\r\n }\r\n\r\n /** 绘制圆 */\r\n function drawCircle(style?: Record<string, any>) {\r\n startDraw(\"circle\", { radius: 1000, color: \"#00ff00\", opacity: 0.3, ...style }, \"circle\");\r\n }\r\n\r\n /** 绘制矩形 */\r\n function drawRectangle(style?: Record<string, any>) {\r\n startDraw(\"rectangle\", { color: \"#3388ff\", opacity: 0.5, ...style }, \"rectangle\");\r\n }\r\n\r\n /** 绘制自由多边形(贴地) */\r\n function drawFreePolygon(style?: Record<string, any>) {\r\n startDraw(\r\n \"polygon\",\r\n { color: \"#3388ff\", opacity: 0.5, clampToGround: true, ...style },\r\n \"freePolygon\",\r\n );\r\n }\r\n\r\n /** 停止当前绘制,但保留已绘结果 */\r\n function stopDraw() {\r\n if (currentDraw.value) {\r\n getLayer()?.stopDraw();\r\n currentDraw.value = null;\r\n }\r\n activeDrawType.value = null;\r\n }\r\n\r\n /** 停止并清除所有绘制结果 */\r\n function clearDraw() {\r\n stopDraw();\r\n getLayer()?.clear();\r\n }\r\n\r\n return {\r\n currentDraw,\r\n activeDrawType,\r\n drawPoint,\r\n drawLine,\r\n drawPolygon,\r\n drawCircle,\r\n drawRectangle,\r\n drawFreePolygon,\r\n stopDraw,\r\n clearDraw,\r\n };\r\n}\r\n","/**\r\n * useVision — 视角控制 composable\r\n *\r\n * 职责:\r\n * - 封装环绕飞行(RotatePoint)\r\n * - 封装飞行到指定位置(flyTo / flyHome)\r\n * - 封装第一视角漫游(FirstPersonRoam)\r\n * - 封装键盘漫游(KeyboardRoam)\r\n * - 暴露各功能的激活状态,供 UI 显示切换文案\r\n *\r\n * 依赖:useMap 返回的 map 与 lastClickPosition\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"./useMap\";\r\n\r\nexport function useVision(mapContext: UseMapReturn) {\r\n // ─── 状态 ──────────────────────────────────────────────────────────────\r\n const circleFlyActive = ref(false);\r\n const firstPersonActive = ref(false);\r\n const keyboardActive = ref(false);\r\n const flyToActive = ref(false);\r\n\r\n // ─── Thing 实例 ────────────────────────────────────────────────────────\r\n const rotatePoint = shallowRef<mars3d.thing.RotatePoint | null>(null);\r\n const firstPersonRoam = shallowRef<mars3d.thing.FirstPersonRoam | null>(null);\r\n const keyboardRoam = shallowRef<mars3d.thing.KeyboardRoam | null>(null);\r\n let initialCameraView: any = null;\r\n\r\n /** 获取地图实例(内部简写) */\r\n function getMap() {\r\n return mapContext.map.value;\r\n }\r\n\r\n // ─── 环绕飞行 ──────────────────────────────────────────────────────────\r\n function toggleCircleFly() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (rotatePoint.value) {\r\n if (rotatePoint.value.isStart) {\r\n rotatePoint.value.stop();\r\n }\r\n map.removeThing(rotatePoint.value);\r\n rotatePoint.value = null;\r\n circleFlyActive.value = false;\r\n return;\r\n }\r\n\r\n const center = map.getCenter();\r\n const rp = new mars3d.thing.RotatePoint({ distance: 5000, time: 30 });\r\n map.addThing(rp);\r\n rp.start(center);\r\n rotatePoint.value = rp;\r\n circleFlyActive.value = true;\r\n }\r\n\r\n // ─── 飞行到点击位置或地图中心 ──────────────────────────────────────────\r\n function flyTo() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n flyToActive.value = true;\r\n const done = () => setTimeout(() => { flyToActive.value = false; }, 2000);\r\n\r\n const pos = mapContext.lastClickPosition.value;\r\n if (pos) {\r\n const target = { ...pos, alt: pos.alt > 0 ? pos.alt : 5000 };\r\n map.setCameraView(target, { duration: 2, complete: done });\r\n } else {\r\n map.flyHome({ duration: 2 });\r\n done();\r\n }\r\n }\r\n\r\n // ─── 第一视角漫游 ──────────────────────────────────────────────────────\r\n function toggleFirstPerson() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (!firstPersonRoam.value) {\r\n const roam = new mars3d.thing.FirstPersonRoam({});\r\n map.addThing(roam);\r\n initialCameraView = map.getCameraView();\r\n roam.enabled = true;\r\n firstPersonRoam.value = roam;\r\n firstPersonActive.value = true;\r\n } else {\r\n const roam = firstPersonRoam.value;\r\n roam.enabled = !roam.enabled;\r\n firstPersonActive.value = roam.enabled;\r\n if (!roam.enabled && initialCameraView) {\r\n map.setCameraView(initialCameraView, { duration: 1 });\r\n } else if (roam.enabled) {\r\n initialCameraView = map.getCameraView();\r\n }\r\n }\r\n }\r\n\r\n // ─── 键盘漫游 ──────────────────────────────────────────────────────────\r\n function toggleKeyboardNavigate() {\r\n const map = getMap();\r\n if (!map) return;\r\n\r\n if (!keyboardRoam.value) {\r\n const roam = new mars3d.thing.KeyboardRoam({});\r\n map.addThing(roam);\r\n roam.enabled = true;\r\n keyboardRoam.value = roam;\r\n keyboardActive.value = true;\r\n } else {\r\n const roam = keyboardRoam.value;\r\n roam.enabled = !roam.enabled;\r\n keyboardActive.value = roam.enabled;\r\n }\r\n }\r\n\r\n return {\r\n // 状态\r\n circleFlyActive,\r\n firstPersonActive,\r\n keyboardActive,\r\n flyToActive,\r\n // 方法\r\n toggleCircleFly,\r\n flyTo,\r\n toggleFirstPerson,\r\n toggleKeyboardNavigate,\r\n };\r\n}\r\n","<!--\r\n MarsMapContainer — 地图核心容器组件\r\n\r\n 功能:\r\n 1. 集成底层 MarsMap 渲染组件\r\n 2. 内置测量/绘制工具栏(ToolbarPanel)和视角控制面板(VisionPanel)\r\n 3. 组合所有 composable,通过 provide 向子组件/插槽透传地图上下文\r\n 4. 通过 default 插槽支持业务组件叠加(popup、图表、统计面板等)\r\n\r\n Props:\r\n - configUrl 地图配置 JSON 路径\r\n - mapKey 多地图时区分实例的 key(默认 \"default\")\r\n - hideToolbar 是否隐藏工具栏(默认 false)\r\n - hideVision 是否隐藏视觉控制按钮(默认 false)\r\n\r\n Expose(供父组件通过 ref 访问):\r\n - map\r\n - graphicLayer\r\n - measureLayer\r\n - selectedGraphic\r\n - addGraphic()\r\n - addThing()\r\n - measure(useMeasure 全量返回)\r\n - draw(useDraw 全量返回)\r\n - vision(useVision 全量返回)\r\n-->\r\n<template>\r\n <div class=\"mars-map-container\">\r\n <!-- 底层地图渲染 -->\r\n <MarsMap\r\n :url=\"configUrl\"\r\n :map-key=\"mapKey\"\r\n @onload=\"onMapLoad\"\r\n />\r\n\r\n <!-- 测量/绘制工具栏 -->\r\n <ToolbarPanel\r\n v-if=\"!hideToolbar\"\r\n :active-draw-type=\"draw.activeDrawType.value\"\r\n @tool-activate=\"handleToolActivate\"\r\n @clear=\"handleClear\"\r\n />\r\n\r\n <!-- 视角控制面板 -->\r\n <VisionPanel\r\n v-if=\"!hideVision\"\r\n :circle-fly-active=\"vision.circleFlyActive.value\"\r\n :fly-to-active=\"vision.flyToActive.value\"\r\n :first-person-active=\"vision.firstPersonActive.value\"\r\n :keyboard-navigate-active=\"vision.keyboardActive.value\"\r\n @vision-execute=\"handleVisionExecute\"\r\n />\r\n\r\n <!-- 业务插槽:自定义 UI 叠加层 -->\r\n <slot />\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { provide } from \"vue\";\r\nimport MarsMap from \"../mars-work/mars-map.vue\";\r\nimport ToolbarPanel from \"./panels/ToolbarPanel.vue\";\r\nimport VisionPanel from \"./panels/VisionPanel.vue\";\r\n\r\nimport { useMap } from \"./composables/useMap\";\r\nimport { useMeasure } from \"./composables/useMeasure\";\r\nimport { useDraw } from \"./composables/useDraw\";\r\nimport { useVision } from \"./composables/useVision\";\r\n\r\n// ─── Props ──────────────────────────────────────────────────────────────────\r\nconst props = withDefaults(\r\n defineProps<{\r\n configUrl?: string;\r\n mapKey?: string;\r\n hideToolbar?: boolean;\r\n hideVision?: boolean;\r\n }>(),\r\n {\r\n configUrl: \"config/config.json\",\r\n mapKey: \"default\",\r\n hideToolbar: false,\r\n hideVision: false,\r\n },\r\n);\r\n\r\n// ─── Emits ──────────────────────────────────────────────────────────────────\r\nconst emit = defineEmits<{\r\n /** 地图加载完成,回传 map 实例 */\r\n onload: [map: any];\r\n}>();\r\n\r\n// ─── Composables ────────────────────────────────────────────────────────────\r\nconst mapCtx = useMap();\r\nconst measure = useMeasure(mapCtx);\r\nconst draw = useDraw(mapCtx);\r\nconst vision = useVision(mapCtx);\r\n\r\n// ─── provide(供插槽内的业务组件直接 inject 使用) ──────────────────────────\r\nprovide(\"mapContext\", mapCtx);\r\nprovide(\"measureContext\", measure);\r\nprovide(\"drawContext\", draw);\r\nprovide(\"visionContext\", vision);\r\n\r\n// ─── 地图加载回调 ────────────────────────────────────────────────────────────\r\nfunction onMapLoad(map: any) {\r\n mapCtx.initMap(map);\r\n measure.initMeasure();\r\n emit(\"onload\", map);\r\n}\r\n\r\n// ─── 工具栏事件处理 ──────────────────────────────────────────────────────────\r\ntype ToolAction =\r\n | \"measureDistance\" | \"measureArea\" | \"measureHeight\" | \"measureAngle\"\r\n | \"drawPoint\" | \"drawLine\" | \"drawPolygon\" | \"drawCircle\" | \"drawRectangle\" | \"drawFreePolygon\";\r\n\r\nfunction handleToolActivate(tool: string) {\r\n switch (tool as ToolAction) {\r\n case \"measureDistance\": measure.measureDistance(); break;\r\n case \"measureArea\": measure.measureArea(); break;\r\n case \"measureHeight\": measure.measureHeight(); break;\r\n case \"measureAngle\": measure.measureAngle(); break;\r\n case \"drawPoint\": draw.drawPoint(); break;\r\n case \"drawLine\": draw.drawLine(); break;\r\n case \"drawPolygon\": draw.drawPolygon(); break;\r\n case \"drawCircle\": draw.drawCircle(); break;\r\n case \"drawRectangle\": draw.drawRectangle(); break;\r\n case \"drawFreePolygon\": draw.drawFreePolygon(); break;\r\n }\r\n}\r\n\r\nfunction handleClear() {\r\n measure.clearMeasure();\r\n draw.clearDraw();\r\n}\r\n\r\n// ─── 视角控制事件处理 ────────────────────────────────────────────────────────\r\ntype VisionAction = \"circleFly\" | \"flyTo\" | \"firstPerson\" | \"keyboardNavigate\";\r\n\r\nfunction handleVisionExecute(action: string) {\r\n switch (action as VisionAction) {\r\n case \"circleFly\": vision.toggleCircleFly(); break;\r\n case \"flyTo\": vision.flyTo(); break;\r\n case \"firstPerson\": vision.toggleFirstPerson(); break;\r\n case \"keyboardNavigate\": vision.toggleKeyboardNavigate(); break;\r\n }\r\n}\r\n\r\n// ─── Expose(父组件 ref 访问) ────────────────────────────────────────────────\r\ndefineExpose({\r\n map: mapCtx.map,\r\n graphicLayer: mapCtx.graphicLayer,\r\n measureLayer: mapCtx.measureLayer,\r\n selectedGraphic: mapCtx.selectedGraphic,\r\n lastClickPosition: mapCtx.lastClickPosition,\r\n addGraphic: mapCtx.addGraphic,\r\n addThing: mapCtx.addThing,\r\n measure,\r\n draw,\r\n vision,\r\n});\r\n</script>\r\n\r\n<style scoped>\r\n.mars-map-container {\r\n width: 100%;\r\n height: 100%;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n</style>\r\n","/**\r\n * usePoiMarker — POI 标注管理 composable\r\n *\r\n * 职责:\r\n * - 维护 POI 数据列表(纯数据层)\r\n * - 管理地图上对应的 BillboardEntity 图形(图形层)\r\n * - 提供 添加 / 删除 / 选中 / 飞行定位 操作\r\n * - 数据与图形保持双向同步(通过 graphicId 关联)\r\n *\r\n * 使用方式(在业务组件内):\r\n * const mapCtx = inject<UseMapReturn>('mapContext')!\r\n * const poi = usePoiMarker(mapCtx)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\n\r\n// ─── POI 数据类型 ─────────────────────────────────────────────────────────────\r\nexport interface PoiItem {\r\n id: string;\r\n name: string;\r\n lng: number;\r\n lat: number;\r\n alt: number;\r\n category: \"default\" | \"warning\" | \"info\";\r\n description?: string;\r\n /** 对应地图上的 Graphic 实例引用 */\r\n graphic?: any;\r\n}\r\n\r\n/** 分类颜色映射 */\r\nconst CATEGORY_ICON: Record<PoiItem[\"category\"], string> = {\r\n default: \"//data.mars3d.cn/img/marker/mark-blue.png\",\r\n warning: \"//data.mars3d.cn/img/marker/mark-red.png\",\r\n info: \"//data.mars3d.cn/img/marker/mark-green.png\",\r\n};\r\n\r\nlet _idCounter = 1;\r\n\r\nexport function usePoiMarker(mapCtx: UseMapReturn) {\r\n // ─── 独立业务图层(与测量层隔离) ─────────────────────────────────────────\r\n const poiLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── POI 数据列表 ──────────────────────────────────────────────────────────\r\n const poiList = ref<PoiItem[]>([]);\r\n\r\n // ─── 当前选中的 POI ────────────────────────────────────────────────────────\r\n const activePoiId = ref<string | null>(null);\r\n\r\n /** 在地图加载后调用,初始化专属图层 */\r\n function initPoiLayer() {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n const layer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(layer);\r\n poiLayer.value = layer;\r\n\r\n // 点击图层上的标注 → 选中对应 POI\r\n layer.on(mars3d.EventType.click, (e: any) => {\r\n const poiId = e.graphic?.attr?.poiId;\r\n if (poiId) selectPoi(poiId);\r\n });\r\n }\r\n\r\n /** 添加 POI(创建数据 + 在地图上生成图形) */\r\n function addPoi(params: Omit<PoiItem, \"id\" | \"graphic\">) {\r\n const layer = poiLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `poi-${_idCounter++}`;\r\n\r\n // 创建地图图形\r\n const graphic = new mars3d.graphic.BillboardEntity({\r\n position: [params.lng, params.lat, params.alt],\r\n style: {\r\n image: CATEGORY_ICON[params.category],\r\n scale: 1,\r\n horizontalOrigin: mars3d.Cesium.HorizontalOrigin.CENTER,\r\n verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,\r\n clampToGround: false,\r\n // 标注文字\r\n label: {\r\n text: params.name,\r\n font_size: 14,\r\n color: \"#ffffff\",\r\n outline: true,\r\n outlineColor: \"#333333\",\r\n outlineWidth: 2,\r\n pixelOffset: new mars3d.Cesium.Cartesian2(0, -40),\r\n visibleDepth: false,\r\n },\r\n },\r\n // popup 弹窗(点击标注时自动展示)\r\n popup: buildPopupHtml(params),\r\n attr: { poiId: id, name: params.name },\r\n });\r\n\r\n layer.addGraphic(graphic);\r\n\r\n const poi: PoiItem = { ...params, id, graphic };\r\n poiList.value.push(poi);\r\n return poi;\r\n }\r\n\r\n /** 删除 POI */\r\n function removePoi(id: string) {\r\n const idx = poiList.value.findIndex((p) => p.id === id);\r\n if (idx === -1) return;\r\n\r\n const poi = poiList.value[idx];\r\n poi.graphic && poiLayer.value?.removeGraphic(poi.graphic);\r\n poiList.value.splice(idx, 1);\r\n\r\n if (activePoiId.value === id) activePoiId.value = null;\r\n }\r\n\r\n /** 选中 POI(高亮 + 视角飞行) */\r\n function selectPoi(id: string, flyTo = false) {\r\n activePoiId.value = id;\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi) return;\r\n\r\n // 高亮:放大图标\r\n poiList.value.forEach((p) => {\r\n if (p.graphic) {\r\n p.graphic.style.scale = p.id === id ? 1.4 : 1.0;\r\n }\r\n });\r\n\r\n if (flyTo) flyToPoi(id);\r\n }\r\n\r\n /** 更新 POI 名称(实时同步到图形和 popup) */\r\n function updatePoiName(id: string, newName: string) {\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi) return;\r\n\r\n poi.name = newName;\r\n\r\n // 同步更新图形 attr\r\n if (poi.graphic) {\r\n poi.graphic.attr = { ...poi.graphic.attr, name: newName };\r\n poi.graphic.popup = buildPopupHtml(poi);\r\n // 同步更新 label 文字\r\n if (poi.graphic.style?.label) {\r\n poi.graphic.style.label.text = newName;\r\n }\r\n poi.graphic.closePopup?.();\r\n }\r\n }\r\n\r\n /** 飞行到 POI 位置 */\r\n function flyToPoi(id: string) {\r\n const poi = poiList.value.find((p) => p.id === id);\r\n if (!poi || !mapCtx.map.value) return;\r\n\r\n const map = mapCtx.map.value;\r\n\r\n // 以标注点高度为基准,飞行高度 = 标注高度 + 合理偏移\r\n const baseAlt = poi.alt > 1 ? poi.alt : 50;\r\n const flyAlt = baseAlt + 1500;\r\n\r\n // 不指定 pitch,让相机正上方俯视,定位最准确\r\n map.setCameraView({ lng: poi.lng, lat: poi.lat, alt: flyAlt }, { duration: 1.5 });\r\n }\r\n\r\n /** 清空所有 POI */\r\n function clearAll() {\r\n poiLayer.value?.clear();\r\n poiList.value = [];\r\n activePoiId.value = null;\r\n }\r\n\r\n /** 开启/关闭「点击地图添加标注」模式 */\r\n const isAddMode = ref(false);\r\n let _clickHandler: ((e: any) => void) | null = null;\r\n\r\n function toggleAddMode(\r\n onAdded?: (poi: PoiItem) => void,\r\n defaultName = \"新标注\",\r\n category: PoiItem[\"category\"] = \"default\",\r\n ) {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n if (isAddMode.value) {\r\n // 退出添加模式\r\n if (_clickHandler) {\r\n map.off(mars3d.EventType.click, _clickHandler);\r\n _clickHandler = null;\r\n }\r\n isAddMode.value = false;\r\n } else {\r\n // 进入添加模式:下一次点击地图即创建 POI\r\n isAddMode.value = true;\r\n _clickHandler = (e: any) => {\r\n // 优先取经纬度坐标,兜底用笛卡尔坐标转换\r\n let lng: number, lat: number, alt: number;\r\n\r\n if (e.lnglat) {\r\n lng = e.lnglat.lng;\r\n lat = e.lnglat.lat;\r\n alt = e.lnglat.alt ?? 0;\r\n } else if (e.cartesian) {\r\n const carto = mars3d.Cesium.Cartographic.fromCartesian(e.cartesian);\r\n lng = mars3d.Cesium.Math.toDegrees(carto.longitude);\r\n lat = mars3d.Cesium.Math.toDegrees(carto.latitude);\r\n alt = carto.height > 0 ? carto.height : 50; // terrain height fallback\r\n } else {\r\n return;\r\n }\r\n\r\n // 标注高度至少离地面 50m,避免贴地\r\n const finalAlt = alt > 1 ? alt : 50;\r\n\r\n const poi = addPoi({\r\n name: `${defaultName} ${_idCounter}`,\r\n lng,\r\n lat,\r\n alt: finalAlt,\r\n category,\r\n });\r\n if (poi) onAdded?.(poi);\r\n // 单次模式:添加完即退出\r\n toggleAddMode();\r\n };\r\n map.on(mars3d.EventType.click, _clickHandler);\r\n }\r\n }\r\n\r\n return {\r\n poiLayer,\r\n poiList,\r\n activePoiId,\r\n isAddMode,\r\n initPoiLayer,\r\n addPoi,\r\n removePoi,\r\n selectPoi,\r\n flyToPoi,\r\n updatePoiName,\r\n clearAll,\r\n toggleAddMode,\r\n };\r\n}\r\n\r\n// ─── 工具:生成 popup HTML ────────────────────────────────────────────────────\r\nfunction buildPopupHtml(poi: Omit<PoiItem, \"id\" | \"graphic\">) {\r\n return `\r\n <div style=\"padding:8px 12px;min-width:160px;\">\r\n <div style=\"font-size:15px;font-weight:bold;margin-bottom:6px;color:#fff;\">${poi.name}</div>\r\n <div style=\"font-size:12px;color:#adc6e5;line-height:1.8;\">\r\n <div>经度:${poi.lng.toFixed(6)}</div>\r\n <div>纬度:${poi.lat.toFixed(6)}</div>\r\n <div>高度:${poi.alt.toFixed(1)} m</div>\r\n ${poi.description ? `<div style=\"margin-top:4px;\">${poi.description}</div>` : \"\"}\r\n </div>\r\n </div>\r\n `;\r\n}\r\n\r\nexport type UsePoiMarkerReturn = ReturnType<typeof usePoiMarker>;\r\n","<!--\r\n PoiMarkerLayer — POI 标注地图层组件\r\n\r\n 职责:\r\n - 放置在 MarsMapContainer 的 <slot> 内\r\n - 通过 inject 获取地图上下文,完成图层初始化\r\n - 通过 provide 将 poiCtx 向子组件暴露(inject 只走父→子,不走兄弟)\r\n - 内部通过 <slot> 渲染 PoiMarkerPanel 等子组件,保证 provide/inject 链路正确\r\n - 对外 expose usePoiMarker 全量接口,供父组件 ref 访问\r\n\r\n 使用方式(PoiMarkerPanel 必须作为子内容传入,而非兄弟节点):\r\n <MarsMapContainer @onload=\"...\">\r\n <PoiMarkerLayer ref=\"poiLayerRef\">\r\n <PoiMarkerPanel />\r\n </PoiMarkerLayer>\r\n </MarsMapContainer>\r\n-->\r\n<template>\r\n <!-- provide/inject 需要父子关系,用 slot 渲染子组件 -->\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject, provide, watch, onUnmounted } from \"vue\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\nimport { usePoiMarker } from \"./usePoiMarker\";\r\n\r\n// ─── 注入地图上下文 ────────────────────────────────────────────────────────────\r\nconst mapCtx = inject<UseMapReturn>(\"mapContext\");\r\nif (!mapCtx) throw new Error(\"[PoiMarkerLayer] 必须放置在 MarsMapContainer 内部\");\r\n\r\n// ─── 初始化 POI 管理 composable ────────────────────────────────────────────────\r\nconst poi = usePoiMarker(mapCtx);\r\n\r\n// ─── 等待地图就绪后初始化图层 ─────────────────────────────────────────────────\r\n// map 在 MarsMapContainer onload 后才不为 null\r\nconst stopWatch = watch(\r\n () => mapCtx.map.value,\r\n (map) => {\r\n if (map) {\r\n poi.initPoiLayer();\r\n stopWatch(); // 只需初始化一次\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonUnmounted(() => {\r\n poi.clearAll();\r\n});\r\n\r\n// ─── provide 给同级业务组件(PoiMarkerPanel 等)─────────────────────────────\r\nprovide(\"poiContext\", poi);\r\n\r\n// ─── expose 给父组件 ref ──────────────────────────────────────────────────────\r\ndefineExpose(poi);\r\n</script>\r\n","<!--\r\n PoiMarkerPanel — POI 标注管理面板(左侧)\r\n\r\n 功能:\r\n - 标注列表(名称 / 分类标签 / 定位 / 删除)\r\n - 添加模式切换按钮(点击地图新增标注)\r\n - 分类筛选标签\r\n - 点击列表项飞行到标注位置 + 地图高亮\r\n\r\n 数据来源:inject('poiContext'),由同级 PoiMarkerLayer 提供\r\n-->\r\n<template>\r\n <div\r\n ref=\"panelEl\"\r\n class=\"poi-panel\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :style=\"\r\n !isCollapsed\r\n ? { left: pos.x + 'px', top: pos.y + 'px' }\r\n : { left: pos.x + 'px', top: pos.y + 'px' }\r\n \"\r\n >\r\n <!-- 面板标题栏(可拖拽) -->\r\n <div\r\n class=\"poi-panel__header\"\r\n :class=\"{ 'is-dragging': isDragging }\"\r\n @mousedown.prevent=\"startDrag\"\r\n @click=\"isDragging ? null : toggleCollapse()\"\r\n >\r\n <!-- 收缩后只显示图标 -->\r\n <template v-if=\"isCollapsed\">\r\n <div class=\"collapsed-icon-wrap\">\r\n <i class=\"fa fa-map-marker collapsed-icon\" />\r\n <span class=\"poi-count poi-count--collapsed\">{{\r\n filteredList.length\r\n }}</span>\r\n </div>\r\n </template>\r\n <template v-else>\r\n <span class=\"poi-panel__title\">\r\n <i class=\"fa fa-map-marker\" />\r\n POI 标注管理\r\n <span class=\"poi-count\">{{ filteredList.length }}</span>\r\n </span>\r\n <i class=\"fa fa-chevron-left collapse-icon\" />\r\n </template>\r\n </div>\r\n\r\n <div class=\"poi-panel__body\" v-show=\"!isCollapsed\">\r\n <!-- 操作栏 -->\r\n <div class=\"poi-panel__toolbar\">\r\n <button\r\n class=\"btn\"\r\n :class=\"{ 'btn--active': poi.isAddMode.value }\"\r\n @click=\"toggleAdd\"\r\n >\r\n <i :class=\"['fa', poi.isAddMode.value ? 'fa-times' : 'fa-plus']\" />\r\n {{ poi.isAddMode.value ? \"取消添加\" : \"点击地图添加\" }}\r\n </button>\r\n <button\r\n class=\"btn btn--danger\"\r\n @click=\"confirmClear\"\r\n :disabled=\"poi.poiList.value.length === 0\"\r\n >\r\n <i class=\"fa fa-trash-o\" /> 清空\r\n </button>\r\n </div>\r\n\r\n <!-- 分类筛选 -->\r\n <div class=\"poi-panel__filter\">\r\n <span\r\n v-for=\"cat in categories\"\r\n :key=\"cat.value\"\r\n class=\"filter-tag\"\r\n :class=\"{ active: activeCategory === cat.value }\"\r\n @click=\"activeCategory = cat.value\"\r\n >\r\n <i :class=\"['fa', cat.icon]\" :style=\"{ color: cat.color }\" />\r\n {{ cat.label }}\r\n </span>\r\n </div>\r\n\r\n <!-- POI 列表 -->\r\n <div class=\"poi-panel__list\">\r\n <TransitionGroup name=\"poi-list\">\r\n <div\r\n v-for=\"item in filteredList\"\r\n :key=\"item.id\"\r\n class=\"poi-item\"\r\n :class=\"{ 'poi-item--active': poi.activePoiId.value === item.id }\"\r\n @click=\"onSelect(item.id)\"\r\n >\r\n <!-- 分类色块 -->\r\n <span\r\n class=\"poi-item__dot\"\r\n :style=\"{ background: getCategoryColor(item.category) }\"\r\n />\r\n\r\n <div class=\"poi-item__info\">\r\n <!-- 编辑态:输入框 -->\r\n <input\r\n v-if=\"editingId === item.id\"\r\n class=\"poi-item__name-input\"\r\n v-model=\"editName\"\r\n @keydown.enter=\"saveEdit\"\r\n @keydown.escape=\"cancelEdit\"\r\n @click.stop\r\n ref=\"editInputEl\"\r\n />\r\n <!-- 正常态:名称 -->\r\n <div\r\n v-else\r\n class=\"poi-item__name\"\r\n @dblclick.stop=\"startEdit(item)\"\r\n >\r\n {{ item.name }}\r\n </div>\r\n <div class=\"poi-item__coord\">\r\n {{ item.lng.toFixed(4) }}, {{ item.lat.toFixed(4) }}\r\n </div>\r\n </div>\r\n\r\n <!-- 操作按钮 -->\r\n <div class=\"poi-item__actions\">\r\n <button\r\n class=\"icon-btn\"\r\n title=\"编辑名称\"\r\n @click.stop=\"startEdit(item)\"\r\n >\r\n <i class=\"fa fa-pencil\" />\r\n </button>\r\n <button\r\n class=\"icon-btn\"\r\n title=\"飞行定位\"\r\n @click.stop=\"onFlyTo(item.id)\"\r\n >\r\n <i class=\"fa fa-crosshairs\" />\r\n </button>\r\n <button\r\n class=\"icon-btn icon-btn--danger\"\r\n title=\"删除\"\r\n @click.stop=\"onRemove(item.id)\"\r\n >\r\n <i class=\"fa fa-times\" />\r\n </button>\r\n </div>\r\n </div>\r\n </TransitionGroup>\r\n\r\n <!-- 空状态 -->\r\n <div v-if=\"filteredList.length === 0\" class=\"poi-panel__empty\">\r\n <i class=\"fa fa-map-o\" />\r\n <p>\r\n {{\r\n poi.isAddMode.value ? \"请在地图上点击添加标注\" : \"暂无标注数据\"\r\n }}\r\n </p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, reactive, computed, inject } from \"vue\";\r\nimport type { UsePoiMarkerReturn, PoiItem } from \"./usePoiMarker\";\r\n\r\n// ─── 注入 POI 上下文(由 PoiMarkerLayer provide) ────────────────────────────\r\nconst poi = inject<UsePoiMarkerReturn>(\"poiContext\");\r\nif (!poi) throw new Error(\"[PoiMarkerPanel] 必须与 PoiMarkerLayer 同级使用\");\r\n\r\n// ─── 面板状态 ─────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(true);\r\nconst toggleCollapse = () => {\r\n isCollapsed.value = !isCollapsed.value;\r\n};\r\n\r\n// ─── 拖拽移动 ─────────────────────────────────────────────────────────────────\r\nconst panelEl = ref<HTMLElement | null>(null);\r\nconst isDragging = ref(false);\r\n\r\n// 初始位置(可随需求调整)\r\nconst pos = reactive({ x: 10, y: 10 });\r\n\r\nlet dragStartX = 0;\r\nlet dragStartY = 0;\r\nlet origX = 0;\r\nlet origY = 0;\r\n\r\nfunction startDrag(e: MouseEvent) {\r\n isDragging.value = true;\r\n dragStartX = e.clientX;\r\n dragStartY = e.clientY;\r\n origX = pos.x;\r\n origY = pos.y;\r\n\r\n document.addEventListener(\"mousemove\", onDrag);\r\n document.addEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\nfunction onDrag(e: MouseEvent) {\r\n if (!isDragging.value) return;\r\n pos.x = origX + (e.clientX - dragStartX);\r\n pos.y = origY + (e.clientY - dragStartY);\r\n}\r\n\r\nfunction stopDrag() {\r\n isDragging.value = false;\r\n document.removeEventListener(\"mousemove\", onDrag);\r\n document.removeEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\n// ─── 分类筛选 ─────────────────────────────────────────────────────────────────\r\nconst categories = [\r\n { value: \"all\", label: \"全部\", icon: \"fa-list\", color: \"#aaa\" },\r\n { value: \"default\", label: \"普通\", icon: \"fa-map-marker\", color: \"#3ea6ff\" },\r\n {\r\n value: \"warning\",\r\n label: \"警告\",\r\n icon: \"fa-exclamation-triangle\",\r\n color: \"#ff6b6b\",\r\n },\r\n { value: \"info\", label: \"信息\", icon: \"fa-info-circle\", color: \"#52c41a\" },\r\n] as const;\r\n\r\nconst activeCategory = ref<string>(\"all\");\r\n\r\nconst filteredList = computed(() => {\r\n if (activeCategory.value === \"all\") return poi.poiList.value;\r\n return poi.poiList.value.filter((p) => p.category === activeCategory.value);\r\n});\r\n\r\nconst getCategoryColor = (cat: PoiItem[\"category\"]) => {\r\n const map: Record<string, string> = {\r\n default: \"#3ea6ff\",\r\n warning: \"#ff6b6b\",\r\n info: \"#52c41a\",\r\n };\r\n return map[cat] ?? \"#aaa\";\r\n};\r\n\r\n// ─── 添加模式 ─────────────────────────────────────────────────────────────────\r\nconst addCategory = ref<PoiItem[\"category\"]>(\"default\");\r\n\r\nfunction toggleAdd() {\r\n poi.toggleAddMode(\r\n undefined, // onAdded 回调(可按需传)\r\n \"标注点\",\r\n addCategory.value,\r\n );\r\n}\r\n\r\n// ─── 列表操作 ─────────────────────────────────────────────────────────────────\r\nfunction onSelect(id: string) {\r\n poi.selectPoi(id, true); // 选中并飞行\r\n}\r\n\r\nfunction onFlyTo(id: string) {\r\n poi.flyToPoi(id);\r\n}\r\n\r\nfunction onRemove(id: string) {\r\n poi.removePoi(id);\r\n}\r\n\r\n// ─── 编辑名称 ─────────────────────────────────────────────────────────────────\r\nconst editingId = ref<string | null>(null);\r\nconst editName = ref(\"\");\r\nconst editInputEl = ref<HTMLInputElement | null>(null);\r\n\r\nfunction startEdit(item: PoiItem) {\r\n editingId.value = item.id;\r\n editName.value = item.name;\r\n // DOM 更新后自动聚焦\r\n setTimeout(() => editInputEl.value?.select(), 30);\r\n}\r\n\r\nfunction saveEdit() {\r\n if (editingId.value && editName.value.trim()) {\r\n poi.updatePoiName(editingId.value, editName.value.trim());\r\n }\r\n cancelEdit();\r\n}\r\n\r\nfunction cancelEdit() {\r\n editingId.value = null;\r\n editName.value = \"\";\r\n}\r\n\r\nfunction confirmClear() {\r\n if (window.confirm(`确认清空全部 ${poi.poiList.value.length} 个标注?`)) {\r\n poi.clearAll();\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n// ─── 主面板 ────────────────────────────────────────────────────────────────────\r\n.poi-panel {\r\n position: absolute;\r\n width: 260px;\r\n height: auto;\r\n max-height: calc(100vh - 40px);\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px;\r\n z-index: 999;\r\n display: flex;\r\n flex-direction: column;\r\n backdrop-filter: blur(4px);\r\n transition: width 0.25s ease;\r\n\r\n // 收缩状态:只保留标题栏宽度,内容自适应高度\r\n &.collapsed {\r\n width: 46px;\r\n max-height: none;\r\n overflow: hidden;\r\n\r\n .poi-panel__title {\r\n display: none;\r\n }\r\n .poi-panel__body {\r\n display: none;\r\n }\r\n .collapse-icon {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n// ─── 标题栏 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__header {\r\n position: relative; // 为收缩态角标 absolute 定位提供参考\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 14px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 6px 0 0;\r\n cursor: grab;\r\n user-select: none;\r\n flex-shrink: 0;\r\n\r\n &.is-dragging {\r\n cursor: grabbing;\r\n }\r\n\r\n // 收缩后的图标态\r\n .collapsed-icon {\r\n display: none;\r\n color: #3ea6ff;\r\n font-size: 18px;\r\n }\r\n\r\n .poi-panel__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #e8f4ff;\r\n font-size: 14px;\r\n font-weight: 600;\r\n\r\n .fa {\r\n color: #3ea6ff;\r\n font-size: 15px;\r\n }\r\n }\r\n\r\n .poi-count {\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 11px;\r\n padding: 1px 6px;\r\n border-radius: 10px;\r\n min-width: 18px;\r\n text-align: center;\r\n }\r\n\r\n .collapse-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n }\r\n}\r\n\r\n// 收缩态:图标自适应高度,角标定位在图标右上角\r\n.poi-panel.collapsed .poi-panel__header {\r\n flex-direction: column;\r\n align-items: flex-start; // 左对齐\r\n padding: 8px 10px 10px; // 底部留更多空间\r\n gap: 0;\r\n cursor: pointer;\r\n\r\n // 图标 + 角标一体化容器,图标在左下\r\n .collapsed-icon-wrap {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-top: 12px; // 往下一点\r\n margin-left: 2px;\r\n }\r\n\r\n .collapsed-icon {\r\n display: block;\r\n font-size: 20px;\r\n color: #3ea6ff;\r\n }\r\n\r\n // 角标:相对于图标容器定位,落在图标右上角\r\n .poi-count--collapsed {\r\n display: block;\r\n position: absolute;\r\n top: -10px;\r\n right: -12px;\r\n min-width: 16px;\r\n height: 16px;\r\n line-height: 16px;\r\n font-size: 10px;\r\n padding: 0 3px;\r\n background: #3ea6ff;\r\n color: #fff;\r\n border-radius: 8px;\r\n }\r\n}\r\n\r\n// ─── 面板体 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__body {\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n// ─── 操作栏 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__toolbar {\r\n display: flex;\r\n gap: 8px;\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .btn {\r\n flex: 1;\r\n padding: 6px 8px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.35);\r\n color: #fff;\r\n border-color: #3ea6ff;\r\n }\r\n &--danger {\r\n flex: 0 0 auto;\r\n border-color: rgba(255, 100, 100, 0.4);\r\n background: rgba(255, 100, 100, 0.1);\r\n color: #ffaaaa;\r\n &:hover:not(:disabled) {\r\n background: rgba(255, 100, 100, 0.25);\r\n color: #fff;\r\n }\r\n &:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 分类筛选 ──────────────────────────────────────────────────────────────────\r\n.poi-panel__filter {\r\n display: flex;\r\n gap: 6px;\r\n padding: 8px 12px;\r\n flex-wrap: wrap;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .filter-tag {\r\n padding: 3px 8px;\r\n border-radius: 12px;\r\n font-size: 11px;\r\n color: #7a9ec0;\r\n background: rgba(255, 255, 255, 0.06);\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n transition: all 0.2s ease;\r\n\r\n &:hover {\r\n background: rgba(255, 255, 255, 0.12);\r\n color: #c8dff0;\r\n }\r\n &.active {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #3ea6ff;\r\n }\r\n }\r\n}\r\n\r\n// ─── 列表 ──────────────────────────────────────────────────────────────────────\r\n.poi-panel__list {\r\n overflow-y: auto;\r\n max-height: calc(100vh - 220px);\r\n padding: 6px 0;\r\n\r\n &::-webkit-scrollbar {\r\n width: 4px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n\r\n.poi-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background 0.15s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.1);\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.18);\r\n }\r\n\r\n &__dot {\r\n width: 8px;\r\n height: 8px;\r\n border-radius: 50%;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__info {\r\n flex: 1;\r\n min-width: 0;\r\n &-name {\r\n overflow: hidden;\r\n }\r\n }\r\n\r\n &__name {\r\n font-size: 13px;\r\n color: #d8ecff;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n cursor: text;\r\n\r\n &:hover {\r\n color: #a0d4ff;\r\n }\r\n }\r\n\r\n &__name-input {\r\n width: 100%;\r\n font-size: 13px;\r\n color: #e8f4ff;\r\n background: rgba(62, 166, 255, 0.15);\r\n border: 1px solid rgba(62, 166, 255, 0.5);\r\n border-radius: 3px;\r\n padding: 1px 5px;\r\n outline: none;\r\n font-family: inherit;\r\n\r\n &:focus {\r\n border-color: #3ea6ff;\r\n background: rgba(62, 166, 255, 0.22);\r\n }\r\n }\r\n\r\n &__coord {\r\n font-size: 11px;\r\n color: #5a7a9a;\r\n margin-top: 2px;\r\n font-family: monospace;\r\n }\r\n\r\n &__actions {\r\n display: flex;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n opacity: 0;\r\n transition: opacity 0.15s ease;\r\n }\r\n\r\n &:hover &__actions {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.icon-btn {\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: rgba(255, 255, 255, 0.08);\r\n color: #9dc8f0;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n transition: all 0.15s ease;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n &--danger:hover {\r\n background: rgba(255, 80, 80, 0.35);\r\n color: #fff;\r\n }\r\n}\r\n\r\n// ─── 空状态 ────────────────────────────────────────────────────────────────────\r\n.poi-panel__empty {\r\n text-align: center;\r\n padding: 30px 20px;\r\n color: #4a6a8a;\r\n\r\n .fa {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: block;\r\n }\r\n p {\r\n font-size: 12px;\r\n margin: 0;\r\n line-height: 1.6;\r\n }\r\n}\r\n\r\n// ─── 列表动画 ──────────────────────────────────────────────────────────────────\r\n.poi-list-enter-active,\r\n.poi-list-leave-active {\r\n transition: all 0.25s ease;\r\n}\r\n.poi-list-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n.poi-list-leave-to {\r\n opacity: 0;\r\n transform: translateX(12px);\r\n}\r\n</style>\r\n","/**\r\n * useTrack — 轨迹管理 composable\r\n *\r\n * 职责:\r\n * - 维护轨迹数据列表(历史轨迹 + 实时轨迹)\r\n * - 管理地图上的折线图形(PolylinePrimitive / CorridorPrimitive)\r\n * - 提供历史轨迹回放(播放 / 暂停 / 倍速 / 进度拖拽)\r\n * - 提供实时轨迹推送(持续追加坐标点)\r\n * - 数据与图形保持双向同步\r\n *\r\n * 使用方式(在 TrackLayer 内):\r\n * const mapCtx = inject<UseMapReturn>('mapContext')!\r\n * const track = useTrack(mapCtx)\r\n */\r\nimport { ref, shallowRef } from \"vue\";\r\nimport * as mars3d from \"mars3d\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\n\r\n// ─── 数据类型 ─────────────────────────────────────────────────────────────────\r\n\r\n/** 轨迹点 */\r\nexport interface TrackPoint {\r\n time: number; // Unix 时间戳(毫秒)\r\n lng: number;\r\n lat: number;\r\n alt: number;\r\n}\r\n\r\n/** 单条轨迹 */\r\nexport interface TrackItem {\r\n id: string;\r\n name: string;\r\n /** 轨迹点列表(按时间排序) */\r\n points: TrackPoint[];\r\n /** 轨迹线图形 */\r\n lineGraphic?: any;\r\n /** 实时模式下:当前\"已绘制\"到的点索引 */\r\n realtimeDrawnIdx?: number;\r\n /** 实时模式下:当前实时点图形 */\r\n realtimePoint?: any;\r\n /** 实时模式下:当前车头图标 */\r\n realtimeHeading?: any;\r\n /** 实时模式下:所有线段图形(用于删除时统一清理) */\r\n realtimeLineSegments?: any[];\r\n /** 回放开始时间戳 */\r\n _playStartTime?: number;\r\n}\r\n\r\nlet _idCounter = 1;\r\n\r\nexport function useTrack(mapCtx: UseMapReturn) {\r\n // ─── 图层 ─────────────────────────────────────────────────────────────────\r\n const trackLayer = shallowRef<mars3d.layer.GraphicLayer | null>(null);\r\n\r\n // ─── 轨迹列表 ─────────────────────────────────────────────────────────────\r\n const trackList = ref<TrackItem[]>([]);\r\n\r\n // ─── 当前选中 / 回放的轨迹 ────────────────────────────────────────────────\r\n const activeTrackId = ref<string | null>(null);\r\n\r\n // ─── 回放状态 ─────────────────────────────────────────────────────────────\r\n const isPlaying = ref(false);\r\n const currentTime = ref(0); // 当前回放时间戳\r\n const playbackSpeed = ref(1); // 倍速(1x / 2x / 4x / 8x)\r\n const playbackProgress = ref(0); // 0~100 百分比\r\n\r\n // ─── 实时模式标记 ──────────────────────────────────────────────────────────\r\n const isRealtimeMode = ref(false);\r\n const activeRealtimeId = ref<string | null>(null);\r\n\r\n // ─── 回放定时器 ───────────────────────────────────────────────────────────\r\n let _playInterval: ReturnType<typeof setInterval> | null = null;\r\n let _realtimeInterval: ReturnType<typeof setInterval> | null = null;\r\n\r\n // ─── 初始化图层 ────────────────────────────────────────────────────────────\r\n function initTrackLayer() {\r\n const map = mapCtx.map.value;\r\n if (!map) return;\r\n\r\n const layer = new mars3d.layer.GraphicLayer();\r\n map.addLayer(layer);\r\n trackLayer.value = layer;\r\n }\r\n\r\n // ─── 内部:绘制完整折线 ────────────────────────────────────────────────────\r\n function _buildLineGraphic(track: TrackItem) {\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n // 只画已有坐标\r\n const positions = track.points.map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n const line = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#3ea6ff\") as any,\r\n width: 3,\r\n opacity: 0.9,\r\n clampToGround: false,\r\n },\r\n attr: { trackId: track.id },\r\n });\r\n\r\n layer.addGraphic(line);\r\n return line;\r\n }\r\n\r\n // ─── 内部:实时追加一段线 ──────────────────────────────────────────────────\r\n function _appendRealtimeLine(track: TrackItem, fromIdx: number, toIdx: number) {\r\n const layer = trackLayer.value;\r\n if (!layer || toIdx <= fromIdx) return;\r\n\r\n const positions = track.points.slice(fromIdx, toIdx + 1)\r\n .map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n const segment = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#ff6b35\") as any,\r\n width: 4,\r\n opacity: 1,\r\n clampToGround: false,\r\n },\r\n });\r\n layer.addGraphic(segment);\r\n // 记录线段引用,用于删除时统一清理\r\n if (!track.realtimeLineSegments) {\r\n track.realtimeLineSegments = [];\r\n }\r\n track.realtimeLineSegments.push(segment);\r\n }\r\n\r\n // ─── 内部:更新实时点位图标 ─────────────────────────────────────────────────\r\n function _updateRealtimeMarker(track: TrackItem) {\r\n const layer = trackLayer.value;\r\n if (!layer) return;\r\n\r\n const lastPoint = track.points[track.realtimeDrawnIdx!];\r\n if (!lastPoint) return;\r\n\r\n // 更新图标位置\r\n if (track.realtimePoint) {\r\n track.realtimePoint.position = [lastPoint.lng, lastPoint.lat, lastPoint.alt];\r\n } else {\r\n const marker = new mars3d.graphic.BillboardEntity({\r\n position: [lastPoint.lng, lastPoint.lat, lastPoint.alt],\r\n style: {\r\n image: \"//data.mars3d.cn/img/marker/mark-blue.png\",\r\n scale: 1.2,\r\n horizontalOrigin: mars3d.Cesium.HorizontalOrigin.CENTER,\r\n verticalOrigin: mars3d.Cesium.VerticalOrigin.BOTTOM,\r\n },\r\n });\r\n layer.addGraphic(marker);\r\n track.realtimePoint = marker;\r\n }\r\n }\r\n\r\n // ─── 添加历史轨迹(从预置数据回放) ─────────────────────────────────────────\r\n function addTrack(points: TrackPoint[], name = \"轨迹\") {\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `track-${_idCounter++}`;\r\n const track: TrackItem = { id, name, points };\r\n track.lineGraphic = _buildLineGraphic(track);\r\n trackList.value.push(track);\r\n return track;\r\n }\r\n\r\n // ─── 开始实时轨迹推送 ──────────────────────────────────────────────────────\r\n function startRealtime(name = \"实时轨迹\") {\r\n if (activeRealtimeId.value) stopRealtime();\r\n\r\n const layer = trackLayer.value;\r\n if (!layer) return null;\r\n\r\n const id = `realtime-${_idCounter++}`;\r\n const track: TrackItem = {\r\n id,\r\n name,\r\n points: [],\r\n realtimeDrawnIdx: -1,\r\n };\r\n trackLayer.value = layer;\r\n trackList.value.push(track);\r\n activeRealtimeId.value = id;\r\n isRealtimeMode.value = true;\r\n return track;\r\n }\r\n\r\n // ─── 推送实时坐标点 ───────────────────────────────────────────────────────\r\n function pushRealtimePoint(id: string, lng: number, lat: number, alt = 0) {\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track) return;\r\n\r\n const point: TrackPoint = {\r\n time: Date.now(),\r\n lng,\r\n lat,\r\n alt,\r\n };\r\n track.points.push(point);\r\n track.realtimeDrawnIdx = track.points.length - 1;\r\n\r\n // 首次:直接建线和图标\r\n if (track.points.length === 1) {\r\n track.lineGraphic = _buildLineGraphic(track);\r\n _updateRealtimeMarker(track);\r\n } else {\r\n // 追加一段折线\r\n _appendRealtimeLine(track, track.points.length - 2, track.points.length - 1);\r\n _updateRealtimeMarker(track);\r\n }\r\n\r\n // 自动飞行跟随(最后一点)\r\n if (mapCtx.map.value) {\r\n mapCtx.map.value.flyToPoint(\r\n [lng, lat, alt + 50],\r\n { radius: 500, duration: 0.5 },\r\n );\r\n }\r\n }\r\n\r\n // ─── 停止实时推送(固化轨迹) ──────────────────────────────────────────────\r\n function stopRealtime(id?: string) {\r\n const targetId = id ?? activeRealtimeId.value;\r\n if (!targetId) return;\r\n\r\n const track = trackList.value.find((t) => t.id === targetId);\r\n if (track) {\r\n track.realtimeDrawnIdx = undefined;\r\n if (track.realtimePoint) {\r\n trackLayer.value?.removeGraphic(track.realtimePoint);\r\n track.realtimePoint = undefined;\r\n }\r\n }\r\n\r\n if (activeRealtimeId.value === targetId) {\r\n activeRealtimeId.value = null;\r\n isRealtimeMode.value = false;\r\n }\r\n }\r\n\r\n // ─── 历史轨迹回放 ─────────────────────────────────────────────────────────\r\n function play(trackId?: string) {\r\n const id = trackId ?? activeTrackId.value;\r\n if (!id) return;\r\n\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track || track.points.length < 2) return;\r\n\r\n if (activeTrackId.value !== id) {\r\n selectTrack(id);\r\n }\r\n\r\n isPlaying.value = true;\r\n _clearPlayInterval();\r\n\r\n const start = track.points[0].time;\r\n const end = track.points[track.points.length - 1].time;\r\n const totalMs = end - start;\r\n\r\n // 进度每帧更新\r\n _playInterval = setInterval(() => {\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (!track || !isPlaying.value) return;\r\n\r\n const elapsed = Date.now() - (track._playStartTime ?? Date.now());\r\n const total = end - start;\r\n const progress = Math.min(elapsed / total, 1);\r\n\r\n // 更新当前时间 → 驱动进度条\r\n currentTime.value = start + progress * total;\r\n playbackProgress.value = progress * 100;\r\n\r\n // 逐步绘制轨迹\r\n const targetIdx = Math.floor(progress * (track.points.length - 1));\r\n _updatePlaybackLine(track, targetIdx);\r\n }, 60);\r\n }\r\n\r\n function _updatePlaybackLine(track: TrackItem, toIdx: number) {\r\n const layer = trackLayer.value;\r\n if (!layer) return;\r\n\r\n // 清除旧线\r\n if (track.lineGraphic) {\r\n layer.removeGraphic(track.lineGraphic);\r\n }\r\n\r\n // 画到 toIdx 位置\r\n const positions = track.points.slice(0, toIdx + 1)\r\n .map((p) => [p.lng, p.lat, p.alt] as [number, number, number]);\r\n\r\n track.lineGraphic = new mars3d.graphic.PolylinePrimitive({\r\n positions,\r\n style: {\r\n color: mars3d.Cesium.Color.fromCssColorString(\"#00ff88\") as any,\r\n width: 4,\r\n opacity: 1,\r\n clampToGround: false,\r\n },\r\n });\r\n layer.addGraphic(track.lineGraphic);\r\n\r\n // 画当前点位\r\n const pt = track.points[toIdx];\r\n mapCtx.map.value?.flyToPoint(\r\n [pt.lng, pt.lat, pt.alt + 200],\r\n { radius: 300, duration: 0 },\r\n );\r\n }\r\n\r\n function pause() {\r\n isPlaying.value = false;\r\n _clearPlayInterval();\r\n }\r\n\r\n function stop() {\r\n isPlaying.value = false;\r\n playbackProgress.value = 0;\r\n currentTime.value = 0;\r\n _clearPlayInterval();\r\n\r\n // 恢复整条轨迹\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (track && trackLayer.value) {\r\n if (track.lineGraphic) trackLayer.value.removeGraphic(track.lineGraphic);\r\n track.lineGraphic = _buildLineGraphic(track);\r\n }\r\n }\r\n\r\n function setSpeed(speed: number) {\r\n playbackSpeed.value = speed;\r\n if (isPlaying.value) {\r\n pause();\r\n play();\r\n }\r\n }\r\n\r\n /** 跳转到指定进度(0~100) */\r\n function seek(progress: number) {\r\n const track = trackList.value.find((t) => t.id === activeTrackId.value);\r\n if (!track) return;\r\n\r\n const targetIdx = Math.floor((progress / 100) * (track.points.length - 1));\r\n currentTime.value = track.points[targetIdx].time;\r\n playbackProgress.value = progress;\r\n _updatePlaybackLine(track, targetIdx);\r\n }\r\n\r\n // ─── 选中轨迹 ─────────────────────────────────────────────────────────────\r\n function selectTrack(id: string) {\r\n activeTrackId.value = id;\r\n stop();\r\n }\r\n\r\n /** 飞行到轨迹概览 */\r\n function flyToTrack(id: string) {\r\n const track = trackList.value.find((t) => t.id === id);\r\n if (!track || !mapCtx.map.value) return;\r\n\r\n const first = track.points[0];\r\n mapCtx.map.value.flyToPoint(\r\n [first.lng, first.lat, first.alt + 2000],\r\n { radius: 3000, duration: 1.5 },\r\n );\r\n }\r\n\r\n // ─── 删除 / 清空 ───────────────────────────────────────────────────────────\r\n function removeTrack(id: string) {\r\n const idx = trackList.value.findIndex((t) => t.id === id);\r\n if (idx === -1) return;\r\n\r\n const track = trackList.value[idx];\r\n if (track.lineGraphic) trackLayer.value?.removeGraphic(track.lineGraphic);\r\n if (track.realtimePoint) trackLayer.value?.removeGraphic(track.realtimePoint);\r\n // 删除实时轨迹的所有线段\r\n if (track.realtimeLineSegments) {\r\n track.realtimeLineSegments.forEach((seg) => {\r\n trackLayer.value?.removeGraphic(seg);\r\n });\r\n }\r\n trackList.value.splice(idx, 1);\r\n\r\n if (activeTrackId.value === id) {\r\n activeTrackId.value = null;\r\n stop();\r\n }\r\n if (activeRealtimeId.value === id) {\r\n activeRealtimeId.value = null;\r\n isRealtimeMode.value = false;\r\n }\r\n }\r\n\r\n function clearAll() {\r\n stop();\r\n stopRealtime();\r\n trackLayer.value?.clear();\r\n trackList.value = [];\r\n activeTrackId.value = null;\r\n }\r\n\r\n // ─── 内部工具 ─────────────────────────────────────────────────────────────\r\n function _clearPlayInterval() {\r\n if (_playInterval) {\r\n clearInterval(_playInterval);\r\n _playInterval = null;\r\n }\r\n }\r\n\r\n return {\r\n trackLayer,\r\n trackList,\r\n activeTrackId,\r\n isPlaying,\r\n currentTime,\r\n playbackSpeed,\r\n playbackProgress,\r\n isRealtimeMode,\r\n activeRealtimeId,\r\n initTrackLayer,\r\n addTrack,\r\n startRealtime,\r\n pushRealtimePoint,\r\n stopRealtime,\r\n play,\r\n pause,\r\n stop,\r\n setSpeed,\r\n seek,\r\n selectTrack,\r\n flyToTrack,\r\n removeTrack,\r\n clearAll,\r\n };\r\n}\r\n\r\nexport type UseTrackReturn = ReturnType<typeof useTrack>;\r\n","<!--\r\n TrackLayer — 轨迹组件逻辑层\r\n\r\n 职责:\r\n - 放置在 MarsMapContainer 的 slot 内(通过 <slot /> 渲染子组件)\r\n - inject mapContext,初始化轨迹图层\r\n - provide trackContext,供子组件 inject 使用\r\n - expose useTrack 全量接口,供父组件 ref 访问\r\n\r\n 使用方式(Panel 必须作为子内容传入):\r\n <MarsMapContainer>\r\n <TrackLayer ref=\"trackLayerRef\">\r\n <TrackPanel />\r\n </TrackLayer>\r\n </MarsMapContainer>\r\n-->\r\n<template>\r\n <slot />\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { inject, provide, watch, onUnmounted } from \"vue\";\r\nimport type { UseMapReturn } from \"../../mars-map/composables/useMap\";\r\nimport { useTrack } from \"./useTrack\";\r\n\r\n// ─── 注入地图上下文 ──────────────────────────────────────────────────────────\r\nconst mapCtx = inject<UseMapReturn>(\"mapContext\");\r\nif (!mapCtx) throw new Error(\"[TrackLayer] 必须放置在 MarsMapContainer 内部\");\r\n\r\n// ─── 初始化轨迹管理 ──────────────────────────────────────────────────────────\r\nconst track = useTrack(mapCtx);\r\n\r\n// ─── 等待地图就绪后初始化图层 ───────────────────────────────────────────────\r\nconst stopWatch = watch(\r\n () => mapCtx.map.value,\r\n (map) => {\r\n if (map) {\r\n track.initTrackLayer();\r\n stopWatch();\r\n }\r\n },\r\n { immediate: true },\r\n);\r\n\r\nonUnmounted(() => {\r\n track.clearAll();\r\n});\r\n\r\n// ─── provide 给子组件 ───────────────────────────────────────────────────────\r\nprovide(\"trackContext\", track);\r\n\r\n// ─── expose 给父组件 ref ───────────────────────────────────────────────────\r\ndefineExpose(track);\r\n</script>\r\n","<!--\r\n TrackPanel — 轨迹管理面板\r\n\r\n 功能:\r\n - 轨迹列表管理(添加历史轨迹 / 实时轨迹)\r\n - 历史轨迹回放控制(播放 / 暂停 / 停止 / 倍速 / 进度拖拽)\r\n - 实时轨迹推送(开始 / 追加模拟点 / 停止)\r\n - 拖拽移动 + 收缩图标态\r\n\r\n 数据来源:inject('trackContext'),由 TrackLayer provide\r\n-->\r\n<template>\r\n <div\r\n class=\"track-panel\"\r\n :class=\"{ collapsed: isCollapsed }\"\r\n :style=\"{ left: pos.x + 'px', top: pos.y + 'px' }\"\r\n >\r\n <!-- 标题栏(可拖拽) -->\r\n <div\r\n class=\"track-panel__header\"\r\n :class=\"{ 'is-dragging': isDragging }\"\r\n @mousedown.prevent=\"startDrag\"\r\n @click=\"isDragging ? null : toggleCollapse()\"\r\n >\r\n <template v-if=\"isCollapsed\">\r\n <div class=\"collapsed-icon-wrap\">\r\n <i class=\"fa fa-share-alt collapsed-icon\" />\r\n <span class=\"track-badge\">{{ track.trackList.value.length }}</span>\r\n </div>\r\n </template>\r\n <template v-else>\r\n <span class=\"track-panel__title\">\r\n <i class=\"fa fa-share-alt\" />\r\n 轨迹管理\r\n <span class=\"track-count\">{{ track.trackList.value.length }}</span>\r\n </span>\r\n <i class=\"fa fa-chevron-left collapse-icon\" />\r\n </template>\r\n </div>\r\n\r\n <!-- 面板体 -->\r\n <div class=\"track-panel__body\" v-show=\"!isCollapsed\">\r\n <!-- ── 操作栏 ── -->\r\n <div class=\"track-panel__toolbar\">\r\n <button class=\"btn btn--primary\" @click=\"addDemoTrack\">\r\n <i class=\"fa fa-plus\" /> 历史轨迹\r\n </button>\r\n <button\r\n class=\"btn\"\r\n :class=\"track.isRealtimeMode.value ? 'btn--active' : 'btn--info'\"\r\n @click=\"toggleRealtime\"\r\n >\r\n <i\r\n :class=\"['fa', track.isRealtimeMode.value ? 'fa-stop' : 'fa-bolt']\"\r\n />\r\n {{ track.isRealtimeMode.value ? \"停止推送\" : \"实时轨迹\" }}\r\n </button>\r\n <button\r\n class=\"btn btn--danger\"\r\n @click=\"confirmClear\"\r\n :disabled=\"track.trackList.value.length === 0\"\r\n >\r\n <i class=\"fa fa-trash-o\" />\r\n </button>\r\n </div>\r\n\r\n <!-- ── 回放控制(选中轨迹时显示) ── -->\r\n <div class=\"track-panel__playback\" v-if=\"track.activeTrackId.value\">\r\n <!-- 轨迹名称 -->\r\n <div class=\"playback__track-name\">\r\n <i class=\"fa fa-road\" />\r\n {{ activeTrackName }}\r\n <span class=\"playback__mode-badge\">历史回放</span>\r\n </div>\r\n\r\n <!-- 播放按钮组 -->\r\n <div class=\"playback__controls\">\r\n <button class=\"ctrl-btn\" @click=\"track.stop()\">\r\n <i class=\"fa fa-stop\" />\r\n </button>\r\n <button\r\n class=\"ctrl-btn ctrl-btn--play\"\r\n @click=\"track.isPlaying.value ? track.pause() : track.play()\"\r\n >\r\n <i\r\n :class=\"['fa', track.isPlaying.value ? 'fa-pause' : 'fa-play']\"\r\n />\r\n </button>\r\n <button class=\"ctrl-btn\" @click=\"track.play()\">\r\n <i class=\"fa fa-refresh\" />\r\n </button>\r\n </div>\r\n\r\n <!-- 倍速选择 -->\r\n <div class=\"playback__speed\">\r\n <span class=\"speed-label\">倍速</span>\r\n <div class=\"speed-btns\">\r\n <button\r\n v-for=\"s in speedOptions\"\r\n :key=\"s\"\r\n class=\"speed-btn\"\r\n :class=\"{ active: track.playbackSpeed.value === s }\"\r\n @click=\"track.setSpeed(s)\"\r\n >\r\n {{ s }}x\r\n </button>\r\n </div>\r\n </div>\r\n\r\n <!-- 进度条 -->\r\n <div class=\"playback__timeline\">\r\n <span class=\"time-label\">{{\r\n formatTime(track.currentTime.value)\r\n }}</span>\r\n <input\r\n type=\"range\"\r\n class=\"progress-slider\"\r\n min=\"0\"\r\n max=\"100\"\r\n step=\"0.1\"\r\n :value=\"track.playbackProgress.value\"\r\n @input=\"onSeek\"\r\n />\r\n <span class=\"time-label\">{{ formatTime(trackMaxTime) }}</span>\r\n </div>\r\n </div>\r\n\r\n <!-- ── 实时模式指示 ── -->\r\n <div\r\n class=\"track-panel__realtime-hint\"\r\n v-if=\"track.isRealtimeMode.value && !track.activeTrackId.value\"\r\n >\r\n <div class=\"realtime-pulse\">\r\n <i class=\"fa fa-bolt\" />\r\n 实时推送中\r\n <span class=\"blink-dot\" />\r\n </div>\r\n <div class=\"realtime-count\">\r\n 已推送 <strong>{{ realtimePointCount }}</strong> 个坐标点\r\n </div>\r\n </div>\r\n\r\n <!-- ── 轨迹列表 ── -->\r\n <div class=\"track-panel__list\">\r\n <TransitionGroup name=\"track-list\">\r\n <div\r\n v-for=\"item in track.trackList.value\"\r\n :key=\"item.id\"\r\n class=\"track-item\"\r\n :class=\"{\r\n 'track-item--active': track.activeTrackId.value === item.id,\r\n 'track-item--realtime': item.id.startsWith('realtime'),\r\n }\"\r\n @click=\"onSelectTrack(item.id)\"\r\n >\r\n <!-- 颜色条 -->\r\n <span\r\n class=\"track-item__bar\"\r\n :style=\"{\r\n background: item.id.startsWith('realtime')\r\n ? '#ff6b35'\r\n : '#3ea6ff',\r\n }\"\r\n />\r\n\r\n <div class=\"track-item__info\">\r\n <div class=\"track-item__name\">\r\n <i\r\n :class=\"[\r\n 'fa',\r\n item.id.startsWith('realtime') ? 'fa-bolt' : 'fa-road',\r\n ]\"\r\n />\r\n {{ item.name }}\r\n </div>\r\n <div class=\"track-item__meta\">\r\n {{ item.points.length }} 个点\r\n <span v-if=\"item.id.startsWith('realtime')\" class=\"realtime-tag\"\r\n >实时</span\r\n >\r\n </div>\r\n </div>\r\n\r\n <div class=\"track-item__actions\">\r\n <button\r\n class=\"icon-btn\"\r\n title=\"飞行\"\r\n @click.stop=\"track.flyToTrack(item.id)\"\r\n >\r\n <i class=\"fa fa-crosshairs\" />\r\n </button>\r\n <button\r\n class=\"icon-btn icon-btn--danger\"\r\n title=\"删除\"\r\n @click.stop=\"track.removeTrack(item.id)\"\r\n >\r\n <i class=\"fa fa-times\" />\r\n </button>\r\n </div>\r\n </div>\r\n </TransitionGroup>\r\n\r\n <!-- 空状态 -->\r\n <div\r\n v-if=\"track.trackList.value.length === 0\"\r\n class=\"track-panel__empty\"\r\n >\r\n <i class=\"fa fa-map-o\" />\r\n <p>暂无轨迹数据</p>\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<script setup lang=\"ts\">\r\nimport { ref, computed, inject, reactive } from \"vue\";\r\nimport type { UseTrackReturn } from \"./useTrack\";\r\n\r\n// ─── 注入轨迹上下文 ──────────────────────────────────────────────────────────\r\nconst track = inject<UseTrackReturn>(\"trackContext\");\r\nif (!track) throw new Error(\"[TrackPanel] 必须与 TrackLayer 同级使用\");\r\n\r\n// ─── 拖拽 ──────────────────────────────────────────────────────────────────\r\nconst isCollapsed = ref(true);\r\nconst isDragging = ref(false);\r\nconst pos = reactive({ x: 10, y: 80 }); // 默认错开 POI 面板\r\n\r\nlet dragStartX = 0,\r\n dragStartY = 0,\r\n origX = 0,\r\n origY = 0;\r\n\r\nfunction toggleCollapse() {\r\n isCollapsed.value = !isCollapsed.value;\r\n}\r\n\r\nfunction startDrag(e: MouseEvent) {\r\n isDragging.value = true;\r\n dragStartX = e.clientX;\r\n dragStartY = e.clientY;\r\n origX = pos.x;\r\n origY = pos.y;\r\n document.addEventListener(\"mousemove\", onDrag);\r\n document.addEventListener(\"mouseup\", stopDrag);\r\n}\r\nfunction onDrag(e: MouseEvent) {\r\n if (!isDragging.value) return;\r\n pos.x = origX + (e.clientX - dragStartX);\r\n pos.y = origY + (e.clientY - dragStartY);\r\n}\r\nfunction stopDrag() {\r\n isDragging.value = false;\r\n document.removeEventListener(\"mousemove\", onDrag);\r\n document.removeEventListener(\"mouseup\", stopDrag);\r\n}\r\n\r\n// ─── 选中轨迹 ──────────────────────────────────────────────────────────────\r\nfunction onSelectTrack(id: string) {\r\n if (track.activeTrackId.value === id) return;\r\n track.selectTrack(id);\r\n track.stop();\r\n}\r\n\r\nconst activeTrackName = computed(() => {\r\n const t = track.trackList.value.find(\r\n (x) => x.id === track.activeTrackId.value,\r\n );\r\n return t?.name ?? \"\";\r\n});\r\n\r\nconst trackMaxTime = computed(() => {\r\n const t = track.trackList.value.find(\r\n (x) => x.id === track.activeTrackId.value,\r\n );\r\n if (!t || t.points.length < 2) return 0;\r\n return t.points[t.points.length - 1].time;\r\n});\r\n\r\n// ─── 倍速选项 ──────────────────────────────────────────────────────────────\r\nconst speedOptions = [1, 2, 4, 8];\r\n\r\n// ─── 进度拖拽 ─────────────────────────────────────────────────────────────\r\nfunction onSeek(e: Event) {\r\n const val = parseFloat((e.target as HTMLInputElement).value);\r\n track.seek(val);\r\n}\r\n\r\n// ─── 时间格式化 ────────────────────────────────────────────────────────────\r\nfunction formatTime(ts: number): string {\r\n if (!ts) return \"00:00\";\r\n const d = new Date(ts);\r\n return `${String(d.getMinutes()).padStart(2, \"0\")}:${String(d.getSeconds()).padStart(2, \"0\")}`;\r\n}\r\n\r\n// ─── 添加演示历史轨迹 ─────────────────────────────────────────────────────\r\nfunction addDemoTrack() {\r\n // 生成一段北京区域贴近实际的路径:方向惯性 + 高度随路线起伏\r\n const baseLng = 116.3974;\r\n const baseLat = 39.909;\r\n const points = [];\r\n let t = Date.now();\r\n\r\n // 初始方向角(弧度)\r\n let heading = Math.random() * Math.PI * 2;\r\n const STEP = 20; // 减少到 20 个点\r\n\r\n for (let i = 0; i < STEP; i++) {\r\n t += 5000 + Math.random() * 5000;\r\n // 方向每步微调 ±15°,模拟沿道路行驶\r\n heading += (Math.random() - 0.5) * (Math.PI / 6);\r\n const stepLng = baseLng + Math.cos(heading) * 0.004;\r\n const stepLat = baseLat + Math.sin(heading) * 0.002;\r\n const alt = 30 + Math.sin((i / STEP) * Math.PI) * 80; // 拱形起伏\r\n points.push({ time: t, lng: stepLng, lat: stepLat, alt });\r\n }\r\n\r\n track.addTrack(points, `轨迹 ${_counter++}`);\r\n}\r\n\r\nlet _counter = 1;\r\n\r\n// ─── 实时轨迹 ─────────────────────────────────────────────────────────────\r\nlet _realtimeTimer: ReturnType<typeof setInterval> | null = null;\r\nlet _currentRealtimeId: string | null = null;\r\n\r\nfunction toggleRealtime() {\r\n if (track.isRealtimeMode.value) {\r\n stopRealtime();\r\n } else {\r\n startRealtime();\r\n }\r\n}\r\n\r\nfunction startRealtime() {\r\n const id = track.startRealtime(`实时轨迹 ${_counter++}`)?.id;\r\n if (!id) return;\r\n _currentRealtimeId = id;\r\n\r\n // 天安门坐标(圆心)\r\n const CENTER_LNG = 116.397;\r\n const CENTER_LAT = 39.908;\r\n // 绕圈半径(约 400 米)\r\n const RADIUS_LNG = 0.004;\r\n const RADIUS_LAT = 0.003;\r\n // 总共 36 个点,每 10° 一个点,完成一圈\r\n const TOTAL_POINTS = 36;\r\n const ANGLE_STEP = (2 * Math.PI) / TOTAL_POINTS;\r\n // 初始角度随机,让起点不在固定位置\r\n let angle = Math.random() * 2 * Math.PI;\r\n let pushCount = 0;\r\n\r\n _realtimeTimer = setInterval(() => {\r\n pushCount++;\r\n // 沿圆形轨迹移动\r\n const lng = CENTER_LNG + Math.cos(angle) * RADIUS_LNG;\r\n const lat = CENTER_LAT + Math.sin(angle) * RADIUS_LAT;\r\n const alt = 40 + Math.sin(angle * 3) * 20; // 高度随位置微微起伏\r\n track.pushRealtimePoint(id, lng, lat, alt);\r\n\r\n // 角度递增,绘制下一位置\r\n angle += ANGLE_STEP;\r\n\r\n // 完成一圈后自动停止\r\n if (pushCount >= TOTAL_POINTS) {\r\n stopRealtime();\r\n }\r\n }, 800);\r\n}\r\n\r\nfunction stopRealtime() {\r\n if (_realtimeTimer) {\r\n clearInterval(_realtimeTimer);\r\n _realtimeTimer = null;\r\n }\r\n if (_currentRealtimeId) {\r\n track.stopRealtime(_currentRealtimeId);\r\n _currentRealtimeId = null;\r\n }\r\n}\r\n\r\nconst realtimePointCount = computed(() => {\r\n const t = track.trackList.value.find((x) => x.id === _currentRealtimeId);\r\n return t?.points.length ?? 0;\r\n});\r\n\r\n// ─── 清空 ─────────────────────────────────────────────────────────────────\r\nfunction confirmClear() {\r\n if (window.confirm(`确认清空全部 ${track.trackList.value.length} 条轨迹?`)) {\r\n stopRealtime();\r\n track.clearAll();\r\n }\r\n}\r\n</script>\r\n\r\n<style lang=\"less\" scoped>\r\n// ─── 主面板 ─────────────────────────────────────────────────────────────────\r\n.track-panel {\r\n position: absolute;\r\n width: 280px;\r\n height: auto;\r\n max-height: calc(100vh - 40px);\r\n background: rgba(23, 35, 50, 0.92);\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n border-radius: 6px;\r\n z-index: 998;\r\n display: flex;\r\n flex-direction: column;\r\n backdrop-filter: blur(4px);\r\n transition: width 0.25s ease;\r\n\r\n &.collapsed {\r\n width: 46px;\r\n max-height: none;\r\n overflow: hidden;\r\n\r\n .track-panel__title {\r\n display: none;\r\n }\r\n .track-panel__body {\r\n display: none;\r\n }\r\n .collapse-icon {\r\n display: none;\r\n }\r\n }\r\n}\r\n\r\n// ─── 标题栏 ────────────────────────────────────────────────────────────────\r\n.track-panel__header {\r\n position: relative;\r\n display: flex;\r\n align-items: center;\r\n justify-content: space-between;\r\n padding: 12px 14px;\r\n background: rgba(15, 25, 40, 0.9);\r\n border-radius: 6px 6px 0 0;\r\n cursor: grab;\r\n user-select: none;\r\n flex-shrink: 0;\r\n\r\n &.is-dragging {\r\n cursor: grabbing;\r\n }\r\n\r\n .collapsed-icon {\r\n display: none;\r\n color: #ff6b35;\r\n font-size: 18px;\r\n }\r\n\r\n .track-panel__title {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #e8f4ff;\r\n font-size: 14px;\r\n font-weight: 600;\r\n .fa {\r\n color: #ff6b35;\r\n font-size: 15px;\r\n }\r\n }\r\n\r\n // 展开态角标(红色)\r\n .track-count {\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 11px;\r\n padding: 1px 6px;\r\n border-radius: 10px;\r\n min-width: 18px;\r\n text-align: center;\r\n }\r\n\r\n .collapse-icon {\r\n color: #7a9ec0;\r\n font-size: 12px;\r\n }\r\n}\r\n\r\n// 收缩态\r\n.track-panel.collapsed .track-panel__header {\r\n flex-direction: column;\r\n align-items: flex-start; // 左对齐\r\n padding: 8px 10px 10px; // 底部留更多空间\r\n gap: 0;\r\n cursor: pointer;\r\n\r\n // 图标 + 角标一体化容器,图标在左下,角标叠在图标右上\r\n .collapsed-icon-wrap {\r\n position: relative;\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n margin-top: 12px; // 往下一点\r\n margin-left: 2px; // 往左一点\r\n }\r\n\r\n .collapsed-icon {\r\n display: block;\r\n color: #ff6b35;\r\n font-size: 18px;\r\n }\r\n\r\n // 角标:相对于图标容器定位,落在图标右上角\r\n .track-badge {\r\n position: absolute;\r\n top: -12px;\r\n right: -12px;\r\n background: #e74c3c;\r\n color: #fff;\r\n font-size: 10px;\r\n font-weight: 600;\r\n min-width: 16px;\r\n height: 16px;\r\n line-height: 16px;\r\n text-align: center;\r\n border-radius: 8px;\r\n padding: 0 3px;\r\n }\r\n}\r\n\r\n// ─── 面板体 ────────────────────────────────────────────────────────────────\r\n.track-panel__body {\r\n display: flex;\r\n flex-direction: column;\r\n overflow: hidden;\r\n}\r\n\r\n// ─── 操作栏 ───────────────────────────────────────────────────────────────\r\n.track-panel__toolbar {\r\n display: flex;\r\n gap: 6px;\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .btn {\r\n flex: 1;\r\n padding: 5px 8px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 4px;\r\n font-size: 12px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 5px;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.25);\r\n color: #fff;\r\n }\r\n &--active {\r\n background: rgba(255, 100, 50, 0.35);\r\n color: #ffaa88;\r\n border-color: #ff6b35;\r\n }\r\n &--primary {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #fff;\r\n border-color: rgba(62, 166, 255, 0.6);\r\n }\r\n &--info {\r\n background: rgba(255, 107, 53, 0.2);\r\n color: #ffaa88;\r\n border-color: rgba(255, 107, 53, 0.5);\r\n }\r\n &--danger {\r\n flex: 0 0 auto;\r\n width: 36px;\r\n border-color: rgba(255, 80, 80, 0.4);\r\n background: rgba(255, 80, 80, 0.1);\r\n color: #ffaaaa;\r\n &:hover:not(:disabled) {\r\n background: rgba(255, 80, 80, 0.25);\r\n color: #fff;\r\n }\r\n &:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 回放控制 ─────────────────────────────────────────────────────────────\r\n.track-panel__playback {\r\n padding: 10px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n\r\n .playback__track-name {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-size: 12px;\r\n color: #9dc8f0;\r\n margin-bottom: 8px;\r\n\r\n .fa {\r\n color: #00ff88;\r\n }\r\n .playback__mode-badge {\r\n background: rgba(0, 255, 136, 0.15);\r\n color: #00ff88;\r\n font-size: 10px;\r\n padding: 1px 6px;\r\n border-radius: 8px;\r\n margin-left: 4px;\r\n }\r\n }\r\n\r\n // 播放按钮组\r\n .playback__controls {\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n gap: 8px;\r\n margin-bottom: 8px;\r\n }\r\n\r\n // 单独控制按钮\r\n .ctrl-btn {\r\n width: 30px;\r\n height: 30px;\r\n border: 1px solid rgba(62, 166, 255, 0.4);\r\n background: rgba(62, 166, 255, 0.1);\r\n color: #9dc8f0;\r\n border-radius: 50%;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 12px;\r\n transition: all 0.2s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n\r\n &--play {\r\n width: 38px;\r\n height: 38px;\r\n background: rgba(0, 200, 100, 0.2);\r\n border-color: rgba(0, 200, 100, 0.6);\r\n color: #00ff88;\r\n font-size: 15px;\r\n &:hover {\r\n background: rgba(0, 200, 100, 0.35);\r\n }\r\n }\r\n }\r\n\r\n // 倍速\r\n .playback__speed {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n margin-bottom: 8px;\r\n\r\n .speed-label {\r\n font-size: 11px;\r\n color: #5a7a9a;\r\n }\r\n .speed-btns {\r\n display: flex;\r\n gap: 4px;\r\n }\r\n .speed-btn {\r\n padding: 2px 7px;\r\n border: 1px solid rgba(62, 166, 255, 0.3);\r\n background: rgba(255, 255, 255, 0.04);\r\n color: #7a9ec0;\r\n border-radius: 10px;\r\n font-size: 11px;\r\n cursor: pointer;\r\n transition: all 0.2s;\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.2);\r\n color: #fff;\r\n }\r\n &.active {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #3ea6ff;\r\n border-color: #3ea6ff;\r\n }\r\n }\r\n }\r\n\r\n // 进度条\r\n .playback__timeline {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n\r\n .time-label {\r\n font-size: 10px;\r\n color: #5a7a9a;\r\n font-family: monospace;\r\n min-width: 36px;\r\n text-align: center;\r\n }\r\n\r\n .progress-slider {\r\n flex: 1;\r\n height: 4px;\r\n -webkit-appearance: none;\r\n appearance: none;\r\n background: rgba(62, 166, 255, 0.2);\r\n border-radius: 2px;\r\n outline: none;\r\n cursor: pointer;\r\n\r\n &::-webkit-slider-thumb {\r\n -webkit-appearance: none;\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 50%;\r\n background: #3ea6ff;\r\n cursor: pointer;\r\n box-shadow: 0 0 6px rgba(62, 166, 255, 0.6);\r\n }\r\n\r\n &::-moz-range-thumb {\r\n width: 12px;\r\n height: 12px;\r\n border-radius: 50%;\r\n background: #3ea6ff;\r\n border: none;\r\n cursor: pointer;\r\n }\r\n }\r\n }\r\n}\r\n\r\n// ─── 实时模式提示 ──────────────────────────────────────────────────────────\r\n.track-panel__realtime-hint {\r\n padding: 8px 12px;\r\n border-bottom: 1px solid rgba(255, 255, 255, 0.07);\r\n display: flex;\r\n flex-direction: column;\r\n gap: 4px;\r\n\r\n .realtime-pulse {\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n font-size: 12px;\r\n color: #ff6b35;\r\n .fa {\r\n color: #ff6b35;\r\n }\r\n }\r\n\r\n .blink-dot {\r\n width: 6px;\r\n height: 6px;\r\n border-radius: 50%;\r\n background: #ff6b35;\r\n animation: blink 1s ease-in-out infinite;\r\n }\r\n\r\n .realtime-count {\r\n font-size: 11px;\r\n color: #7a9ec0;\r\n strong {\r\n color: #ff6b35;\r\n }\r\n }\r\n}\r\n\r\n@keyframes blink {\r\n 0%,\r\n 100% {\r\n opacity: 1;\r\n }\r\n 50% {\r\n opacity: 0.2;\r\n }\r\n}\r\n\r\n// ─── 轨迹列表 ─────────────────────────────────────────────────────────────\r\n.track-panel__list {\r\n overflow-y: auto;\r\n max-height: calc(100vh - 340px);\r\n padding: 6px 0;\r\n\r\n &::-webkit-scrollbar {\r\n width: 4px;\r\n }\r\n &::-webkit-scrollbar-thumb {\r\n background: rgba(62, 166, 255, 0.3);\r\n border-radius: 2px;\r\n }\r\n}\r\n\r\n.track-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 10px;\r\n padding: 8px 12px;\r\n cursor: pointer;\r\n transition: background 0.15s;\r\n\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.1);\r\n }\r\n &--active {\r\n background: rgba(62, 166, 255, 0.18);\r\n }\r\n &--realtime .track-item__bar {\r\n background: #ff6b35 !important;\r\n }\r\n\r\n &__bar {\r\n width: 3px;\r\n height: 30px;\r\n border-radius: 2px;\r\n background: #3ea6ff;\r\n flex-shrink: 0;\r\n }\r\n\r\n &__info {\r\n flex: 1;\r\n min-width: 0;\r\n }\r\n\r\n &__name {\r\n overflow: hidden;\r\n font-size: 13px;\r\n color: #ffffff;\r\n white-space: nowrap;\r\n text-overflow: ellipsis;\r\n display: flex;\r\n align-items: center;\r\n gap: 5px;\r\n .fa {\r\n color: #8ab4d4;\r\n font-size: 12px;\r\n }\r\n }\r\n\r\n &__meta {\r\n font-size: 11px;\r\n color: #9dc8f0;\r\n margin-top: 2px;\r\n display: flex;\r\n align-items: center;\r\n gap: 6px;\r\n }\r\n\r\n .realtime-tag {\r\n background: rgba(255, 107, 53, 0.2);\r\n color: #ff6b35;\r\n font-size: 10px;\r\n padding: 0 5px;\r\n border-radius: 6px;\r\n }\r\n\r\n &__actions {\r\n display: flex;\r\n gap: 4px;\r\n flex-shrink: 0;\r\n opacity: 0;\r\n transition: opacity 0.15s;\r\n }\r\n\r\n &:hover &__actions {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.icon-btn {\r\n width: 22px;\r\n height: 22px;\r\n border: none;\r\n background: rgba(255, 255, 255, 0.08);\r\n color: #9dc8f0;\r\n border-radius: 3px;\r\n cursor: pointer;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n font-size: 11px;\r\n transition: all 0.15s;\r\n &:hover {\r\n background: rgba(62, 166, 255, 0.3);\r\n color: #fff;\r\n }\r\n &--danger:hover {\r\n background: rgba(255, 80, 80, 0.35);\r\n color: #fff;\r\n }\r\n}\r\n\r\n// ─── 空状态 ────────────────────────────────────────────────────────────────\r\n.track-panel__empty {\r\n text-align: center;\r\n padding: 30px 20px;\r\n color: #4a6a8a;\r\n .fa {\r\n font-size: 32px;\r\n margin-bottom: 10px;\r\n display: block;\r\n }\r\n p {\r\n font-size: 12px;\r\n margin: 0;\r\n }\r\n}\r\n\r\n// ─── 列表动画 ──────────────────────────────────────────────────────────────\r\n.track-list-enter-active,\r\n.track-list-leave-active {\r\n transition: all 0.25s ease;\r\n}\r\n.track-list-enter-from {\r\n opacity: 0;\r\n transform: translateX(-12px);\r\n}\r\n.track-list-leave-to {\r\n opacity: 0;\r\n transform: translateX(12px);\r\n}\r\n</style>\r\n","/**\r\n * Mars3D Vue3 Components - 统一导出入口\r\n *\r\n * @description 封装了 Mars3D 地图的基础能力(测量、绘制、视角控制)\r\n * 及业务组件(POI 标注、轨迹管理)的 Vue3 组件库\r\n *\r\n * @example\r\n * // 完整引入\r\n * import Mars3dVueComponents from '@your-org/mars3d-vue-components'\r\n * app.use(Mars3dVueComponents)\r\n *\r\n * // 按需引入\r\n * import { MarsMapContainer, useMap } from '@your-org/mars3d-vue-components'\r\n *\r\n * // 样式导入(如果 CSS 未内联)\r\n * import '@your-org/mars3d-vue-components/dist/yi-map-web.css';\r\n */\r\n\r\n// 注意:CSS 样式已移至 ./styles/index.css\r\n// 组件库打包时会自动提取 CSS 到单独文件\r\n// 消费项目可以通过以下方式引入样式:\r\n// import 'yi-map-web/dist/yi-map-web.css';\r\n// 或\r\n// import 'yi-map-web/styles'; // 直接导入源样式文件\r\n\r\n// ── 基础组件 ──────────────────────────────────────────────────────────────────\r\nexport { default as MarsMapContainer } from \"./components/mars-map/MarsMapContainer.vue\";\r\nexport { default as ToolbarPanel } from \"./components/mars-map/panels/ToolbarPanel.vue\";\r\nexport { default as VisionPanel } from \"./components/mars-map/panels/VisionPanel.vue\";\r\n\r\n// ── Composables ────────────────────────────────────────────────────────────────\r\nexport { useMap } from \"./components/mars-map/composables/useMap\";\r\nexport { useMeasure } from \"./components/mars-map/composables/useMeasure\";\r\nexport { useDraw } from \"./components/mars-map/composables/useDraw\";\r\nexport { useVision } from \"./components/mars-map/composables/useVision\";\r\n\r\n// ── 业务组件 ──────────────────────────────────────────────────────────────────\r\nexport { default as PoiMarkerLayer } from \"./components/business/poi-marker/PoiMarkerLayer.vue\";\r\nexport { default as PoiMarkerPanel } from \"./components/business/poi-marker/PoiMarkerPanel.vue\";\r\nexport { default as TrackLayer } from \"./components/business/track/TrackLayer.vue\";\r\nexport { default as TrackPanel } from \"./components/business/track/TrackPanel.vue\";\r\n\r\n// ── 业务 Composable ───────────────────────────────────────────────────────────\r\nexport { usePoiMarker } from \"./components/business/poi-marker/usePoiMarker\";\r\nexport { useTrack } from \"./components/business/track/useTrack\";\r\n\r\n// ── 类型导出 ─────────────────────────────────────────────────────────────────\r\nexport type { UseMapReturn } from \"./components/mars-map/composables/useMap\";\r\nexport type { DrawType } from \"./components/mars-map/composables/useDraw\";\r\nexport type {\r\n PoiItem,\r\n UsePoiMarkerReturn,\r\n} from \"./components/business/poi-marker/usePoiMarker\";\r\nexport type {\r\n TrackPoint,\r\n TrackItem,\r\n UseTrackReturn,\r\n} from \"./components/business/track/useTrack\";\r\n\r\n// ── 安装插件(完整引入时使用)─────────────────────────────────────────────────\r\nimport type { App, Component } from \"vue\";\r\nimport MarsMapContainer from \"./components/mars-map/MarsMapContainer.vue\";\r\nimport ToolbarPanel from \"./components/mars-map/panels/ToolbarPanel.vue\";\r\nimport VisionPanel from \"./components/mars-map/panels/VisionPanel.vue\";\r\nimport PoiMarkerLayer from \"./components/business/poi-marker/PoiMarkerLayer.vue\";\r\nimport PoiMarkerPanel from \"./components/business/poi-marker/PoiMarkerPanel.vue\";\r\nimport TrackLayer from \"./components/business/track/TrackLayer.vue\";\r\nimport TrackPanel from \"./components/business/track/TrackPanel.vue\";\r\n\r\nconst components: Record<string, Component> = {\r\n MarsMapContainer,\r\n ToolbarPanel,\r\n VisionPanel,\r\n PoiMarkerLayer,\r\n PoiMarkerPanel,\r\n TrackLayer,\r\n TrackPanel,\r\n};\r\n\r\nconst YiMapWeb = {\r\n install(app: App, options?: { prefix?: string }) {\r\n const prefix = options?.prefix ?? \"\";\r\n for (const [name, component] of Object.entries(components)) {\r\n app.component(prefix ? `${prefix}${name}` : name, component);\r\n }\r\n },\r\n};\r\n\r\nexport default YiMapWeb;\r\n"],"names":["_createElementBlock","_normalizeClass","_createElementVNode","_withDirectives","_hoisted_1","_hoisted_2","_Fragment","_renderList","_hoisted_4","_createVNode","_Transition","_openBlock","_hoisted_3","_toDisplayString","MarsMap","_createBlock","_unref","_renderSlot","_idCounter","_normalizeStyle","_hoisted_5","_hoisted_6","_createTextVNode","_hoisted_8","_hoisted_10","_TransitionGroup","_hoisted_12","_withModifiers","_hoisted_13","_hoisted_14","_hoisted_15","_hoisted_19","track","_a","PoiMarkerLayer","TrackLayer"],"mappings":"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"}