CaiYuanYiTiHua/src/components/MapboxMaps/MapComponent.vue

896 lines
23 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<template>
<div class="map-container">
<div id="mapContainer" class="map-box"></div>
<!-- 图层控制 -->
<div class="layer-control-center" v-if="false">
<a-collapse v-model:activeKey="activeKey" accordion expandIconPosition="end" expandIcon="">
<a-collapse-panel key="1" header="图层">
<p v-for="(item, index) in props.mapConfig.layers" class="layer-item">
<a-checkbox v-model:checked="item.checked" @change="handlerCheckboxChange(item)">{{
item.name
}}</a-checkbox>
</p>
<p v-for="(item, index) in props.mapConfig.baseLayers" class="layer-item">
<a-checkbox v-model:checked="item.checked" @change="handlerCheckboxChange(item)">{{
item.name
}}</a-checkbox>
</p>
</a-collapse-panel>
</a-collapse>
</div>
<!-- 绘图控制 -->
<div class="draw-control-center" v-show="drawing">
<div class="draw-btn" @click="handlerCancleDraw"> 取消 </div>
<div class="draw-btn" @click="handlerDrawComplete"> 保存 </div>
</div>
</div>
</template>
<script lang="ts" setup>
import {
onMounted,
onUnmounted,
defineProps,
defineEmits,
reactive,
ref,
defineExpose,
} from 'vue';
import { useMessage } from '@/hooks/web/useMessage';
import mapboxgl, { Map, Popup } from 'mapbox-gl';
// 图形绘制工具类
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import { generateUUID,getGeometryCenter } from './src/tool'
// 测量工具
import { SwitchLayerControl,MeasureControl,SwitchMapControl } from 'mapbox-extensions'
import 'mapbox-extensions/dist/index.css'
import U from 'mapbox-gl-utils';
import 'mapbox-gl/dist/mapbox-gl.css';
import './src/index.less';
import { MapboxConfig, MapboxDefaultStyle, MapControlConfig } from './src/config';
import { MP } from './src/MP';
import { DrawingType } from '@/enums/mapEnum';
import {
SnapPolygonMode,
SnapPointMode,
SnapLineMode,
SnapModeDrawStyles,
SnapDirectSelect,
} from 'mapbox-gl-draw-snap-mode';
import { customDrawStyles } from './Styles/Styles';
import Drawtool from '@/views/datamaintenance/components/drawtool.vue';
import { WktToGeojson, GeojsonToWkt } from './src/WktGeojsonTransform';
import { features } from 'process';
const openModal = ref(false);
const insertShpModal = ref(false);
const changeOpenModal = (value) => {
openModal.value = value;
};
const changeOpenInsertShpModal = (value) => {
insertShpModal.value = value;
};
// map参数类型
interface MapboxOptionsInterface {
mapOptions: mapboxgl.MapboxOptions;
control: DrawingType[];
}
const props = defineProps({
mapConfig:{
type:Object,
default:{}
},
layers: {
type: Array,
default: [],
},
location: {
type: Array,
default: [],
},
type: {
type: String,
default: '',
},
feature: {
type: String,
default: '',
},
});
console.log("mapConfig",props.mapConfig);
let nextMapControl: Array<any> = reactive([]);
nextMapControl = props.control
? props.control.map((item) => {
return MapControlConfig[item];
})
: [];
// 定义地图容器
let map: Map;
let drawTool: any;
let popup: Popup;
let clickPoisition: Array<number> = [];
let selectFeature: Object = {};
let mp: any = null;
let geojson = reactive({
geojson: {},
});
let drawing = ref(false);
let drawGeojson = reactive({
geojson: {
type: 'FeatureCollection',
features: [],
},
});
const { createConfirm, createMessage } = useMessage();
// 定义地图回调emit
// 地图加载完成回调
const emit = defineEmits(['mapOnLoad', 'mapDraw', 'handlerDrawComplete']);
onMounted(() => {
mapboxgl.accessToken = MapboxConfig.ACCESS_TOKEN;
map = initMap();
map.on('load', () => {
// 根据地图配置信息加载地形数据
if(props.mapConfig.mode == "3D"){
handlerLoadTerrain();
}
// 初始化绘图空间
// handlerInitDrawTool(null);
map.on('click', (e) => {
// handlerPreviewFeatureInfo(e);
clickPoisition = e.lngLat;
});
map.on('draw.selectionchange', (e) => {
// handlerCopyToTargetLayer(e);
});
emit('mapOnLoad', map);
// 设置绘图监听事件
map.on('draw.create', function (e) {
drawGeojson.geojson.features = e.features;
handlerDealFeature(e.features[0]);
});
map.on('draw.update', function (e) {
drawGeojson.geojson = e.features;
handlerDealFeature(e.features[0]);
});
map.on('draw.delete', function (e) {
handlerDeleteFeature(e.features[0]);
});
window.handlerCopyFeature = handlerCopyFeature;
// 测量工具
map.addControl(new MeasureControl({
horizontal : true, //default false
btnBgColor : '#ffffff', //default '#ffffff'
btnActiveColor:'#ddd', //default '#ddd'
geometryClick:true, //defualt false
enableModes:['Point','LineString','Polygon'],//default all
onStart:()=>{},
onStop:()=>{},
measurePointOptions:{
},
measureLineStringOptions:{
},
measurePolygonOptions:{
}
}),"top-right")
let applicationLayers = []
let baseLayers = [];
props.mapConfig.layers?.forEach((item,index)=>{
let style = JSON.parse(item.style)
let layers = {
name:item.name,
layer:style,
fixed:true,
zoom:-100,
easeToOptions:{},
mutex:true,
mutexIdentity:"t1",
active:false,
backgroundImage:"",
backgroundImageActive:"",
onVisibleChange:(visible:boolean)=>{}
}
applicationLayers.push(layers)
})
props.mapConfig.baseLayers?.forEach((item,index)=>{
let layers = {
name:item.name,
layer: item.layer,
fixed:true,
zoom:-100,
easeToOptions:{},
mutex:true,
mutexIdentity:index,
active:false,
backgroundImage:"http://lbs.tianditu.gov.cn/images/cia_c.png",
backgroundImageActive:"",
onVisibleChange:(visible:boolean)=>{}
}
baseLayers.push(layers)
})
map.addControl(new SwitchLayerControl({
name:"图层管理" ,
position:"top-left",
selectAndClearAll:true,
selectAllLabel:"select all",
clearAllLabel:"clear all",
showToTop:true,
topLayerId:"",
layerGroups:{
"应用图层":{
mutex:true,
collapse:true,
uiType:"SwitchBtn",
layers:applicationLayers
},
"地图底图":{
mutex:true,
collapse:true,
uiType:"ImgTxtBtn",
layers:baseLayers
},
}
}),"top-left");
});
});
// 销毁地图
// 加载地形
const handlerLoadTerrain = () => {
map.addSource('mapbox-dem', {
'type': 'raster-dem',
'url': 'mapbox://mapbox.mapbox-terrain-dem-v1',
'tileSize': 512,
'maxzoom': 14
});
map.setTerrain({ 'source': 'mapbox-dem', 'exaggeration': 1.5 });
}
// 移除地图实例
onUnmounted(() => {
map ? map.remove() : null;
});
// 数据绘制完成判断
const handlerDealFeature = (feature) => {
let existFeature = geojson.geojson.features.find((item, index) => {
return item.id == feature.id;
});
if (existFeature) {
// 如果查找到了 则替换数据
for (let i = 0; i < geojson.geojson.features.length; i++) {
if (geojson.geojson.features[i].id == feature.id) {
geojson.geojson.features[i] = feature;
}
}
} else {
// 如果没找到数据则添加到数组
geojson.geojson.features.push(feature);
}
// 自动将数据返回给父组件
handlerDrawComplete();
};
// 删除数据
const handlerDeleteFeature = (feature) => {
for (let i = 0; i < geojson.geojson.features.length; i++) {
if (geojson.geojson.features[i].id == feature.id) {
geojson.geojson.features.splice(i, 1);
}
}
// handlerDrawComplete();
};
// 初始化地图 返回地图实例
const initMap = () => {
return new mapboxgl.Map({
container: 'mapContainer',
language: 'zh-cmn',
projection: 'equirectangular', // wgs84参考系
style: MapboxDefaultStyle,
maxZoom: props.mapConfig.maxZoom ? props.mapConfig.maxZoom:18,
minZoom: props.mapConfig.minZoom ? props.mapConfig.minZoom:1,
zoom: props.mapConfig.zoom ? props.mapConfig.zoom:12,
pitch:props.mapConfig.angle ? props.mapConfig.angle:0,
center: props.mapConfig.center?.split(","),
});
};
const handlerMapControlClick = (handler: string) => {
handler === 'handlerDrawPoint' && handlerDrawPoint();
handler === 'handlerDrawLineString' && handlerDrawLineString();
handler === 'handlerDrawPolygon' && handlerDrawPolygon();
};
//绘制点
const handlerDrawPoint = () => {
mp.draw('Point');
mp.on('Point', function (e) {
emit('mapDraw', 'Point', e);
});
};
//绘制线
const handlerDrawLineString = () => {
mp.draw('LineString');
mp.on('LineString', function (e) {
emit('mapDraw', 'LineString', e);
});
};
//绘制面
const handlerDrawPolygon = () => {
mp.draw('Polygon');
mp.on('Polygon', function (e) {
emit('mapDraw', 'Polygon', e);
});
};
//删除标记
const handlerUnDraw = () => {
mp.deleteDraw();
emit('mapDraw', 'cancel');
};
// 初始化绘图空间
const handlerInitDrawTool = (feature, bool) => {
// if (feature.features.length > 0) {
// feature.features.forEach((item) => {
// if (item.geometry.type == 'MultiPolygon') {
// let arr: any = ref([]);
// item.geometry.coordinates.forEach((val) => {
// arr.value.push(val[0]);
// });
// item.geometry.coordinates = arr.value;
// item.geometry.type = 'Polygon';
// }
// });
// }
geojson.geojson = feature;
if (drawTool) {
drawTool.deleteAll();
if (feature.features) {
drawTool.set(geojson.geojson);
}
} else {
drawTool = new MapboxDraw({
modes: {
...MapboxDraw.modes,
draw_point: SnapPointMode,
draw_polygon: SnapPolygonMode,
draw_line_string: SnapLineMode,
direct_select: SnapDirectSelect,
},
styles: customDrawStyles,
userProperties: true,
snap: true,
snapOptions: {
snapPx: 12, // defaults to 15
snapToMidPoints: true, // defaults to false
snapVertexPriorityDistance: 0.0025, // defaults to 1.25
},
guides: false,
});
map.addControl(drawTool, 'top-right');
if (feature.features) {
drawTool.set(geojson.geojson);
}
}
// 正在绘制
// if (bool) {
// drawing.value = true;
// } else {
// drawing.value = false;
// }
drawing.value = true;
};
// 将图斑复制到指定图层
const handlerCopyToTargetLayer = (e) => {
if (e.features.length > 0) {
if (popup) {
popup.remove();
popup = null;
}
selectFeature = e.features[0];
popup = new mapboxgl.Popup({
closeButton: false,
closeOnClick: false,
});
// 设置 popup 的位置和内容
popup
.setLngLat(clickPoisition)
.setHTML(
`
<div style="color:#333;padding:3px 12px;cursor:pointer;" type="primary" icon="el-icon-search" onclick="handlerCopyFeature();"></div>`,
)
.addTo(map);
} else {
popup.remove();
}
};
const handlerCopyFeature = () => {
popup.remove();
createMessage.success('复制成功!');
};
// 添加到图层
const handlerAddToLayerList = (layer) => {
handlerCheckLayerExist(layer);
};
// 判断图层列表中是否一定添加
const handlerCheckLayerExist = (layer) => {
for (let i = 0; i < layerList.length; i++) {
if (layerList[i] == layer.id) {
return;
}
}
layerList.push(layer);
};
const handlerCheckboxChange = (item) => {
console.log("itemitemitem",item);
handlerPreviewLayer(item);
};
// 控制图层是否显示
const handlerPreviewLayer = (layer) => {
console.log("layersss",layer);
handlerLayerControler(layer);
};
// 图层控制中心
const handlerLayerControler = (layerInfo) => {
layerInfo.layer = layerInfo.layer? layerInfo.layer : JSON.parse(layerInfo.style);
if (map.getSource(layerInfo.layer.id)) {
if (layerInfo.checked) {
map.setLayoutProperty(layerInfo.layer.id, 'visibility', 'visible');
} else {
map.setLayoutProperty(layerInfo.layer.id, 'visibility', 'none');
}
} else {
map.addLayer(layerInfo.layer);
map.on('click', layerInfo.layer.id, function (e) {
handlerPreviewFeatureInfo(e);
});
}
};
// 查看列表数据
const handlerDataList = () => {};
// 图斑属性查看
const handlerPreviewFeatureInfo = (e) => {
if (e.features) {
isOpen.value = true;
}
};
const handlerClose = (e) => {
isOpen.value = e;
};
// 图斑定位
const handlerLocation = (lngLat) => {
map.flyTo({
center: lngLat,
zoom: 17,
speed: 10, // 飞行速度
curve: 1, // 飞行曲线
easing(t) {
// 飞行动画函数
return t;
},
});
};
// 编辑图斑
const handlerEdit = (info) => {
initDraw(info);
};
const initDraw = (layerInfo) => {
// 实例化绘图工具
drawTool = new MapboxDraw({
modes: {
...MapboxDraw.modes,
draw_point: SnapPointMode,
// draw_polygon: SnapPolygonMode,
// draw_line_string: SnapLineMode,
direct_select: SnapDirectSelect,
},
styles: customDrawStyles,
userProperties: true,
snap: true,
snapOptions: {
snapPx: 15, // defaults to 15
snapToMidPoints: true, // defaults to false
snapVertexPriorityDistance: 0.0025, // defaults to 1.25
},
guides: false,
});
map.addControl(drawTool, 'top-right');
// let geojson:Object = {};
// if (layerInfo.dataType == "面") {
// geojson.type = "Polygon";
// geojson.coordinates = geojson.coordinates[0];
// } else if (layerInfo.dataType == "点") {
// geojson.type = "Point";
// geojson.coordinates = geojson.coordinates;
// } else if (layerInfo.dataType == "线") {
// geojson.type = "LineString";
// geojson.coordinates = geojson.coordinates[0];
// }
// if (formData.lat && formData.lng) {
// formData.lat = geojson.coordinates[1];
// formData.lng = geojson.coordinates[0];
// }
// geojson = {
// type: "FeatureCollection",
// features: [
// {
// type: "Feature",
// geometry: geojson,
// },
// ],
// };
// map.setLayoutProperty("pbfLayer", "visibility", "none");
// drawTool.set(geojson);
};
const handlerDrawComplete = () => {
let arr = [];
geojson.geojson.features.forEach((item, index) => {
let wktStr = GeojsonToWkt(item.geometry);
let obj = {
columnName: 'mapgeom',
value: wktStr,
};
arr.push(obj);
});
console.log('aaaa', arr);
emit('handlerDrawComplete', arr);
};
const handlerCancleDraw = () => {
map.removeControl(drawTool);
drawTool = null;
drawing.value = false;
// 清空详情图层
if(map.getSource("detailsSource")){
map.getSource("detailsSource").setData({
type: 'FeatureCollection',
features: [],
})
}
};
/**
*
* 查看图斑
*
* 添加图斑
*
* 编辑图斑
*
* status 操作类型
*
* features 空间数据
*
* [
* {id:"8448048304dofhaofh0af0q4",geom:""}
* ]
* */
const handlerDraw = (status:string,features = null, bool = false) => {
let geo = {
type: 'FeatureCollection',
features: [],
};
// 清空详情图斑
if(map.getSource("detailsSource")){
map.getSource("detailsSource").setData({
type: 'FeatureCollection',
features: [],
})
}
if (features == null) {
bool = true;
} else {
if (features.length > 0) {
for (let i = 0; i < features.length; i++) {
try {
let featureTemp = WktToGeojson(features[i]?.mapgeom);
let feature = {
id: generateUUID(),
type: 'Feature',
properties: {},
geometry: featureTemp,
};
geo.features.push(feature);
// 获取第一个图斑的中心点跳转定位
if(i == 0){
let lngLat = getGeometryCenter(feature);
handlerLocation(lngLat);
}
} catch (e) {
createMessage.error("WKT数据格式解析错误请检查WKT数据格式是否有误");
}
}
}
}
switch(status){
case "Add":
handlerInitDrawTool(geo, bool);
break;
case "Edit":
handlerInitDrawTool(geo, bool);
break;
case "Details":
handlerDetails(geo);
break;
default:
createMessage.error("请传入操作类型!");
}
};
// 查看图斑详情
const handlerDetails = (geojson) => {
if(map.getSource("detailsSource")){
map.getSource("detailsSource").setData(geojson);
}else{
map.addSource("detailsSource",{
type:"geojson",
data:geojson
})
map.addLayer(
{
"id": "detailsLayer",
"type": "fill",
"source": "detailsSource",
'layout':{
},
'paint': {
//填充颜色
'fill-color': '#3badc9',
//透明度设置
"fill-opacity": 0.4,
}
}
)
map.addLayer(
{
"id": "detailsLayerLine",
"type": "line",
"source": "detailsSource",
'layout':{
},
'paint': {
'line-color': '#3badc9',
'line-width': 2
}
}
)
}
}
// 创建查看图斑图层
defineExpose({
handlerDraw,
handlerLocation,
handlerCancleDraw,
});
</script>
<style>
.map-container {
width: 100%;
height: 100%;
}
.map-box {
width: 100%;
height: 100%;
}
.layer-control-center {
position: absolute;
top: 15px;
left: 15px;
background:#fff;
border-radius: 8px;
}
.layer-control-center p {
margin: 0px;
}
.layer-control-center .ant-checkbox-wrapper{
}
.draw-control-center {
position: absolute;
padding: 8px;
top: 15px;
right: 15px;
background: #ffffff;
border-radius: 12px;
}
.draw-control-center .draw-btn {
float: left;
margin: 0px 7px;
padding: 5px;
border-radius: 5px;
}
.draw-control-center .draw-btn:hover {
background-color: rgb(0 0 0/5%);
cursor: pointer;
}
.mapboxgl-ctrl-group:not(:empty) {
box-shadow: none;
}
.mapboxgl-ctrl-group {
padding: 6px;
border-radius: 12px;
top: 5px;
}
.mapbox-gl-draw_ctrl-draw-btn {
width: 20px !important;
height: 20px !important;
float: left;
}
.mapboxgl-ctrl-top-right {
}
.mapboxgl-ctrl-group button + button {
border: 0px;
margin: 0px 6px;
}
.mapbox-gl-draw_ctrl-draw-btn:hover {
transform: scale(1.2);
}
.mapbox-gl-draw_polygon {
background-image: url(/polygon.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_point {
background-image: url(/point.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_line {
background-image: url(/line.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
margin: 0px 6px;
}
.mapbox-gl-draw_trash {
background-image: url(/del.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_combine {
background-image: url(/combine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.mapbox-gl-draw_uncombine {
background-image: url(/uncombine.png);
background-size: 100% 100%;
width: 100px;
height: 100px;
}
.jas-ctrl-measure{
position:relative;
top:6px;
right:10px;
}
.jas-ctrl-measure-item{
height:22px;
color: rgb(255, 255, 255);
}
.layer-item{
padding:8px 16px;
}
.layer-item:hover{
background:#c7dcf580;
}
::v-deep .ant-collapse-content-box{
padding:0px!important;
}
</style>