map.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. <template>
  2. <div id="map-container"></div>
  3. </template>
  4. <script setup>
  5. import { ref, onMounted, onUnmounted } from "vue";
  6. import AMapLoader from "@amap/amap-jsapi-loader";
  7. import eventBus from "@/api/eventBus";
  8. import { convertPointToArray } from "@/utils/index";
  9. import { deepClone } from "@/common/commonFun";
  10. const map = ref(null);
  11. const mouseTool = ref(null);
  12. const selectedArea = ref(null);
  13. const selectedPoints = ref([]);
  14. const allPoints = ref([]);
  15. const defalutAllPoints = ref([])
  16. // 自定义圆点样式
  17. const createMarkerContent = (color = 'rgba(0, 0, 0, 0.4)') => {
  18. return `
  19. <div style="
  20. width: 15px;
  21. height: 15px;
  22. background-color: ${color};
  23. border: 1px solid #fff;
  24. border-radius: 50%;
  25. ">
  26. </div>
  27. `;
  28. }
  29. // 初始化地图
  30. const initMap = async () => {
  31. try {
  32. const AMap = await AMapLoader.load({
  33. key: "41769169f0f157e13a197e7eb0dd7b5b", // 替换为你的高德地图 Key
  34. version: "2.0", // SDK 版本
  35. plugins: ["AMap.MouseTool"], // 加载 MouseTool 插件
  36. }).then((AMap) => {
  37. // 创建地图实例
  38. map.value = new AMap.Map("map-container", {
  39. zoom: 18, // 初始缩放级别
  40. center: allPoints.value[0].lngLat,
  41. layers: [
  42. // 卫星
  43. new AMap.TileLayer.Satellite(),
  44. ],
  45. });
  46. // 初始化 MouseTool
  47. mouseTool.value = new AMap.MouseTool(map.value);
  48. // // 添加点位
  49. allPoints.value.forEach((point) => {
  50. point.icon = new AMap.Marker({
  51. position: point.lngLat,
  52. map: map.value,
  53. content: createMarkerContent(point.color),
  54. offset: new AMap.Pixel(-7, -7),
  55. });
  56. point.type = 'defalutIcon'
  57. // 绑定点击事件
  58. point.icon.on('click', () => {
  59. if(point.type === 'defalutIcon'){
  60. point.icon.setContent(createMarkerContent('#FFD489')); // 修改颜色
  61. point.type = 'activeIcon'
  62. }else{
  63. point.icon.setContent(createMarkerContent(point.color)); // 修改颜色
  64. point.type = 'defalutIcon'
  65. }
  66. });
  67. defalutAllPoints.value.push(point)
  68. });
  69. const latLngs = allPoints.value.map(item =>item.icon)
  70. map.value.setFitView(latLngs,{
  71. padding: [0, 0, 0, 0], // 上下左右的边距
  72. maxZoom: 18, // 最大缩放级别
  73. })
  74. startRectangleSelection()
  75. // 监听框选完成事件
  76. mouseTool.value.on("draw", (event) => {
  77. const { obj } = event;
  78. if (obj instanceof AMap.Rectangle) {
  79. selectedArea.value = obj;
  80. map.value.remove(selectedArea.value);
  81. checkPointsInArea(); // 检查框选区域内的点位
  82. }
  83. });
  84. });
  85. } catch (error) {
  86. console.error("地图加载失败:", error);
  87. }
  88. };
  89. const resetData = () =>{
  90. allPoints.value = defalutAllPoints.value
  91. allPoints.value.forEach(item =>{
  92. item.icon.setContent(createMarkerContent(item.color))
  93. item.type = 'defalutIcon'
  94. })
  95. }
  96. // 开始框选
  97. const startRectangleSelection = () => {
  98. if (mouseTool.value) {
  99. mouseTool.value.rectangle({
  100. strokeColor: "#ffffff", // 框选区域边框颜色
  101. strokeOpacity: 1, // 边框透明度
  102. strokeWeight: 2, // 边框宽度
  103. fillColor: "#000000", // 填充颜色
  104. fillOpacity: 0.5, // 填充透明度
  105. }); // 启用矩形框选工具
  106. }
  107. };
  108. // 清除框选
  109. const clearSelection = () => {
  110. if (selectedArea.value) {
  111. map.value.remove(selectedArea.value); // 移除框选区域
  112. selectedArea.value = null;
  113. resetData()
  114. selectedPoints.value = []; // 清空选中的点位
  115. }
  116. };
  117. // 检查框选区域内的点位
  118. const checkPointsInArea = () => {
  119. if (!selectedArea.value) return;
  120. const bounds = selectedArea.value.getBounds(); // 获取框选区域的边界
  121. selectedPoints.value = allPoints.value.filter((point) => {
  122. return bounds.contains(point.lngLat); // 判断点位是否在框选区域内
  123. });
  124. selectedPoints.value.forEach(item =>{
  125. if(item.type==='defalutIcon'){
  126. item.icon.setContent(createMarkerContent('#FFD489'))
  127. item.type = 'activeIcon'
  128. }else{
  129. item.icon.setContent(createMarkerContent(item.color))
  130. item.type = 'defalutIcon'
  131. }
  132. })
  133. const arr = selectedPoints.value.filter(item =>item.type==='activeIcon')
  134. eventBus.emit('map:list',arr)
  135. };
  136. const speciesArr = ref([])
  137. const getList = () =>{
  138. const params = {
  139. farmId:sessionStorage.getItem('farmId'),
  140. regionId:sessionStorage.getItem('regionId')
  141. }
  142. VE_API.variety.pointList(params).then(res =>{
  143. allPoints.value = res.data.map(item =>{
  144. const bgColor = speciesArr.value.filter(ele =>ele.speciesItemId === item.speciesItemId)
  145. return{
  146. ...item,
  147. color:bgColor[0].color,
  148. lngLat:convertPointToArray(item.point)
  149. }
  150. })
  151. initMap()
  152. })
  153. }
  154. function getSpeciesList(arr){
  155. speciesArr.value = arr
  156. getList()
  157. }
  158. // 组件挂载时初始化地图
  159. onMounted(() => {
  160. eventBus.on('handle:clear',clearSelection)
  161. eventBus.on('species:list',getSpeciesList)
  162. });
  163. onUnmounted(()=>{
  164. map.value.destroy()// 销毁地图实例以释放资源
  165. eventBus.off('handle:clear',clearSelection)
  166. eventBus.off('species:list',getSpeciesList)
  167. })
  168. </script>
  169. <style scoped>
  170. #map-container {
  171. width: 100%;
  172. height: 100%;
  173. }
  174. </style>