|
@@ -0,0 +1,284 @@
|
|
|
|
+<template>
|
|
|
|
+ <div id="map-container"></div>
|
|
|
|
+</template>
|
|
|
|
+
|
|
|
|
+<script setup>
|
|
|
|
+import { ref, onMounted, onUnmounted } from "vue";
|
|
|
|
+import AMapLoader from "@amap/amap-jsapi-loader";
|
|
|
|
+import eventBus from "@/api/eventBus";
|
|
|
|
+import { convertPointToArray } from "@/utils/index";
|
|
|
|
+import { deepClone } from "@/common/commonFun";
|
|
|
|
+import {base_img_url,base_img_url3} from "@/api/config";
|
|
|
|
+
|
|
|
|
+const map = ref(null);
|
|
|
|
+const mouseTool = ref(null);
|
|
|
|
+const selectedArea = ref(null);
|
|
|
|
+const selectedPoints = ref([]);
|
|
|
|
+const allPoints = ref([]);
|
|
|
|
+const defalutAllPoints = ref([])
|
|
|
|
+const pointList = ref([])
|
|
|
|
+
|
|
|
|
+const mapEventType = ref('rectangle')
|
|
|
|
+
|
|
|
|
+// 自定义圆点样式
|
|
|
|
+const createMarkerContent = (color = 'rgba(0, 0, 0, 0.4)') => {
|
|
|
|
+ return `
|
|
|
|
+ <div style="
|
|
|
|
+ width: 15px;
|
|
|
|
+ height: 15px;
|
|
|
|
+ background-color: ${color};
|
|
|
|
+ border: 1px solid #fff;
|
|
|
|
+ border-radius: 50%;
|
|
|
|
+ ">
|
|
|
|
+ </div>
|
|
|
|
+ `;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//高亮样式
|
|
|
|
+const createMarkerImg = () => {
|
|
|
|
+ return `
|
|
|
|
+ <img style="width: 38px;height: 38px;" src="${require('@/assets/images/map/status/active-icon.png')}">
|
|
|
|
+ `;
|
|
|
|
+}
|
|
|
|
+// 初始化地图
|
|
|
|
+const initMap = async () => {
|
|
|
|
+ try {
|
|
|
|
+ const AMap = await AMapLoader.load({
|
|
|
|
+ key: "41769169f0f157e13a197e7eb0dd7b5b", // 替换为你的高德地图 Key
|
|
|
|
+ version: "2.0", // SDK 版本
|
|
|
|
+ plugins: ["AMap.MouseTool","AMap.MarkerCluster"], // 加载 MouseTool 插件
|
|
|
|
+ }).then(async (AMap) => {
|
|
|
|
+ // 创建地图实例
|
|
|
|
+ map.value = new AMap.Map("map-container", {
|
|
|
|
+ zoom: 18, // 初始缩放级别
|
|
|
|
+ center: [113.6149629 ,23.58594117],
|
|
|
|
+ layers: [
|
|
|
|
+ // 天地图卫星
|
|
|
|
+ new AMap.TileLayer({
|
|
|
|
+ tileSize: 256, // 瓦片大小
|
|
|
|
+ getTileUrl: function(x, y, z) {
|
|
|
|
+ // 天地图影像 WMTS 地址
|
|
|
|
+ const s = Math.floor(Math.random() * 8); // 随机选择服务器节点
|
|
|
|
+ return `https://t${s}.tianditu.gov.cn/img_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=img&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=${z}&TILEROW=${y}&TILECOL=${x}&tk=e95115c454a663cd052d96019fd83840`;
|
|
|
|
+ },
|
|
|
|
+ }),
|
|
|
|
+ //天地图路网
|
|
|
|
+ new AMap.TileLayer({
|
|
|
|
+ tileSize: 256, // 瓦片大小
|
|
|
|
+ getTileUrl: function(x, y, z) {
|
|
|
|
+ // 天地图影像 WMTS 地址
|
|
|
|
+ const s = Math.floor(Math.random() * 8); // 随机选择服务器节点
|
|
|
|
+ return `https://t${s}.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX=${z}&TILEROW=${y}&TILECOL=${x}&tk=e95115c454a663cd052d96019fd83840`;
|
|
|
|
+ },
|
|
|
|
+ }),
|
|
|
|
+ //正射影像
|
|
|
|
+ new AMap.TileLayer({
|
|
|
|
+ tileUrl: base_img_url + 'map/lby/[z]/[x]/[y].png',
|
|
|
|
+ zIndex:2
|
|
|
|
+ }),
|
|
|
|
+ new AMap.TileLayer({
|
|
|
|
+ tileUrl: base_img_url3 + 'map/lby/[z]/[x]/[y].png',
|
|
|
|
+ zIndex:2
|
|
|
|
+ })
|
|
|
|
+ ],
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ // // 初始化点聚合
|
|
|
|
+ // const cluster = new AMap.MarkerCluster(map, markers, {
|
|
|
|
+ // gridSize: 60, // 聚合网格像素大小
|
|
|
|
+ // maxZoom: 15, // 最大聚合级别
|
|
|
|
+ // renderClusterMarker: customizeCluster // 自定义聚合样式
|
|
|
|
+ // });
|
|
|
|
+
|
|
|
|
+ // 初始化 MouseTool
|
|
|
|
+ mouseTool.value = new AMap.MouseTool(map.value);
|
|
|
|
+
|
|
|
|
+ // startRectangleSelection()
|
|
|
|
+
|
|
|
|
+ // 监听框选完成事件
|
|
|
|
+ mouseTool.value.on("draw", (event) => {
|
|
|
|
+ if(mapEventType.value==='click') return
|
|
|
|
+ const { obj} = event;
|
|
|
|
+ if (obj instanceof AMap.Rectangle) {
|
|
|
|
+ selectedArea.value = obj;
|
|
|
|
+ map.value.remove(selectedArea.value);
|
|
|
|
+ checkPointsInArea(); // 检查框选区域内的点位
|
|
|
|
+ }
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ });
|
|
|
|
+ } catch (error) {
|
|
|
|
+ console.error("地图加载失败:", error);
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+//重置数据
|
|
|
|
+const resetData = () =>{
|
|
|
|
+ allPoints.value = defalutAllPoints.value
|
|
|
|
+ allPoints.value.forEach(item =>{
|
|
|
|
+ item.icon.setContent(createMarkerContent(item.color))
|
|
|
|
+ item.icon.setOffset(new window.AMap.Pixel(-7, -7))
|
|
|
|
+ item.type = 'defalutIcon'
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+//初始化数据
|
|
|
|
+const initData = (data) =>{
|
|
|
|
+ allPoints.value = data
|
|
|
|
+ defalutAllPoints.value = []
|
|
|
|
+ totalList.value.forEach(item => map.value.remove(item.icon))
|
|
|
|
+ totalList.value = []
|
|
|
|
+ // allPoints.value.forEach(item =>{
|
|
|
|
+ // item.icon = new window.AMap.Marker({
|
|
|
|
+ // position: item.lngLat,
|
|
|
|
+ // map: map.value,
|
|
|
|
+ // content: createMarkerContent(item.color),
|
|
|
|
+ // offset: new window.AMap.Pixel(-7, -7),
|
|
|
|
+ // extData: { id: item.id, priority: item.status > item.noImg > item.wys } // 标记优先级
|
|
|
|
+ // });
|
|
|
|
+ // item.type = 'defalutIcon'
|
|
|
|
+
|
|
|
|
+ // // 绑定点击事件
|
|
|
|
+ // item.icon.on('click', () => {
|
|
|
|
+ // mapEventType.value = 'click'
|
|
|
|
+ // if(item.type === 'defalutIcon'){
|
|
|
|
+ // item.icon.setContent(createMarkerImg());
|
|
|
|
+ // item.icon.setOffset(new window.AMap.Pixel(-18, -18))
|
|
|
|
+ // item.type = 'activeIcon'
|
|
|
|
+ // const arr = pointList.value.filter(ele => ele.id === item.id)
|
|
|
|
+ // if(arr.length===0){
|
|
|
|
+ // pointList.value.push(item)
|
|
|
|
+ // }
|
|
|
|
+ // }else{
|
|
|
|
+ // item.icon.setContent(createMarkerContent(item.color));
|
|
|
|
+ // item.icon.setOffset(new window.AMap.Pixel(-7, -7))
|
|
|
|
+ // item.type = 'defalutIcon'
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ // setTimeout(()=>{
|
|
|
|
+ // mapEventType.value = 'draw'
|
|
|
|
+ // },100)
|
|
|
|
+ // });
|
|
|
|
+ // defalutAllPoints.value.push(item)
|
|
|
|
+ // })
|
|
|
|
+ // 初始化点聚合
|
|
|
|
+ console.log('data',data);
|
|
|
|
+ const cluster = new window.AMap.MarkerCluster(map.value, data, {
|
|
|
|
+ gridSize: 60, // 聚合网格像素大小
|
|
|
|
+ // maxZoom: 15, // 最大聚合级别
|
|
|
|
+ // renderClusterMarker: customizeCluster // 自定义聚合样式
|
|
|
|
+ });
|
|
|
|
+ setTimeout(()=>{
|
|
|
|
+ map.value.setFitView(null, false, [0, 0, 0, 0]);
|
|
|
|
+ },100)
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 开始框选
|
|
|
|
+const startRectangleSelection = () => {
|
|
|
|
+ if (mouseTool.value) {
|
|
|
|
+ mouseTool.value.rectangle({
|
|
|
|
+ strokeColor: "#ffffff", // 框选区域边框颜色
|
|
|
|
+ strokeOpacity: 1, // 边框透明度
|
|
|
|
+ strokeWeight: 2, // 边框宽度
|
|
|
|
+ fillColor: "#000000", // 填充颜色
|
|
|
|
+ fillOpacity: 0.5, // 填充透明度
|
|
|
|
+ }); // 启用矩形框选工具
|
|
|
|
+ map.value.setDefaultCursor("crosshair");
|
|
|
|
+ }
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+ // 停止绘制矩形
|
|
|
|
+const stopDrawRectangle = () => {
|
|
|
|
+ mouseTool.value.close(); // 关闭 mouseTool
|
|
|
|
+ map.value.setDefaultCursor("default");
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 清除框选
|
|
|
|
+const clearSelection = () => {
|
|
|
|
+ if (selectedArea.value) {
|
|
|
|
+ map.value.remove(selectedArea.value); // 移除框选区域
|
|
|
|
+ selectedArea.value = null;
|
|
|
|
+ }
|
|
|
|
+ resetData()
|
|
|
|
+ selectedPoints.value = []; // 清空选中的点位
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+// 检查框选区域内的点位
|
|
|
|
+const checkPointsInArea = () => {
|
|
|
|
+ if (!selectedArea.value) return;
|
|
|
|
+ const bounds = selectedArea.value.getBounds(); // 获取框选区域的边界
|
|
|
|
+ selectedPoints.value = allPoints.value.filter((point) => {
|
|
|
|
+ return bounds.contains(point.lngLat); // 判断点位是否在框选区域内
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ selectedPoints.value.forEach(item =>{
|
|
|
|
+ if(item.type==='defalutIcon'){
|
|
|
|
+ item.icon.setContent(createMarkerImg())
|
|
|
|
+ item.icon.setOffset(new window.AMap.Pixel(-18, -18))
|
|
|
|
+ item.type = 'activeIcon'
|
|
|
|
+ }else{
|
|
|
|
+ item.icon.setContent(createMarkerContent(item.color))
|
|
|
|
+ item.icon.setOffset(new window.AMap.Pixel(-7, -7))
|
|
|
|
+ item.type = 'defalutIcon'
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+const speciesArr = ref([])
|
|
|
|
+const getList = () =>{
|
|
|
|
+ const params = {
|
|
|
|
+ farmId:sessionStorage.getItem('farmId'),
|
|
|
|
+ regionId:sessionStorage.getItem('regionId')
|
|
|
|
+ }
|
|
|
|
+ VE_API.variety.pointList(params).then(res =>{
|
|
|
|
+ allPoints.value = res.data.map(item =>{
|
|
|
|
+ const bgColor = speciesArr.value.filter(ele =>ele.speciesItemId === item.speciesItemId)
|
|
|
|
+ return{
|
|
|
|
+ ...item,
|
|
|
|
+ color:bgColor[0].color,
|
|
|
|
+ lngLat:convertPointToArray(item.point)
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+ initData()
|
|
|
|
+ })
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+const totalList = ref([])
|
|
|
|
+
|
|
|
|
+function getSelectPoint(){
|
|
|
|
+ totalList.value = selectedPoints.value.concat(pointList.value)
|
|
|
|
+ const arr = totalList.value.filter(item =>item.type==='activeIcon')
|
|
|
|
+ return arr
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+defineExpose({getSelectPoint,initData})
|
|
|
|
+
|
|
|
|
+function getSpeciesList(arr){
|
|
|
|
+ speciesArr.value = arr
|
|
|
|
+ getList()
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+// 组件挂载时初始化地图
|
|
|
|
+onMounted(() => {
|
|
|
|
+ initMap()
|
|
|
|
+ eventBus.on('handle:clear',clearSelection)
|
|
|
|
+ eventBus.on('species:list',getSpeciesList)
|
|
|
|
+ eventBus.on('handle:start',startRectangleSelection)
|
|
|
|
+ eventBus.on('handle:end',stopDrawRectangle)
|
|
|
|
+});
|
|
|
|
+
|
|
|
|
+onUnmounted(()=>{
|
|
|
|
+ map.value.destroy()// 销毁地图实例以释放资源
|
|
|
|
+ eventBus.off('handle:clear',clearSelection)
|
|
|
|
+ eventBus.off('species:list',getSpeciesList)
|
|
|
|
+ eventBus.off('handle:start',startRectangleSelection)
|
|
|
|
+ eventBus.off('handle:end',stopDrawRectangle)
|
|
|
|
+})
|
|
|
|
+</script>
|
|
|
|
+
|
|
|
|
+<style scoped>
|
|
|
|
+#map-container {
|
|
|
|
+ width: 100%;
|
|
|
|
+ height: 100%;
|
|
|
|
+}
|
|
|
|
+</style>
|