index.vue 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. <template>
  2. <div ref="containerRef" class="map-container">
  3. <div
  4. ref="mapRef"
  5. id="YztMap"
  6. class="map-container"
  7. :style="{
  8. width: width,
  9. height: height,
  10. transform: 'scale(' + inverseScale.inverseScaleX + ', ' + inverseScale.inverseScaleY + ')',
  11. transformOrigin: '0 0'
  12. }"
  13. ></div>
  14. <!-- 右下工具 -->
  15. <div v-show="mapState.showScale" class="zoom-text">{{ mapState.zoom }}级</div>
  16. <div class="right-tool">
  17. <!-- 快捷缩放 -->
  18. <QuickZoom v-model:zoom="mapState.zoom" @change-step="setMapZoom" />
  19. <div class="flex" style="margin-top: 5px; justify-content: center">
  20. <div class="mask-btn" @click="handleShowMask">{{ showMask ? '显' : '隐' }}</div>
  21. <!-- <div class="model-btn" @click="switchThreeDimensional">{{ mapState.isThreeDimensional ? '3D' : '2D' }}</div>-->
  22. <div class="ruler-icon" style="margin-left: 5px" @click="changeScaleControl"></div>
  23. </div>
  24. </div>
  25. </div>
  26. </template>
  27. <script setup lang="ts">
  28. import 'ol/ol.css';
  29. import mmJson from '@/assets/json/mm.json';
  30. import { olMap } from '@/utils/olMap/olMap';
  31. import { PointType } from '@/api/globalMap/type';
  32. import { ScaleLine } from 'ol/control';
  33. interface Props {
  34. activeMap: string;
  35. pointType: PointType[];
  36. showMask: boolean;
  37. }
  38. const containerScale = inject('containerScale');
  39. const props = withDefaults(defineProps<Props>(), {});
  40. const emits = defineEmits(['update:drawing', 'update:showMask', 'selectGraphics']);
  41. const mapRef = ref(null);
  42. const mapState = reactive({
  43. center: [110.925175, 21.978955],
  44. zoom: 8.5,
  45. minZoom: 6,
  46. maxZoom: 16,
  47. isThreeDimensional: false,
  48. // 是否显示比例尺
  49. showScale: true
  50. });
  51. const containerRef = ref();
  52. const width = ref('100%');
  53. const height = ref('100%');
  54. let yztMap, map;
  55. // 监听是否开启绘制
  56. watch(
  57. () => props.drawing,
  58. (value) => {
  59. if (value) {
  60. map.drawGraphics(props.graphicsType);
  61. } else {
  62. map.closeDraw();
  63. }
  64. }
  65. );
  66. const mapList = reactive({
  67. satellite2: ['YZT1715739306532', 'YZT1695608158269'],
  68. satellite3: ['YZT1708679726700', 'YZT1695608158269'],
  69. imageMap: ['YZT1640925052482', 'YZT1695608158269'],
  70. imageMap2: ['YZT1640925052482', 'YZT1695608158269']
  71. });
  72. // 监听地图类型变化
  73. watch(
  74. () => props.activeMap,
  75. () => {
  76. if (!map) return;
  77. map.replaceLayers(mapList[props.activeMap]);
  78. }
  79. );
  80. watch(
  81. () => props.showMask,
  82. () => {
  83. if (props.showMask) {
  84. map.createVecByJson(mmJson, '茂名市');
  85. } else {
  86. map.removeMask();
  87. }
  88. }
  89. );
  90. let scaleLine;
  91. const init = () => {
  92. map = new olMap({
  93. dom: mapRef.value,
  94. id: mapList[props.activeMap],
  95. center: mapState.center,
  96. zoom: mapState.zoom,
  97. minZoom: mapState.minZoom,
  98. maxZoom: mapState.maxZoom,
  99. drawTool: {
  100. use: true,
  101. color: props.color,
  102. drawType: props.drawType,
  103. graphicsType: props.graphicsType,
  104. // 绘制完成事件
  105. onDrawCompleted: (data, overlaysData, obj) => {
  106. emits('selectGraphics', data, overlaysData.length.toString());
  107. // 点击空间分析
  108. obj.on('click', function () {
  109. // 没在编辑时
  110. if (!props.drawing) {
  111. emits('selectGraphics', data);
  112. }
  113. });
  114. }
  115. },
  116. // 加载完成事件
  117. onLoadCompleted: (yMap) => {
  118. yztMap = yMap;
  119. // initMouseTool(map);
  120. scaleLine = new ScaleLine();
  121. yztMap.addControl(scaleLine);
  122. yztMap.getView().on('change:resolution', () => {
  123. mapState.zoom = yztMap.getView().getZoom().toFixed(2);
  124. });
  125. if (props.showMask) {
  126. map.createVecByJson(mmJson, '茂名市');
  127. }
  128. handleResize();
  129. }
  130. });
  131. };
  132. const addMarker = (points) => {
  133. map.addMarker(points);
  134. };
  135. // 设置地图层级
  136. const setMapZoom = (value) => {
  137. if (!yztMap) return;
  138. const view = yztMap.getView();
  139. if (value === 1) {
  140. view.setCenter([110.925175, 21.678955]);
  141. view.setZoom(7.9);
  142. } else if (value === 2) {
  143. view.setCenter([110.925175, 21.6789558]);
  144. view.setZoom(9.21);
  145. } else if (value === 3) {
  146. view.setCenter([110.925175, 21.678955]);
  147. view.setZoom(11.38);
  148. } else if (value === 4) {
  149. view.setCenter([110.925175, 21.678955]);
  150. view.setZoom(12.83);
  151. }
  152. };
  153. // 切换2D、3D
  154. const switchThreeDimensional = () => {
  155. const view = yztMap.map.getView();
  156. mapState.isThreeDimensional = !mapState.isThreeDimensional;
  157. const pitch = mapState.isThreeDimensional ? 45 : 0;
  158. view.setPitch(pitch);
  159. };
  160. // 切换比例尺
  161. const changeScaleControl = () => {
  162. mapState.showScale = !mapState.showScale;
  163. if (mapState.showScale) {
  164. yztMap.addControl(scaleLine);
  165. } else {
  166. yztMap.removeControl(scaleLine);
  167. }
  168. };
  169. const clearMarker = () => {
  170. map.clearMarker();
  171. };
  172. const handleShowMask = () => {
  173. emits('update:showMask', !props.showMask);
  174. };
  175. defineExpose({ addMarker, clearMarker });
  176. let inverseScale = ref({
  177. inverseScaleX: 1,
  178. inverseScaleY: 1
  179. });
  180. const handleResize = () => {
  181. inverseScale.value.inverseScaleX = 1 / containerScale().scaleX;
  182. inverseScale.value.inverseScaleY = 1 / containerScale().scaleY;
  183. const containerWidth = containerRef.value.clientWidth * containerScale().scaleX;
  184. const containerHeight = containerRef.value.clientHeight * containerScale().scaleY;
  185. width.value = containerWidth + 'px';
  186. height.value = containerHeight + 'px';
  187. yztMap.updateSize();
  188. };
  189. // 加载事件
  190. onMounted(() => {
  191. init();
  192. window.addEventListener('resize', handleResize);
  193. });
  194. // 卸载事件
  195. onUnmounted(() => {
  196. window.removeEventListener('resize', handleResize);
  197. });
  198. </script>
  199. <style scoped>
  200. .map-container {
  201. width: 100%;
  202. height: 100%;
  203. position: relative;
  204. .zoom-text {
  205. position: absolute;
  206. bottom: 120px;
  207. right: 170px;
  208. color: #eaf3fc;
  209. font-size: 25.73px;
  210. }
  211. .right-tool {
  212. position: absolute;
  213. bottom: 160px;
  214. right: 175px;
  215. z-index: 2;
  216. }
  217. .mask-btn {
  218. background-color: #04327c;
  219. font-size: 25.73px;
  220. border: 1px solid #91cfff;
  221. color: #eaf3fc;
  222. cursor: pointer;
  223. padding: 3px 3px;
  224. border-radius: 5px;
  225. //margin-right: 5px;
  226. cursor: pointer;
  227. }
  228. .model-btn {
  229. background-color: #04327c;
  230. font-size: 25.73px;
  231. font-family: 'SourceHanSansCN';
  232. border: 1px solid #91cfff;
  233. color: #eaf3fc;
  234. cursor: pointer;
  235. padding: 3px 3px;
  236. border-radius: 5px;
  237. }
  238. .ruler-icon {
  239. width: 42px;
  240. height: 42px;
  241. background: url('@/assets/images/map/ruler.png') no-repeat;
  242. background-size: 100% 100%;
  243. cursor: pointer;
  244. }
  245. :deep(.ol-scale-line) {
  246. left: unset;
  247. bottom: 16px;
  248. right: 48px;
  249. background-color: transparent;
  250. }
  251. :deep(.ol-scale-line-inner) {
  252. color: #ffffff;
  253. border: 1px solid #fff;
  254. border-top: none;
  255. }
  256. }
  257. </style>