radarEchoMap.vue 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471
  1. <template>
  2. <div class="container">
  3. <div class="map-box">
  4. <div class="title-box">雷达拼图{{imgList[activeImg] ? imgList[activeImg].time : ''}}</div>
  5. <!-- <img v-for="(item, index) in imgList" :key="index" :src="item.url" alt="" style="width: 200px;height: 200px;">-->
  6. <div class="btn1" @click="handleChangeDynamic">
  7. <el-button type="primary">
  8. <i class="icon1" />
  9. {{ openDynamicImage ? '切换为静图' : '切换为动图' }}
  10. </el-button>
  11. </div>
  12. <div ref="mapRef" id="map" />
  13. <div class="right-bottom-box">
  14. <div :class="showLegend ? 'legend-btn btn-active' : 'legend-btn'" @click="handleClickLegend">
  15. <i class="icon-legend" />
  16. <div>图例</div>
  17. <div v-if="showLegend" class="legend-box" @click.stop="">
  18. <img class="img" src="@/assets/images/disasterRiskMonitor/radarEchoMap/legend3.png" alt="">
  19. </div>
  20. </div>
  21. <div :class="showMapSetting ? 'map-btn btn-active' : 'map-btn'" @click="handleClickMapSetting">
  22. <i class="icon-map" />
  23. <div>地图</div>
  24. <div v-if="showMapSetting" class="map-setting-box" @click.stop="">
  25. <div class="function-box">
  26. <div v-for="(item, index) in mapTypeList" :key="index" class="function-item" @click.stop="changeActiveMap(item.value)">
  27. <div :class="item.value + ' img'">
  28. <i v-if="activeMap === item.value" class="checked" />
  29. </div>
  30. <div>{{ item.name }}</div>
  31. </div>
  32. </div>
  33. <div class="function-box">
  34. <div class="function-item" @click.stop="handleShowLatLngLine">
  35. <i :class="showLatLngLine ? 'icon-latlng2' : 'icon-latlng1'" />
  36. <div>经纬度</div>
  37. </div>
  38. <div class="function-item" @click.stop="handleShowLatPlaceName">
  39. <i :class="showLatPlaceName ? 'icon-position2' : 'icon-position1'" />
  40. <div>显示地名</div>
  41. </div>
  42. </div>
  43. </div>
  44. </div>
  45. <div class="operate-box">
  46. <div class="operate-btn" @click="handleIndex('reduce')">
  47. <i class="icon-left" />
  48. 上时次
  49. </div>
  50. <div class="operate-btn" @click="handleIndex('add')">
  51. <i class="icon-right" />
  52. 下时次
  53. </div>
  54. <div :class="playing ? 'operate-btn btn-active' : 'operate-btn'" @click="handleClickPlaying">
  55. <i class="icon-play" />
  56. 动画
  57. </div>
  58. </div>
  59. </div>
  60. </div>
  61. </div>
  62. </template>
  63. <script lang="ts" setup name="RadarEchoMap">
  64. import { olMap } from '@/utils/olMap/olMap';
  65. import mmJson from '@/assets/json/mm2.json';
  66. import {ElButton} from "element-plus";
  67. import {getRadarChart} from "@/api/disasterRiskMonitor/radarEchoMap";
  68. import { transform } from 'ol/proj'
  69. import Image from 'ol/layer/Image';
  70. import ImageStatic from 'ol/source/ImageStatic';
  71. let mapRef = ref(null);
  72. let mapState = reactive({
  73. center: [110.925175, 22],
  74. zoom: 8.4,
  75. minZoom: 6,
  76. maxZoom: 16
  77. });
  78. let map, mapUtils;
  79. // 是否开启动态图
  80. let openDynamicImage = ref(false);
  81. // 初始化地图
  82. const initMap = () => {
  83. const index = mapTypeList.findIndex((item) => item.value === activeMap.value);
  84. mapUtils = new olMap({
  85. dom: mapRef.value,
  86. id: mapTypeList[index].data,
  87. center: mapState.center,
  88. zoom: mapState.zoom,
  89. minZoom: mapState.minZoom,
  90. maxZoom: mapState.maxZoom,
  91. // 加载完成事件
  92. onLoadCompleted: (yMap) => {
  93. map = yMap;
  94. getImageData();
  95. mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 });
  96. mapUtils.handleLngLatLine(showLatLngLine.value);
  97. map.updateSize();
  98. }
  99. });
  100. };
  101. // 获取图层数据
  102. let imageLayer;
  103. let activeImg = ref(0);
  104. let imgList = ref([]);
  105. // 获取图层数据
  106. const getImageData = () => {
  107. getRadarChart().then((res) => {
  108. imgList.value = res.data;
  109. switchImage();
  110. })
  111. }
  112. // 加载图层到地图中
  113. const switchImage = () => {
  114. if (!!imageLayer) {
  115. map.removeLayer(imageLayer);
  116. imageLayer = null;
  117. }
  118. let left = 18.1,
  119. bottom = 108.5,
  120. right = 26.9,
  121. top = 119
  122. let lb = (transform([bottom, left], 'EPSG:4326', 'EPSG:4490'));
  123. let tr = (transform([top, right], 'EPSG:4326', 'EPSG:4490'));
  124. // 创建ImageStatic图层
  125. imageLayer = new Image({
  126. source: new ImageStatic({
  127. url: imgList.value[activeImg.value].url,
  128. crossOrigin: '',
  129. projection: 'EPSG:4490',
  130. imageExtent: [lb[0], lb[1], tr[0], tr[1]]
  131. })
  132. });
  133. map.getLayers().push(imageLayer);
  134. }
  135. // 上下一个时间
  136. const handleIndex = (type = 'add') => {
  137. if (type === 'add') {
  138. if (activeImg.value + 1 < imgList.value.length) {
  139. activeImg.value += 1;
  140. } else if (playing.value) {
  141. activeImg.value = 0
  142. }
  143. } else if (type === 'reduce' && activeImg.value - 1 >= 0) {
  144. activeImg.value -= 1;
  145. }
  146. switchImage();
  147. };
  148. // 切换动/静图
  149. const handleChangeDynamic = () => {
  150. openDynamicImage.value = !openDynamicImage.value;
  151. }
  152. // 图例显隐
  153. let showLegend = ref(false);
  154. const handleClickLegend = () => {
  155. showLegend.value = !showLegend.value;
  156. }
  157. // 地图配置显隐
  158. let showMapSetting = ref(false);
  159. const handleClickMapSetting = () => {
  160. showMapSetting.value = !showMapSetting.value;
  161. }
  162. // 当前显示图层
  163. let activeMap = ref('satelliteMap');
  164. let mapTypeList = reactive([
  165. { name: '业务图', value: 'businessMap', data: [{id: 'YZT1708679726700', zIndex: 0}, {id: 'YZT1695608158269', zIndex: 100}] },
  166. { name: '卫星图', value: 'satelliteMap', data: [{id: 'YZT1640925052482', zIndex: 0}, {id: 'YZT1695608158269', zIndex: 100}] }
  167. ])
  168. // 切换地图
  169. const changeActiveMap = (value) => {
  170. handleClickMapSetting();
  171. if(activeMap.value === value) return;
  172. activeMap.value = value;
  173. const index = mapTypeList.findIndex((item) => item.value === activeMap.value);
  174. let layers = mapTypeList[index].data;
  175. // 判断是否显示地名
  176. if (!showLatPlaceName.value) {
  177. layers = layers.filter(item => item.id !== 'YZT1695608158269');
  178. }
  179. mapUtils.removeMask();
  180. mapUtils.replaceLayers(layers, () => {
  181. //加载完基础图层后再加载其他图层
  182. mapUtils.createVecByJson2(mmJson, { strokeWeight: 2 })
  183. if (showLatLngLine.value) {
  184. mapUtils.handleLngLatLine(showLatLngLine.value);
  185. }
  186. });
  187. };
  188. // 显隐经纬线
  189. let showLatLngLine = ref(true);
  190. let showLatPlaceName = ref(true);
  191. const handleShowLatLngLine = () => {
  192. showLatLngLine.value = !showLatLngLine.value;
  193. handleClickMapSetting();
  194. mapUtils.handleLngLatLine(showLatLngLine.value);
  195. }
  196. // 显隐地名
  197. const handleShowLatPlaceName = () => {
  198. showLatPlaceName.value = !showLatPlaceName.value;
  199. handleClickMapSetting();
  200. if (showLatPlaceName.value) {
  201. mapUtils.formatXml(['YZT1695608158269'])
  202. } else {
  203. mapUtils.removeLayer('YZT1695608158269')
  204. }
  205. }
  206. // 动画
  207. let playing = ref(false);
  208. let timer
  209. const handleClickPlaying = () => {
  210. playing.value = !playing.value;
  211. if (playing.value) {
  212. timer = setInterval(handleIndex, 1000)
  213. } else {
  214. clearInterval(timer)
  215. }
  216. }
  217. onMounted(() => {
  218. initMap();
  219. })
  220. </script>
  221. <style lang="scss" scoped>
  222. .container {
  223. .map-box {
  224. width: 100%;
  225. height: calc(100vh - 55px);
  226. position: relative;
  227. #map {
  228. width: 100%;
  229. height: 100%;
  230. }
  231. .title-box {
  232. position: absolute;
  233. top: 0;
  234. left: 0;
  235. z-index: 10;
  236. width: 100%;
  237. height: 35px;
  238. line-height: 35px;
  239. text-align: center;
  240. background-color: rgba(0, 0, 0, 0.3);
  241. color: #ffffff;
  242. font-size: 14px;
  243. }
  244. .btn1 {
  245. position: absolute;
  246. top: 40px;
  247. right: 5px;
  248. z-index: 10;
  249. color: #fff;
  250. font-size: 14px;
  251. display: flex;
  252. justify-content: center;
  253. align-items: center;
  254. .icon1 {
  255. display: inline-block;
  256. width: 14px;
  257. height: 14px;
  258. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/icon1.png") no-repeat;
  259. background-size: 100% 100%;
  260. margin-right: 3px;
  261. }
  262. }
  263. .right-bottom-box {
  264. position: absolute;
  265. bottom: 5px;
  266. right: 5px;
  267. z-index: 10;
  268. font-size: 14px;
  269. display: flex;
  270. flex-direction: column;
  271. align-items: flex-end;
  272. .legend-btn,
  273. .map-btn {
  274. display: flex;
  275. flex-direction: column;
  276. justify-content: center;
  277. align-items: center;
  278. background-color: #ffffff;
  279. border-radius: 4px;
  280. border: 1px solid #e0e0e0;
  281. width: 48px;
  282. height: 48px;
  283. margin-bottom: 5px;
  284. position: relative;
  285. .legend-box {
  286. position: absolute;
  287. bottom: 53px;
  288. right: 0;
  289. border: 1px solid #e0e0e0;
  290. .img {
  291. width: 46px;
  292. }
  293. }
  294. .map-setting-box {
  295. position: absolute;
  296. bottom: 0;
  297. right: 53px;
  298. border: 1px solid #e0e0e0;
  299. background-color: #ffffff;
  300. color: #445267;
  301. .function-box {
  302. display: flex;
  303. justify-content: center;
  304. align-items: center;
  305. padding: 5px;
  306. .function-item {
  307. width: 68px;
  308. display: flex;
  309. flex-direction: column;
  310. justify-content: center;
  311. align-items: center;
  312. margin-left: 5px;
  313. position: relative;
  314. &:first-child {
  315. margin-left: 0;
  316. }
  317. .checked {
  318. position: absolute;
  319. top: -3px;
  320. right: -3px;
  321. display: inline-block;
  322. width: 12px;
  323. height: 12px;
  324. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/checked.png") no-repeat;
  325. background-size: 100% 100%;
  326. }
  327. .businessMap {
  328. width: 68px;
  329. height: 48px;
  330. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/businessGraph.png") no-repeat;
  331. background-size: 100% 100%;
  332. margin-bottom: 5px;
  333. position: relative;
  334. }
  335. .satelliteMap {
  336. width: 68px;
  337. height: 48px;
  338. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/satellite.png") no-repeat;
  339. background-size: 100% 100%;
  340. margin-bottom: 5px;
  341. position: relative;
  342. }
  343. .icon-latlng1 {
  344. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/latlng1.png") no-repeat;
  345. }
  346. .icon-latlng2 {
  347. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/latlng2.png") no-repeat;
  348. }
  349. .icon-position1 {
  350. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/position1.png") no-repeat;
  351. }
  352. .icon-position2 {
  353. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/position2.png") no-repeat;
  354. }
  355. .icon-latlng1,
  356. .icon-latlng2,
  357. .icon-position1,
  358. .icon-position2 {
  359. display: inline-block;
  360. width: 36px;
  361. height: 36px;
  362. background-size: 100% 100%;
  363. }
  364. }
  365. }
  366. }
  367. .icon-legend {
  368. display: inline-block;
  369. width: 16px;
  370. height: 17px;
  371. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/legend1.png") no-repeat;
  372. background-size: 100% 100%;
  373. margin: 3px 0;
  374. }
  375. .icon-map {
  376. display: inline-block;
  377. width: 16px;
  378. height: 16px;
  379. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/map1.png") no-repeat;
  380. background-size: 100% 100%;
  381. margin: 3px 0;
  382. }
  383. }
  384. .operate-box {
  385. display: flex;
  386. align-items: center;
  387. .operate-btn {
  388. display: flex;
  389. flex-direction: column;
  390. justify-content: center;
  391. align-items: center;
  392. background-color: #ffffff;
  393. border-radius: 4px;
  394. border: 1px solid #e0e0e0;
  395. width: 48px;
  396. height: 48px;
  397. margin-left: 5px;
  398. &:first-child {
  399. margin-left: 0;
  400. }
  401. font-size: 12px;
  402. .icon-left {
  403. display: inline-block;
  404. width: 13px;
  405. height: 15px;
  406. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/left.png") no-repeat;
  407. background-size: 100% 100%;
  408. margin: 3px 0;
  409. }
  410. .icon-right {
  411. display: inline-block;
  412. width: 12px;
  413. height: 15px;
  414. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/right.png") no-repeat;
  415. background-size: 100% 100%;
  416. margin: 3px 0;
  417. }
  418. .icon-play {
  419. display: inline-block;
  420. width: 17px;
  421. height: 16px;
  422. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/play.png") no-repeat;
  423. background-size: 100% 100%;
  424. margin: 3px 0;
  425. }
  426. &:active {
  427. background-color: #48a1f7;
  428. color: #fff;
  429. border: 1px solid #48a1f7;
  430. .icon-left {
  431. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/left2.png") no-repeat;
  432. background-size: 100% 100%;
  433. }
  434. .icon-right {
  435. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/right2.png") no-repeat;
  436. background-size: 100% 100%;
  437. }
  438. .icon-play {
  439. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/play2.png") no-repeat;
  440. background-size: 100% 100%;
  441. }
  442. }
  443. }
  444. }
  445. .btn-active {
  446. background-color: #48a1f7 !important;
  447. color: #fff !important;
  448. border: 1px solid #48a1f7 !important;
  449. .icon-legend {
  450. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/legend2.png") no-repeat;
  451. background-size: 100% 100%;
  452. }
  453. .icon-map {
  454. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/map2.png") no-repeat;
  455. background-size: 100% 100%;
  456. }
  457. .icon-play {
  458. background: url("@/assets/images/disasterRiskMonitor/radarEchoMap/play2.png") no-repeat !important;
  459. background-size: 100% 100% !important;
  460. }
  461. }
  462. }
  463. }
  464. }
  465. </style>