index.vue 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993
  1. <template>
  2. <div class="container">
  3. <el-row id="earth" style="height: 100%; width: 100%; display: flex; position: relative">
  4. <el-col style="height: 100%; position: relative" :span="this.leftwidth">
  5. <div class="main-layout" v-on:mouseover="changeActive('2D')" @mousemove="getMouseLocation">
  6. <div id="2DcesiumContainer" class="map" @click="onMapClick"></div>
  7. </div>
  8. </el-col>
  9. <el-col style="height: 100%; position: relative" :span="24 - this.leftwidth">
  10. <div class="main-layout" v-on:mouseover="changeActive('3D')" @mousemove="getMouseLocation">
  11. <div id="3DcesiumContainer" class="map" @click="onMapClick"></div>
  12. </div>
  13. </el-col>
  14. <el-tabs type="border-card" v-model="activeName" tab-position="left" class="menu" :stretch="true"
  15. @tab-click="legendClick">
  16. <el-tab-pane name="fouth">
  17. <el-tooltip placement="right" effect="light" slot="label">
  18. <span slot="content" class="item">想定</span>
  19. <span><i class="el-icon-house"></i></span>
  20. </el-tooltip>
  21. <el-table :data="situation">
  22. <el-table-column label="名称" prop="xdname" width="150px"></el-table-column>
  23. <el-table-column label="操作" align="center">
  24. <template slot-scope="scope">
  25. <el-button type="primary" @click="getJson(scope.row)">导入</el-button>
  26. <!-- <el-button type="primary" @click="saveJson()">保存</el-button> -->
  27. </template>
  28. </el-table-column>
  29. </el-table>
  30. </el-tab-pane>
  31. </el-tabs>
  32. <div class="buttons">
  33. <el-button icon="el-icon-full-screen" circle @click="ismax()"></el-button>
  34. <el-button icon="el-icon-house" circle @click="home()"></el-button>
  35. <el-button icon="el-icon-plus" circle @click="big()"></el-button>
  36. <el-button icon="el-icon-minus" circle @click="small()"></el-button>
  37. </div>
  38. </el-row>
  39. <!-- <TimeLine :showLayers="showLayers" :timeDataArray="timeDataArray" class="TimeLine"></TimeLine> -->
  40. </div>
  41. </template>
  42. <script>
  43. import screenfull from "screenfull";
  44. import fireController from "@/api/fireController.js";
  45. import { getToken } from "@/utils";
  46. import axios from "axios";
  47. import satelliteModel from '@/assets/model/satelite.glb';
  48. import TimeLine from '@/components/TimeLine/index.vue';
  49. import missileModel from '@/assets/model/basic_missle.glb';
  50. import thaadModel from '@/assets/model/anti-aircraft_gun_fire_control_radar_vehicle.glb';
  51. import centerModel from '@/assets/model/the_white_house.glb';
  52. import radarModel from '@/assets/model/radar.glb'
  53. import { mapGetters } from "vuex";
  54. export default {
  55. components: {
  56. TimeLine
  57. },
  58. computed: {
  59. ...mapGetters([
  60. "dimension"
  61. ])
  62. },
  63. data() {
  64. return {
  65. save: false,
  66. situation: [],
  67. nameIdList: [],
  68. websocket: null,
  69. leftwidth: 12,
  70. unit: [],
  71. satellite: [],
  72. center: [],
  73. move_data: {},
  74. viewer2D: null,
  75. viewer3D: null,
  76. mousevalue: null,
  77. // 选中的点
  78. selectedMarker: null,
  79. // 以前的标记点坐标
  80. oldPosition: null,
  81. activeName: 'fouth',
  82. currentLab: {
  83. index: -1,
  84. isActive: false
  85. },
  86. url: "https://fuss10.elemecdn.com/e/5d/4a731a90594a4af544c0c25941171jpeg.jpeg",
  87. isShow: false,
  88. handler3D: null,
  89. handler2D: null,
  90. image: null,
  91. modeltooltip: null,
  92. id: 1,
  93. showLayers: null,
  94. timeDataArray: ['Time 1', 'Time 2', 'Time 3', 'Time 4'],
  95. jsonData: null
  96. };
  97. },
  98. watch: {
  99. dimension: {
  100. handler: function (val, oldVal) {
  101. console.log(val)
  102. if (val == 2) {
  103. this.leftwidth = 24;
  104. } else if (val == 3) {
  105. this.leftwidth = 0;
  106. } else if (val == 5) {
  107. this.leftwidth = 12;
  108. }
  109. },
  110. },
  111. },
  112. created() {
  113. this.getData();
  114. },
  115. mounted() {
  116. this.cesiumInit();
  117. // this.pointMove();
  118. // this.startWebSocket();
  119. },
  120. beforeDestroy() {
  121. // 在组件销毁前,关闭WebSocket连接
  122. if (this.websocket && this.websocket.readyState === WebSocket.OPEN) {
  123. this.websocket.close();
  124. }
  125. this.viewer2D.clock.onTick.removeEventListener(this.handleTimeChange);
  126. this.viewer3D.clock.onTick.removeEventListener(this.handleTimeChange);
  127. },
  128. methods: {
  129. startWebSocket() {
  130. this.websocket = new WebSocket('ws://localhost:8765');
  131. this.websocket.onopen = () => {
  132. console.log('WebSocket连接已建立!');
  133. };
  134. this.websocket.onmessage = (event) => {
  135. // 处理从WebSocket服务器接收到的消息
  136. const data = JSON.parse(event.data);
  137. console.log('收到消息:', data);
  138. // 在这里处理接收到的数据,更新Vue组件的数据等操作
  139. };
  140. this.websocket.onerror = (error) => {
  141. console.error('WebSocket错误:', error);
  142. };
  143. this.websocket.onclose = () => {
  144. console.log('WebSocket连接已关闭!');
  145. };
  146. },
  147. async saveJson() {
  148. if (this.save) {
  149. const jsonData = JSON.stringify(this.jsonData);
  150. const blob = new Blob([jsonData], { type: 'application/json' });
  151. const url = URL.createObjectURL(blob);
  152. const link = document.createElement('a');
  153. link.href = url;
  154. link.download = this.jsonData.xdname + '.json';
  155. document.body.appendChild(link);
  156. link.click();
  157. document.body.removeChild(link);
  158. }
  159. else {
  160. this.$message("请先导入想定文件!!!")
  161. }
  162. },
  163. changeItemPosition(data) {
  164. },
  165. async getJson(row) {
  166. let redunit = [];
  167. let blueunit = [];
  168. let satellite = [];
  169. let center = [];
  170. let fileInfoStr = row.xdfile;
  171. let fileInfoArr = JSON.parse(fileInfoStr);
  172. await axios
  173. .get("http://localhost:8084/admin/online/onlineOperation/downloadDatasource/main", {
  174. params: {
  175. datasourceId: "1656243335922192384",
  176. fieldName: "xdfile",
  177. asImage: false,
  178. dataId: row.id,
  179. filename: fileInfoArr[0].filename,
  180. Authorization: getToken(),
  181. MenuId: "1656244747347431424"
  182. }
  183. })
  184. .then((response) => {
  185. console.log('response.data :>> ', response.data);
  186. // // 处理成功的响应
  187. // jsonData = response.data
  188. blueunit = response.data.blueunit
  189. redunit = response.data.redunit
  190. satellite = response.data.satellite
  191. center = response.data.center
  192. this.save = true
  193. this.jsonData = {
  194. id: row.id,
  195. xdname: response.data.xdname,
  196. type: response.data.type,
  197. // creator: row.creator,
  198. createtime: response.data.createtime,
  199. bluecnt: response.data.bluecnt,
  200. target: response.data.target,
  201. starttime: response.data.starttime,
  202. steptime: response.data.steptime,
  203. endtime: response.data.endtime,
  204. blueunit: blueunit,
  205. redunit: redunit,
  206. satellite: satellite,
  207. center: center
  208. }
  209. this.setTimeLine(response.data.starttime, response.data.endtime, response.data.steptime)//传入时间到时间轴
  210. })
  211. .catch((error) => {
  212. // 处理错误
  213. console.error(error);
  214. });
  215. for (let i = 0; i < blueunit.length; i++) {
  216. this.markLocationbyJson(parseFloat(blueunit[i].pos.lat), parseFloat(blueunit[i].pos.lon), parseFloat(blueunit[i].pos.height), blueunit[i].name, "blue")
  217. }
  218. for (let i = 0; i < center.length; i++) {
  219. let item = center[i]
  220. this.markLocationbyJson(parseFloat(item[center[i].name].properties.lat), parseFloat(item[center[i].name].properties.lon), parseFloat(item[center[i].name].properties.h), item.name, "center")
  221. }
  222. for (let i = 0; i < redunit.length; i++) {
  223. this.markLocationbyJson(parseFloat(redunit[i].component_movementjson.properties.launch_lat), parseFloat(redunit[i].component_movementjson.properties.launch_lon), parseFloat(redunit[i].component_movementjson.properties.launch_h), redunit[i].name, "red")
  224. let point1 = {
  225. longitude: parseFloat(redunit[i].component_movementjson.properties.launch_lon),
  226. latitude: parseFloat(redunit[i].component_movementjson.properties.launch_lat),
  227. height: parseFloat(redunit[i].component_movementjson.properties.launch_h)
  228. }
  229. let point2 = {
  230. longitude: parseFloat(redunit[i].component_movementjson.properties.target_lon),
  231. latitude: parseFloat(redunit[i].component_movementjson.properties.target_lat),
  232. height: parseFloat(redunit[i].component_movementjson.properties.target_h)
  233. }
  234. this.markLine(point1, point2, "red")
  235. }
  236. },
  237. //获取所有数据
  238. getData() {
  239. this.getCenter();
  240. this.getSatellite();
  241. this.getUnit();
  242. this.getSituation();
  243. },
  244. // 获取场景想定数据
  245. getSituation() {
  246. let params = {
  247. datasourceId: "1656243335922192384",
  248. filterDtoList: [],
  249. pageParam: {
  250. pageNum: 1,
  251. pageSize: 10
  252. }
  253. };
  254. fireController.situation(this, params).then((res) => {
  255. this.situation = res.data.dataList;
  256. });
  257. },
  258. // 获取作战单元数据
  259. getUnit() {
  260. let params = {
  261. datasourceId: "1657931215497334784",
  262. filterDtoList: [],
  263. pageParam: {
  264. pageNum: 1,
  265. pageSize: 10
  266. }
  267. };
  268. fireController.unit(this, params).then((res) => {
  269. this.unit = res.data.dataList;
  270. });
  271. },
  272. // 获取指挥中心数据
  273. getCenter() {
  274. let params = {
  275. datasourceId: "1654421731512684544",
  276. filterDtoList: [],
  277. pageParam: {
  278. pageNum: 1,
  279. pageSize: 10
  280. }
  281. };
  282. fireController.center(this, params).then((res) => {
  283. this.center = res.data.dataList;
  284. });
  285. },
  286. // 获取预警卫星数据
  287. getSatellite() {
  288. let params = {
  289. datasourceId: "1654424480958648320",
  290. filterDtoList: [],
  291. pageParam: {
  292. pageNum: 1,
  293. pageSize: 10
  294. }
  295. };
  296. fireController.satellite(this, params).then((res) => {
  297. this.satellite = res.data.dataList;
  298. });
  299. },
  300. cesiumInit() {
  301. this.viewer2D = new this.Cesium.Viewer("2DcesiumContainer", {
  302. sceneMode: this.Cesium.SceneMode.SCENE2D,
  303. animation: true, // 是否显示时间轴动画
  304. baseLayerPicker: false,
  305. homeButton: false,
  306. geocoder: false,
  307. timeline: true, //是否显示时间线控件
  308. fullscreenButton: false,
  309. sceneModePicker: false,
  310. navigationHelpButton: false,
  311. selectionIndicator: false,
  312. imageryProvider: new this.Cesium.UrlTemplateImageryProvider({
  313. url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
  314. layer: "tdtVecBasicLayer",
  315. style: "default",
  316. format: "image/png",
  317. tileMatrixSetID: "GoogleMapsCompatible",
  318. show: false
  319. })
  320. });
  321. this.viewer3D = new this.Cesium.Viewer("3DcesiumContainer", {
  322. animation: true, // 是否显示时间轴动画
  323. baseLayerPicker: false,
  324. homeButton: false,
  325. geocoder: false,
  326. timeline: true, //是否显示时间线控件
  327. fullscreenButton: false,
  328. sceneModePicker: false,
  329. navigationHelpButton: false,
  330. selectionIndicator: false,
  331. // imageryProvider: new this.Cesium.WebMapServiceImageryProvider({
  332. // url: '/geoserver/map/wms',
  333. // // 这里是自定义的图层名称
  334. // layers: 'map',
  335. // parameters: {
  336. // service: 'WMS',
  337. // format: 'image/png',
  338. // transparent: true
  339. // }
  340. // }),
  341. imageryProvider:
  342. // new this.Cesium.WebMapTileServiceImageryProvider({
  343. // url: "http://10.170.16.95:8080/geoserver/gwc/service/wmts/rest/map:map/{style}/{TileMatrixSet}/{TileMatrixSet}:{TileMatrix}/{TileRow}/{TileCol}?format=image/png",
  344. // layer: 'map:map',
  345. // style: 'raster',
  346. // format: 'image/png',
  347. // tileMatrixSetID: 'EPSG:900913', //一般使用EPSG:3857坐标系
  348. // }),
  349. new this.Cesium.UrlTemplateImageryProvider({
  350. url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
  351. layer: "tdtVecBasicLayer",
  352. style: "default",
  353. format: "image/png",
  354. tileMatrixSetID: "GoogleMapsCompatible",
  355. show: false
  356. })
  357. });
  358. this.viewer3D._cesiumWidget._creditContainer.style.display = "none";
  359. this.viewer2D._cesiumWidget._creditContainer.style.display = "none";
  360. this.viewer3D.camera.setView({
  361. destination: new this.Cesium.Cartesian3.fromDegrees(117.918977, 25.0, 1500000)
  362. // 方向,俯视和仰视的视角
  363. // orientation:{
  364. // heading: this.Cesium.Math.toRadians(90),//坐标系旋转90度
  365. // pitch: this.Cesium.Math.toRadians(-45) ,//设置俯仰角度为-45度
  366. // }
  367. });
  368. this.viewer2D.camera.setView({
  369. destination: new this.Cesium.Cartesian3.fromDegrees(117.918977, 25.0, 1500000)
  370. // 方向,俯视和仰视的视角
  371. // orientation:{
  372. // heading: this.Cesium.Math.toRadians(90),//坐标系旋转90度
  373. // pitch: this.Cesium.Math.toRadians(-45) ,//设置俯仰角度为-45度
  374. // }
  375. });
  376. // this.viewer.scene.screenSpaceCameraController.maximumZoomDistance = 1500000; //相机高度的最大值
  377. this.viewer2D.camera.percentageChanged = 0.01;
  378. this.viewer2D.camera.changed.addEventListener(this.sync); //地图移动事件
  379. this.viewer3D.camera.percentageChanged = 0.01;
  380. this.viewer3D.camera.changed.addEventListener(this.sync); //地图移动事件
  381. this.viewer2D.camera.moveEnd.addEventListener(this.getCammeraHeightAndZoom) //地图缩放事件
  382. this.viewer3D.camera.moveEnd.addEventListener(this.getCammeraHeightAndZoom) //地图缩放事件
  383. this.handler2D = new this.Cesium.ScreenSpaceEventHandler(this.viewer2D.scene.canvas);
  384. this.handler3D = new this.Cesium.ScreenSpaceEventHandler(this.viewer3D.scene.canvas);
  385. },
  386. sync() {
  387. if (this.mousevalue == "3D") {
  388. // 三维地图中心点
  389. let center = new this.Cesium.Cartesian2(
  390. Math.floor(this.viewer3D.canvas.clientWidth / 2),
  391. Math.floor(this.viewer3D.canvas.clientHeight / 2)
  392. );
  393. // 转为世界坐标系
  394. let position = this.viewer3D.scene.camera.pickEllipsoid(center);
  395. // 判断中心点是否在椭球体上
  396. if (this.Cesium.defined(position)) {
  397. // 获取三维地图中心点与相机之间的距离
  398. let distance = this.Cesium.Cartesian3.distance(position, this.viewer3D.scene.camera.positionWC);
  399. position = this.convertWorldToCartographic(position);
  400. // 更新二维地图
  401. this.viewer2D.scene.camera.setView({
  402. destination: new this.Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, distance)
  403. });
  404. }
  405. }
  406. if (this.mousevalue == "2D") {
  407. // 二维地图中心点
  408. let center = new this.Cesium.Cartesian2(
  409. Math.floor(this.viewer2D.canvas.clientWidth / 2),
  410. Math.floor(this.viewer2D.canvas.clientHeight / 2)
  411. );
  412. // 转为世界坐标系
  413. let position = this.viewer2D.scene.camera.pickEllipsoid(center);
  414. // 判断中心点是否在椭球体上
  415. if (this.Cesium.defined(position)) {
  416. // 获取三维地图中心点与相机之间的距离
  417. let distance = this.viewer2D.scene.camera.positionCartographic.height;
  418. position = this.convertWorldToCartographic(position);
  419. // 更新三维地图
  420. this.viewer3D.scene.camera.setView({
  421. destination: new this.Cesium.Cartesian3.fromDegrees(position.longitude, position.latitude, distance)
  422. });
  423. }
  424. }
  425. },
  426. // 将世界坐标系转换为经纬度坐标系
  427. convertWorldToCartographic(worldPosition) {
  428. const ellipsoid = this.viewer2D.scene.globe.ellipsoid;
  429. const cartographic = ellipsoid.cartesianToCartographic(worldPosition);
  430. const longitude = this.Cesium.Math.toDegrees(cartographic.longitude);
  431. const latitude = this.Cesium.Math.toDegrees(cartographic.latitude);
  432. const height = cartographic.height;
  433. return { longitude, latitude, height };
  434. },
  435. // 监听地图变化
  436. changeActive(value) {
  437. this.mousevalue = value;
  438. },
  439. dimensionswitch(value) {
  440. this.dimension = value;
  441. this.selectModel();
  442. },
  443. // 全屏缩小
  444. ismax() {
  445. if (screenfull.isEnabled && screenfull.isFullscreen) {
  446. screenfull.exit();
  447. } else {
  448. screenfull.request();
  449. }
  450. },
  451. /* 获取camera中心点坐标 */
  452. getCenterPosition(is3D = false) {
  453. let viewer = is3D ? this.viewer3D : this.viewer2D;
  454. let result = viewer.camera.pickEllipsoid(
  455. new this.Cesium.Cartesian2(viewer.canvas.clientWidth / 2, viewer.canvas.clientHeight / 2)
  456. );
  457. let curPosition = this.Cesium.Ellipsoid.WGS84.cartesianToCartographic(result);
  458. let lon = (curPosition.longitude * 180) / Math.PI;
  459. let lat = (curPosition.latitude * 180) / Math.PI;
  460. let height = viewer.camera.positionCartographic.height;
  461. return {
  462. lon: lon,
  463. lat: lat,
  464. height: height
  465. };
  466. },
  467. /* 地图放大 */
  468. big() {
  469. let { lon, lat, height } = this.getCenterPosition(this.dimension === 3);
  470. let viewer = (this.dimension === 3 || this.dimension === 5) ? this.viewer3D : this.viewer2D;
  471. // 镜头拉进
  472. viewer.camera.flyTo({
  473. destination: this.Cesium.Cartesian3.fromDegrees(lon, lat, height / 1.8),
  474. duration: 1.0
  475. });
  476. },
  477. /* 地图缩小 */
  478. small() {
  479. let { lon, lat, height } = this.getCenterPosition(this.dimension === 3);
  480. let viewer = (this.dimension === 3 || this.dimension === 5) ? this.viewer3D : this.viewer2D;
  481. // 镜头远离
  482. viewer.camera.flyTo({
  483. destination: this.Cesium.Cartesian3.fromDegrees(lon, lat, height * 1.2),
  484. duration: 1.0
  485. });
  486. },
  487. home() {
  488. let viewer = (this.dimension === 3 || this.dimension === 5) ? this.viewer3D : this.viewer2D;
  489. viewer.camera.flyTo({
  490. destination: this.Cesium.Cartesian3.fromDegrees(117.918977, 25.0, 1500000),
  491. duration: 2.0
  492. });
  493. },
  494. // tabs 切换点击
  495. legendClick({ index }) {
  496. this.selectModel();
  497. let tab_content = document.querySelectorAll(".menu .el-tabs__content");
  498. if (this.currentLab.index == index) {
  499. tab_content[0].style.display == "none" || ""
  500. ? (tab_content[0].style.display = "block")
  501. : (tab_content[0].style.display = "none");
  502. }
  503. if (this.currentLab.index != index) {
  504. this.currentLab.index = index;
  505. tab_content[0].style.display = "block";
  506. }
  507. },
  508. mouseMove(event) {
  509. if (this.$refs.modeltooltip) {
  510. this.$refs.modeltooltip.style.left = event.pageX - 240 + "px";
  511. this.$refs.modeltooltip.style.top = event.pageY - 115 + "px";
  512. }
  513. },
  514. //显示鼠标经纬度
  515. getMouseLocation(event) {
  516. let { longitude, latitude } = this.getCoordinatesFromEvent(event);
  517. this.$store.commit("app/setMouseLocation", { longitude, latitude });
  518. },
  519. /*根据camera高度近似计算当前层级*/
  520. heightToZoom(height) {
  521. var A = 40487.57;
  522. var B = 0.00007096758;
  523. var C = 91610.74;
  524. var D = -40467.74;
  525. return Math.round(D + (A - D) / (1 + Math.pow(height / C, B)));
  526. },
  527. getCammeraHeightAndZoom() {
  528. let viewer = (this.dimension === 3 || this.dimension === 5) ? this.viewer3D : this.viewer2D;
  529. //获取当前相机高度
  530. let height = viewer.camera.positionCartographic.height;
  531. let zoom = this.heightToZoom(height);
  532. this.$store.commit("app/setCameraHeightAndZoom", { height, zoom });
  533. },
  534. selectModel(cursorStyle, image, info) {
  535. console.log('image :>> ', image);
  536. let earthMap = document.getElementById("earth");
  537. earthMap.style.cursor = cursorStyle || "auto";
  538. if (cursorStyle) {
  539. document.addEventListener("mousemove", this.mouseMove);
  540. this.isShow = true;
  541. this.image = image;
  542. this.modeltooltip = info;
  543. } else {
  544. document.removeEventListener("mousemove", this.mouseMove);
  545. this.isShow = false;
  546. this.image = null;
  547. this.modeltooltip = null;
  548. }
  549. },
  550. onMapClick(event) {
  551. if (this.isShow && this.modeltooltip === "左键单击确认") {
  552. const { latitude, longitude } = this.getCoordinatesFromEvent(event);
  553. this.markLocation(latitude, longitude);
  554. }
  555. },
  556. // 同时在2D和3D地图上标记坐标
  557. markLocation(latitude, longitude) {
  558. const position = this.Cesium.Cartesian3.fromDegrees(longitude, latitude);
  559. this.viewer2D.entities.add({
  560. id: this.id,
  561. position: position,
  562. // point: {
  563. // pixelSize: 12, // 调整点的大小,可以增大点的像素大小
  564. // color: this.Cesium.Color.fromCssColorString(this.image.color)
  565. // },
  566. model: {
  567. uri: satelliteModel, // 替换为你的3D模型文件路径
  568. scale: 1.0, // 调整3D模型的缩放大小
  569. minimumPixelSize: 64 // 设置3D模型的最小像素大小,确保在视图中可见
  570. },
  571. label: {
  572. text: this.image.name,
  573. show: true,
  574. font: "18px Helvetica", // 调整标签的字体样式和大小
  575. pixelOffset: new this.Cesium.Cartesian2(0, 20) // 调整标签的像素偏移,向下偏移20像素
  576. }
  577. });
  578. this.viewer3D.entities.add({
  579. id: this.id,
  580. position: position,
  581. // point: {
  582. // pixelSize: 12, // 调整点的大小,可以增大点的像素大小
  583. // color: this.Cesium.Color.fromCssColorString(this.image.color)
  584. // },
  585. model: {
  586. uri: satelliteModel, // 替换为你的3D模型文件路径
  587. scale: 1.0, // 调整3D模型的缩放大小
  588. minimumPixelSize: 64 // 设置3D模型的最小像素大小,确保在视图中可见
  589. },
  590. label: {
  591. text: this.image.name,
  592. show: true,
  593. font: "18px Helvetica", // 调整标签的字体样式和大小
  594. pixelOffset: new this.Cesium.Cartesian2(0, 20) // 调整标签的像素偏移,向下偏移20像素
  595. }
  596. });
  597. this.id++;
  598. },
  599. markLocationbyJson(latitude, longitude, height, name, type) {
  600. const position = this.Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
  601. console.log('position :>> ', position);
  602. let color = ''
  603. let modelUrl = ''
  604. if (type == 'red') {
  605. color = 'Red'
  606. modelUrl = missileModel
  607. }
  608. else if (type == 'blue') {
  609. color = 'Blue'
  610. modelUrl = radarModel
  611. }
  612. else if (type == 'center') {
  613. color = 'Blue'
  614. modelUrl = centerModel
  615. }
  616. this.viewer2D.entities.add({
  617. id: this.id,
  618. position: position,
  619. point: {
  620. pixelSize: 12, // 调整点的大小,可以增大点的像素大小
  621. color: this.Cesium.Color.fromCssColorString(color)
  622. },
  623. model: {
  624. uri: modelUrl, // 替换为你的3D模型文件路径
  625. scale: 1.0, // 调整3D模型的缩放大小
  626. minimumPixelSize: 64 // 设置3D模型的最小像素大小,确保在视图中可见
  627. },
  628. label: {
  629. text: type + ' ' + name,
  630. show: true,
  631. font: "18px Helvetica", // 调整标签的字体样式和大小
  632. pixelOffset: new this.Cesium.Cartesian2(0, 20) // 调整标签的像素偏移,向下偏移20像素
  633. }
  634. });
  635. this.viewer3D.entities.add({
  636. id: this.id,
  637. position: position,
  638. point: {
  639. pixelSize: 12, // 调整点的大小,可以增大点的像素大小
  640. color: this.Cesium.Color.fromCssColorString(color)
  641. },
  642. model: {
  643. uri: modelUrl, // 替换为你的3D模型文件路径
  644. scale: 1.0, // 调整3D模型的缩放大小
  645. minimumPixelSize: 64 // 设置3D模型的最小像素大小,确保在视图中可见
  646. },
  647. label: {
  648. text: type + ' ' + name,
  649. show: true,
  650. font: "18px Helvetica", // 调整标签的字体样式和大小
  651. pixelOffset: new this.Cesium.Cartesian2(0, 20) // 调整标签的像素偏移,向下偏移20像素
  652. }
  653. });
  654. this.nameIdList.push({
  655. id: this.id,
  656. name: name
  657. })
  658. this.id++;
  659. },
  660. // 从鼠标点击事件获取坐标
  661. getCoordinatesFromEvent(event) {
  662. let viewer = this.mousevalue === "2D" ? this.viewer2D : this.viewer3D;
  663. let clickPosition;
  664. if (this.dimension === 5 && this.mousevalue === "3D") {
  665. clickPosition = new this.Cesium.Cartesian2(event.clientX - 1080, event.clientY - 160);
  666. } else {
  667. clickPosition = new this.Cesium.Cartesian2(event.clientX - 280, event.clientY - 160);
  668. }
  669. // 获取地图上的经纬度
  670. const viewerPosition = viewer.scene.camera.pickEllipsoid(clickPosition);
  671. const cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(viewerPosition);
  672. const latitude = this.Cesium.Math.toDegrees(cartographic.latitude);
  673. const longitude = this.Cesium.Math.toDegrees(cartographic.longitude);
  674. return {
  675. latitude,
  676. longitude
  677. };
  678. },
  679. markLine(point1, point2, color) {
  680. // 从点1和点2的WGS84坐标创建Cartesian3对象
  681. const position1 = this.Cesium.Cartesian3.fromDegrees(point1.longitude, point1.latitude, point1.height || 0);
  682. const position2 = this.Cesium.Cartesian3.fromDegrees(point2.longitude, point2.latitude, point2.height || 0);
  683. // 创建一个带有箭头图标的PolylineMaterial
  684. const material = new this.Cesium.PolylineArrowMaterialProperty(
  685. this.Cesium.Color.fromCssColorString(color || "red")
  686. );
  687. // 将点1和点2之间的连线添加到Viewer中
  688. this.viewer2D.entities.add({
  689. polyline: {
  690. positions: [position1, position2],
  691. width: 5, // 设置线的宽度
  692. material: material,
  693. followSurface: false // 设置为false,使连线保持在固定的高度,不会贴地显示
  694. }
  695. });
  696. this.viewer3D.entities.add({
  697. polyline: {
  698. positions: [position1, position2],
  699. width: 5, // 设置线的宽度
  700. material: material,
  701. followSurface: false // 设置为false,使连线保持在固定的高度,不会贴地显示
  702. }
  703. });
  704. },
  705. setTimeLine(startTime, endtime, stepTime) {
  706. let start = this.Cesium.JulianDate.fromDate(new Date(startTime)); // 设置时间轴当前时间为开始时间
  707. let stop = this.Cesium.JulianDate.fromDate(new Date(endtime));
  708. // 添加8小时,使地图时间和北京时间相同
  709. start = this.Cesium.JulianDate.addHours(start, 8, new this.Cesium.JulianDate());
  710. stop = this.Cesium.JulianDate.addHours(stop, 8, new this.Cesium.JulianDate());
  711. // 设置时钟开始时间
  712. this.viewer2D.clock.startTime = start.clone();
  713. this.viewer3D.clock.startTime = start.clone();
  714. // 设置时钟当前时间
  715. this.viewer2D.clock.currentTime = start.clone();
  716. this.viewer3D.clock.currentTime = start.clone();
  717. // 设置时钟结束时间
  718. this.viewer2D.clock.stopTime = stop.clone();
  719. this.viewer3D.clock.stopTime = stop.clone();
  720. // 时间速率,数字越大时间过的越快,设置1好像是和实际时间一样
  721. this.viewer2D.clock.multiplier = stepTime;
  722. this.viewer3D.clock.multiplier = stepTime;
  723. // 时间轴绑定到viewer上去
  724. this.viewer2D.timeline.zoomTo(start, stop);
  725. this.viewer3D.timeline.zoomTo(start, stop);
  726. // 循环执行,到达终止时间,重新从起点时间开始
  727. this.viewer2D.clock.clockRange = this.Cesium.ClockRange.LOOP_STOP;
  728. this.viewer3D.clock.clockRange = this.Cesium.ClockRange.LOOP_STOP;
  729. this.viewer2D.clock.onTick.addEventListener(clock => {
  730. const currentTime = clock.currentTime; // 获取当前时间轴的时间
  731. const elapsedTime = this.Cesium.JulianDate.secondsDifference(
  732. currentTime,
  733. this.viewer2D.clock.startTime
  734. ); // 获取从起始时间到当前时间的秒数
  735. if (parseInt(elapsedTime) % stepTime === 0 && elapsedTime!=0) {
  736. console.log('elapsedTime :>> ', elapsedTime);
  737. // 当从起始时间到当前时间的秒数是 stepTime 的倍数时,发送请求
  738. this.requestDataAndUpdateModel2D(startTime, elapsedTime);
  739. }
  740. });
  741. this.viewer3D.clock.onTick.addEventListener(clock => {
  742. const currentTime = clock.currentTime; // 获取当前时间轴的时间
  743. const elapsedTime = this.Cesium.JulianDate.secondsDifference(
  744. currentTime,
  745. this.viewer3D.clock.startTime
  746. ); // 获取从起始时间到当前时间的秒数
  747. if (parseInt(elapsedTime) % stepTime === 0 && elapsedTime!=0) {
  748. console.log('elapsedTime :>> ', elapsedTime);
  749. // 当从起始时间到当前时间的秒数是 stepTime 的倍数时,发送请求
  750. this.requestDataAndUpdateModel3D(startTime, elapsedTime);
  751. }
  752. });
  753. this.initSTK()
  754. },
  755. // 初始化stk方法,生成轨迹文件
  756. async initSTK() {
  757. console.log('this.jsonData :>> ', this.jsonData);
  758. // await axios
  759. // .get("/api", this.jsonData).then(res=>{
  760. // console.log('res :>> ', res);
  761. // })
  762. await axios
  763. .post("/api/traj", this.jsonData).then(res=>{
  764. console.log('res :>> ', res);
  765. })
  766. },
  767. // 根据时间参数请求模型位置并更新 2D
  768. async requestDataAndUpdateModel2D(startTime, elapsedTime) {
  769. const jsDate = new Date(startTime);
  770. // 增加 elapsedTime 秒
  771. jsDate.setSeconds(jsDate.getSeconds() + elapsedTime);
  772. // 转换为需求字符串格式
  773. const newTimeString = `${jsDate.getFullYear()}-${(jsDate.getMonth() + 1).toString().padStart(2, '0')}-${jsDate.getDate().toString().padStart(2, '0')} ${jsDate.getHours().toString().padStart(2, '0')}:${jsDate.getMinutes().toString().padStart(2, '0')}:${jsDate.getSeconds().toString().padStart(2, '0')}`;
  774. await axios
  775. .post("/api/pos", {simulation_time: newTimeString+'.000'}).then(res=>{
  776. console.log('res :>> ', res);
  777. let data = res.data[1].data
  778. //依次更新每个模型位置
  779. for(let i=0;i<this.nameIdList.length;i++){
  780. if(data[this.nameIdList[i].name]!=null&&data[this.nameIdList[i].name]!=undefined){
  781. this.modelEntityMoveByIDAndLocation(this.viewer2D,this.nameIdList[i].id,data[this.nameIdList[i].name].x,data[this.nameIdList[i].name].y,data[this.nameIdList[i].name].z)
  782. }
  783. }
  784. //更新模型位置
  785. // this.modelEntityMoveByIDAndLocation(this.viewer2D,"1654426964397658112",res.data[1].data.W1.x,res.data[1].data.W1.y,res.data[1].data.W1.z)
  786. })
  787. },
  788. // 根据时间参数请求模型位置并更新 3D
  789. async requestDataAndUpdateModel3D(startTime, elapsedTime) {
  790. const jsDate = new Date(startTime);
  791. // 增加 elapsedTime 秒
  792. jsDate.setSeconds(jsDate.getSeconds() + elapsedTime);
  793. // 转换为需求字符串格式
  794. const newTimeString = `${jsDate.getFullYear()}-${(jsDate.getMonth() + 1).toString().padStart(2, '0')}-${jsDate.getDate().toString().padStart(2, '0')} ${jsDate.getHours().toString().padStart(2, '0')}:${jsDate.getMinutes().toString().padStart(2, '0')}:${jsDate.getSeconds().toString().padStart(2, '0')}`;
  795. await axios
  796. .post("/api/pos", {simulation_time: newTimeString+'.000'}).then(res=>{
  797. let data = res.data[1].data
  798. //依次更新每个模型位置
  799. for(let i=0;i<this.nameIdList.length;i++){
  800. console.log('this.nameIdList[i].name :>> ', this.nameIdList[i].name);
  801. console.log('data :>> ', data);
  802. console.log('data[this.nameIdList[i].name] :>> ', data[this.nameIdList[i].name]);
  803. if(this.nameIdList[i].name in data){
  804. console.log(' 开始移动'+this.nameIdList[i].name);
  805. this.modelEntityMoveByIDAndLocation(this.viewer3D,this.nameIdList[i].id,data[this.nameIdList[i].name].x,data[this.nameIdList[i].name].y,data[this.nameIdList[i].name].z)
  806. }
  807. }
  808. //更新模型位置
  809. // this.modelEntityMoveByIDAndLocation(this.viewer3D,viewer,"1654426964397658112",res.data[1].data.W1.x,res.data[1].data.W1.y,res.data[1].data.W1.z)
  810. })
  811. },
  812. // 根据模型实体Id和终点位置进行移动
  813. modelEntityMoveByIDAndLocation(viewer,id,x,y,z) {
  814. x = parseFloat(x)*1000
  815. y = parseFloat(y)*1000
  816. z = parseFloat(z)*1000
  817. let entity = viewer.entities.getById(id)
  818. //终点位置
  819. let position = new this.Cesium.Cartesian3(x, y, z);
  820. //设置方向,根据实体的位置来配置方向
  821. entity.orientation = new this.Cesium.VelocityOrientationProperty(entity.position);
  822. //设置查看器,让模型动起来
  823. entity.position.setValue(position)
  824. }
  825. }
  826. };
  827. </script>
  828. <style scoped>
  829. ::v-deep .cesium-infoBox {
  830. display: none !important;
  831. }
  832. ::v-deep .cesium-infoBox-bodyless {
  833. display: none !important;
  834. }
  835. ::v-deep .cesium-infoBox-visible {
  836. display: none !important;
  837. }
  838. .container {
  839. height: 100%;
  840. position: relative;
  841. }
  842. .modeltooltip {
  843. position: absolute;
  844. padding: 5px;
  845. color: #fff;
  846. font-size: 20px;
  847. pointer-events: none;
  848. z-index: 999;
  849. }
  850. .myHeader {
  851. background-color: #1c222b !important;
  852. color: #fff;
  853. height: 100%;
  854. display: flex;
  855. flex-direction: row;
  856. align-items: center;
  857. /*由于flex-direction: column,因此align-items代表的是水平方向*/
  858. justify-content: center;
  859. /*由于flex-direction: column,因此justify-content代表的是垂直方向*/
  860. }
  861. .myHeader .el-button {
  862. width: 100px;
  863. height: 20px;
  864. padding: 1px 23px;
  865. }
  866. .box-card {
  867. min-height: 100%;
  868. height: 100%;
  869. }
  870. ::v-deep .el-card__body {
  871. height: 100% !important;
  872. padding: 0px !important;
  873. }
  874. .main-layout {
  875. height: 100%;
  876. width: 100%;
  877. }
  878. .map {
  879. width: 100%;
  880. height: 100%;
  881. }
  882. .menu {
  883. position: absolute;
  884. height: 400px;
  885. z-index: 999;
  886. left: 20px;
  887. top: 20px;
  888. }
  889. ::v-deep .el-tabs--left .el-tabs__header.is-left {
  890. margin-right: 0px !important;
  891. }
  892. .buttons {
  893. display: flex;
  894. flex-direction: column;
  895. align-items: center;
  896. justify-items: center;
  897. position: absolute;
  898. z-index: 999;
  899. right: 20px;
  900. top: 20px;
  901. }
  902. .el-button {
  903. margin: 5px !important;
  904. }
  905. ::v-deep .el-tabs--border-card>.el-tabs__content {
  906. width: 300px;
  907. height: 100%;
  908. overflow-y: visible;
  909. }
  910. .model {
  911. display: flex;
  912. width: 100%;
  913. flex-wrap: wrap;
  914. }
  915. .model>div {
  916. width: 50%;
  917. height: 120px;
  918. padding: 5px;
  919. }
  920. .model>div:hover {
  921. border: 2px solid blue;
  922. }
  923. .model>div:active {
  924. border: 2px solid red;
  925. }
  926. .active {
  927. border: 2px solid red !important;
  928. }
  929. .model .el-image {
  930. display: block !important;
  931. }
  932. ::v-deep .el-image .el-image__inner {
  933. border: 1px solid #ddd;
  934. border-radius: 5px;
  935. }
  936. .item {
  937. font-size: 14px;
  938. /* right: 20px; */
  939. }
  940. .TimeLine {
  941. position: absolute;
  942. left: 21%;
  943. bottom: 15px;
  944. transform: translateX(-50%);
  945. }
  946. </style>