|
@@ -52,9 +52,6 @@
|
|
|
</div>
|
|
|
<div class="draw-item" @click="openDraw">{{ mouseToolState.drawing ? '关闭绘制' : '开启绘制' }}</div>
|
|
|
<div class="draw-item" @click="handleUndo">撤销</div>
|
|
|
- <div id="menu-box">
|
|
|
- <div class="menu-item">删除</div>
|
|
|
- </div>
|
|
|
</div>
|
|
|
</template>
|
|
|
|
|
@@ -63,6 +60,7 @@ import { useHistory } from '@/hooks/useHistory';
|
|
|
import { nanoid } from 'nanoid';
|
|
|
import { deepClone } from '@/utils';
|
|
|
import * as turf from '@turf/turf';
|
|
|
+import Overlay from 'ol/Overlay';
|
|
|
|
|
|
interface ListItem {
|
|
|
label: string;
|
|
@@ -74,6 +72,7 @@ const props = defineProps({
|
|
|
const AMapType = ['vectorgraph', 'satellite'];
|
|
|
const getDrawTool = inject('getDrawTool');
|
|
|
const getMap = inject('getMap');
|
|
|
+const getMapUtils = inject('getMapUtils');
|
|
|
const emits = defineEmits(['handleAnalysisData']);
|
|
|
const { currentState, commit, undo, history, future } = useHistory();
|
|
|
const mouseToolState = reactive({
|
|
@@ -84,6 +83,13 @@ const mouseToolState = reactive({
|
|
|
// 图形形状 circle圆形 rectangle矩形 polygon多边形
|
|
|
graphicsType: 'circle'
|
|
|
});
|
|
|
+let popup;
|
|
|
+let map = computed(() => {
|
|
|
+ return getMap();
|
|
|
+});
|
|
|
+let mapUtils = computed(() => {
|
|
|
+ return getMapUtils();
|
|
|
+});
|
|
|
watch(
|
|
|
mouseToolState,
|
|
|
() => {
|
|
@@ -97,10 +103,14 @@ watch(
|
|
|
drawTool.getMouseTool().on('draw', onDraw);
|
|
|
} else {
|
|
|
drawTool.getMouseTool().on('drawend', onDraw2);
|
|
|
+ map.value.un('click', onMapClick);
|
|
|
}
|
|
|
} else {
|
|
|
mouseToolState.drawing = false;
|
|
|
drawTool.closeDraw();
|
|
|
+ if (!AMapType.includes(props.activeMap)) {
|
|
|
+ map.value.on('click', onMapClick);
|
|
|
+ }
|
|
|
}
|
|
|
},
|
|
|
{
|
|
@@ -234,61 +244,38 @@ const onDraw2 = (event) => {
|
|
|
const geometryType = geometry.getType();
|
|
|
const id = nanoid();
|
|
|
feature.set('id', id);
|
|
|
+ feature.set('dotType', 'analysisSpatial');
|
|
|
const data: any = {
|
|
|
id: id,
|
|
|
type: drawOptions.graphicsType,
|
|
|
- // color: feature._opts.strokeColor,
|
|
|
- // drawType: feature._opts.fillOpacity === 0 ? '1' : '2'
|
|
|
+ color: drawOptions.color,
|
|
|
+ drawType: drawOptions.drawType
|
|
|
};
|
|
|
- // 获取绘制的几何信息(包括经纬度)
|
|
|
- if (geometryType === 'Point') {
|
|
|
- const coordinates = geometry.getCoordinates();
|
|
|
- console.log('绘制了一个点:', coordinates);
|
|
|
- } else if (geometryType === 'LineString') {
|
|
|
- const coordinates = geometry.getCoordinates();
|
|
|
- console.log('绘制了一条线:', coordinates);
|
|
|
- // 线的坐标是点的数组,每个点都是一个经纬度数组
|
|
|
- } else if (geometryType === 'Polygon') {
|
|
|
- const coordinates = geometry.getCoordinates();
|
|
|
- console.log('绘制了一个多边形:', coordinates);
|
|
|
- // 多边形的坐标是环的数组,每个环是点的数组,每个点都是一个经纬度数组
|
|
|
- } else if (geometryType === 'Circle') {
|
|
|
+ feature.set('extraData', data);
|
|
|
+ if (geometryType === 'Circle') {
|
|
|
data.center = geometry.getCenter();
|
|
|
data.radius = geometry.getRadius();
|
|
|
const data2 = turf.sector(data.center, data.radius, 0, 360);
|
|
|
const pathArr = data2.geometry.coordinates[0];
|
|
|
data.path = pathArr;
|
|
|
- console.log('绘制了一个圆:', data);
|
|
|
+ } else if (geometryType === 'Polygon') {
|
|
|
+ const coordinates = geometry.getCoordinates();
|
|
|
+ data.path = coordinates[0];
|
|
|
}
|
|
|
- // const path = geometry.getCoordinates();
|
|
|
- // debugger
|
|
|
- // // 将AMap.LngLat对象数组转换为经纬度数组
|
|
|
- // const pathArr = path.map((lngLat) => {
|
|
|
- // // 返回经度和纬度的数组
|
|
|
- // return [lngLat.lng, lngLat.lat];
|
|
|
- // });
|
|
|
- // data.path = pathArr;
|
|
|
overlays.push(feature);
|
|
|
overlaysData.push(data);
|
|
|
commit(deepClone(overlaysData));
|
|
|
// 右击进入编辑
|
|
|
- feature.on('contextmenu', handleRightClick);
|
|
|
+ let map = getMap();
|
|
|
+ map.on('contextmenu', handleRightClick2);
|
|
|
if (overlaysData.length === 1) {
|
|
|
analysisSpatial(data);
|
|
|
}
|
|
|
- // // 点击空间分析
|
|
|
- // feature.on('click', function () {
|
|
|
- // // 没在编辑时
|
|
|
- // if (!mouseToolState.drawing) {
|
|
|
- // analysisSpatial(data);
|
|
|
- // }
|
|
|
- // });
|
|
|
};
|
|
|
let rightClickObj;
|
|
|
// 图形右击事件
|
|
|
let initContextMenu = false;
|
|
|
const handleRightClick = (event) => {
|
|
|
- debugger
|
|
|
rightClickObj = event.target;
|
|
|
const contextMenu = getDrawTool().getContextMenu();
|
|
|
if (!initContextMenu) {
|
|
@@ -305,13 +292,67 @@ const handleRightClick = (event) => {
|
|
|
}
|
|
|
contextMenu.open(getMap(), event.lnglat);
|
|
|
};
|
|
|
+const handleRightClick2 = (event) => {
|
|
|
+ event.preventDefault(); // 阻止默认的右键菜单弹出
|
|
|
+ map.value.un('click', onMapClick);
|
|
|
+ if (popup) {
|
|
|
+ map.value.removeOverlay(popup);
|
|
|
+ popup = undefined;
|
|
|
+ }
|
|
|
+ rightClickObj = map.value.forEachFeatureAtPixel(event.pixel, (feature2) => {
|
|
|
+ return feature2;
|
|
|
+ });
|
|
|
+ let dotType = rightClickObj.get('dotType');
|
|
|
+ if (!!rightClickObj && dotType === 'analysisSpatial') {
|
|
|
+ const dom = document.createElement('div');
|
|
|
+ const dom2 = document.createElement('div');
|
|
|
+ dom.id = 'analysisSpatial-popup';
|
|
|
+ dom2.className = 'menu-item';
|
|
|
+ dom2.innerHTML = '删除';
|
|
|
+ dom2.onclick = function () {
|
|
|
+ map.value.on('click', onMapClick);
|
|
|
+ deleteGraphics();
|
|
|
+ };
|
|
|
+ dom.appendChild(dom2);
|
|
|
+ popup = new Overlay({
|
|
|
+ element: dom,
|
|
|
+ autoPan: true,
|
|
|
+ positioning: 'bottom-right',
|
|
|
+ stopEvent: false,
|
|
|
+ offset: [0, 0]
|
|
|
+ });
|
|
|
+
|
|
|
+ const geometry = rightClickObj.getGeometry();
|
|
|
+ const geometryType = geometry.getType();
|
|
|
+ let coordinate = [];
|
|
|
+ if (geometryType === 'Circle') {
|
|
|
+ coordinate = geometry.getCenter();
|
|
|
+ } else {
|
|
|
+ const points = geometry.getCoordinates();
|
|
|
+ const features = turf.points(points[0]);
|
|
|
+ const center = turf.center(features);
|
|
|
+ if (center && center.geometry && center.geometry.coordinates) {
|
|
|
+ coordinate = center.geometry.coordinates;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ popup.setPosition(coordinate);
|
|
|
+ map.value.addOverlay(popup);
|
|
|
+ }
|
|
|
+};
|
|
|
// 删除图形
|
|
|
const deleteGraphics = () => {
|
|
|
- const id = rightClickObj.getExtData()?.id;
|
|
|
- if (id) {
|
|
|
+ let id;
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ id = rightClickObj.getExtData()?.id;
|
|
|
+ } else {
|
|
|
+ unMapClick();
|
|
|
+ id = rightClickObj.get('id');
|
|
|
+ }
|
|
|
+ if (!!id) {
|
|
|
for (let i = 0; i < overlays.length; i++) {
|
|
|
const overlay = Array.isArray(overlays[i]) ? overlays[i][0] : overlays[i];
|
|
|
- if (overlay?.getExtData().id === id) {
|
|
|
+ const itemId = AMapType.includes(props.activeMap) ? overlay?.getExtData().id : overlay.get('id');
|
|
|
+ if (itemId === id) {
|
|
|
removeOverlayByIndex(i);
|
|
|
commit(deepClone(overlaysData));
|
|
|
rightClickObj = null;
|
|
@@ -351,14 +392,21 @@ const handleUndo = () => {
|
|
|
strokeOpacity: 1,
|
|
|
strokeWeight: '1',
|
|
|
fillColor: restoreData.color,
|
|
|
- fillOpacity: restoreData.drawType === '1' ? 0 : 0.5
|
|
|
+ fillOpacity: restoreData.drawType === '1' ? '0' : '0.5'
|
|
|
};
|
|
|
if (restoreData.type === 'circle') {
|
|
|
newData.center = restoreData.center;
|
|
|
newData.radius = restoreData.radius;
|
|
|
}
|
|
|
- const obj = getDrawTool().createGraphics(newData);
|
|
|
- overlays.push(obj);
|
|
|
+ let obj;
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ obj = getDrawTool().createGraphics(newData);
|
|
|
+ } else {
|
|
|
+ obj = getDrawTool().createGraphics(newData);
|
|
|
+ }
|
|
|
+ if (!!obj) {
|
|
|
+ overlays.push(obj);
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
undo();
|
|
@@ -369,15 +417,28 @@ const handleUndo = () => {
|
|
|
// 根据索引移除覆盖物
|
|
|
const removeOverlayByIndex = (index: number) => {
|
|
|
const map = getMap();
|
|
|
- if (Array.isArray(overlays[index])) {
|
|
|
- overlays[index].forEach((overlay) => {
|
|
|
+ if (AMapType.includes(props.activeMap)) {
|
|
|
+ if (Array.isArray(overlays[index])) {
|
|
|
+ overlays[index].forEach((overlay) => {
|
|
|
+ // 移除地图上覆盖物
|
|
|
+ map.remove(overlay);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
// 移除地图上覆盖物
|
|
|
- map.remove(overlay);
|
|
|
- });
|
|
|
+ map.remove(overlays[index]);
|
|
|
+ }
|
|
|
} else {
|
|
|
- // 移除地图上覆盖物
|
|
|
- map.remove(overlays[index]);
|
|
|
+ if (Array.isArray(overlays[index])) {
|
|
|
+ overlays[index].forEach((overlay) => {
|
|
|
+ // 移除地图上覆盖物
|
|
|
+ mapUtils.value.getDrawVector().getSource().removeFeature(overlay);
|
|
|
+ });
|
|
|
+ } else {
|
|
|
+ // 移除地图上覆盖物
|
|
|
+ mapUtils.value.getDrawVector().getSource().removeFeature(overlays[index]);
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
overlays.splice(index, 1);
|
|
|
overlaysData.splice(index, 1);
|
|
|
};
|
|
@@ -410,30 +471,35 @@ const analysisSpatial = (data) => {
|
|
|
}
|
|
|
emits('handleAnalysisData', location);
|
|
|
};
|
|
|
+const onMapClick = (event) => {
|
|
|
+ // 没在编辑时
|
|
|
+ if (!mouseToolState.drawing && event.pixel) {
|
|
|
+ const feature = map.value.forEachFeatureAtPixel(event.pixel, (feature2) => {
|
|
|
+ return feature2;
|
|
|
+ });
|
|
|
+ const data = feature.get('extraData');
|
|
|
+ analysisSpatial(data);
|
|
|
+ }
|
|
|
+ unMapClick(event);
|
|
|
+};
|
|
|
+const unMapClick = (event) => {
|
|
|
+ const overlayElement = popup?.getElement();
|
|
|
+ const isClickOnOverlay =
|
|
|
+ event && overlayElement && (overlayElement.contains(event.originalEvent.target) || overlayElement === event.originalEvent.target);
|
|
|
+ if (!isClickOnOverlay && popup) {
|
|
|
+ map.value.removeOverlay(popup);
|
|
|
+ popup = undefined;
|
|
|
+ }
|
|
|
+};
|
|
|
onMounted(() => {
|
|
|
- // 监听右击事件
|
|
|
- getMap().on('contextmenu', (event) => {
|
|
|
- event.preventDefault(); // 阻止默认上下文菜单
|
|
|
-
|
|
|
- // 获取右击位置的要素
|
|
|
- const featuresAtPixel = getMap().getFeaturesAtPixel(event.pixel);
|
|
|
-
|
|
|
- // 检查是否有要素在右击位置
|
|
|
- if (featuresAtPixel && featuresAtPixel.length > 0) {
|
|
|
- // 遍历要素并检查条件(这里可以根据需要添加条件)
|
|
|
- featuresAtPixel.forEach(function(feature) {
|
|
|
- // 执行你想要的动作,例如显示一个信息框或弹出菜单
|
|
|
- console.log('右击了要素:', feature.get('id')); // 假设要素有一个'id'属性
|
|
|
-
|
|
|
- // 你可以在这里显示一个自定义的右击菜单
|
|
|
- // 例如,创建一个<div>元素,设置其内容和样式,然后添加到DOM中
|
|
|
- // 并监听菜单项的点击事件来执行相应的动作
|
|
|
- });
|
|
|
- }
|
|
|
- });
|
|
|
-})
|
|
|
+ if (!AMapType.includes(props.activeMap)) {
|
|
|
+ map.value.on('click', onMapClick);
|
|
|
+ }
|
|
|
+});
|
|
|
onBeforeUnmount(() => {
|
|
|
- //
|
|
|
+ if (!AMapType.includes(props.activeMap)) {
|
|
|
+ map.value.un('click', onMapClick);
|
|
|
+ }
|
|
|
});
|
|
|
</script>
|
|
|
|
|
@@ -497,9 +563,20 @@ onBeforeUnmount(() => {
|
|
|
.active {
|
|
|
background-color: rgba(22, 73, 142, 0.5);
|
|
|
}
|
|
|
-.menu-box {
|
|
|
+</style>
|
|
|
+<style>
|
|
|
+#analysisSpatial-popup {
|
|
|
+ background-color: #ffffff;
|
|
|
+ border-radius: 4px;
|
|
|
+ cursor: pointer;
|
|
|
+ &:hover {
|
|
|
+ background-color: #f3f3ee;
|
|
|
+ }
|
|
|
.menu-item {
|
|
|
- font-size: 32px;
|
|
|
+ font-size: 14px;
|
|
|
+ padding: 0 8px;
|
|
|
+ height: 28px;
|
|
|
+ line-height: 28px;
|
|
|
}
|
|
|
}
|
|
|
</style>
|