CaiYuanYiTiHua/src/components/MapboxMaps/MapComponent.vue

2677 lines
77 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="mapContainerName" @mouseover="mapmouseover" class="map-box"></div>
<div class="cloud-query-div" v-if="props.geomsList">
<div v-if="useCloudQuery.getIdentification" @click="initiateCloudQuery2">
<div class="cloud-query-icon">
<Loading3QuartersOutlined spin :style="{ fontSize: '20px' }" />
</div>
<div>云查询</div>
</div>
<div
v-else-if="
!useCloudQuery.getIdentification &&
useCloudQuery?.beforeId &&
props.caseno == useCloudQuery?.caseno
"
@click="initiateCloudQuery3"
>
<div class="cloud-query-icon">
<Icon icon="gis:globe-poi" :size="20" />
</div>
<div> 查看结果 </div>
</div>
<div v-else @click="initiateCloudQuery1">
<div class="cloud-query-icon">
<Icon icon="gis:globe-poi" :size="20" />
</div>
<div>云查询</div>
</div>
</div>
<!-- 云查询内容提示 -->
<div class="cloudqueryNotice" v-if="props.geomsList && useCloudQuery.getCloudQueryVisable">
<div class="cloudquery-title">
<div class="cloudquery-left">
<img src="/message.png" alt="" />
<span class="title-box">您有一条云查询结果,请查收</span>
</div>
<div class="cloudquery-right">
<a-button type="primary" @click="initiateCloudQuery3">查看</a-button>
<div class="line"></div>
<CloseOutlined @click="closeCloudQuery" style="color: #fff" title="关闭" />
</div>
</div>
</div>
<!-- 云查询结果 -->
<a-modal
v-model:open="open"
:footer="false"
@cancel="closeCloudQueryModal"
:width="compare ? '1020px' : '510px'"
style="top: 20px"
:destroyOnClose="true"
>
<CloudQueryContent @changeCompare="changeCompare"/>
</a-modal>
<!-- 图层控制 -->
<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 class="position-by-lnglat">
<a-tooltip>
<template #title>图斑定位</template>
<div class="to-location" @click="handlerToPosition()"></div>
</a-tooltip>
<a-tooltip>
<template #title>坐标定位</template>
<div class="draw-polygon" @click="LocationShow = true"></div>
</a-tooltip>
<a-popover placement="bottom" v-if="props.splitPlugin" v-model:visible="splitPanelVisible">
<template #content>
<div class="split-panel">
<p class="split-panel-item" @click="handlerDrawLineString()">绘制线分割</p>
<p class="split-panel-item" @click="handlerDrawPolygon()">绘制面分割</p>
<a-upload
name="file"
:before-upload="handleImportShapeFileChange"
:showUploadList="false"
>
<p class="split-panel-item">导入图层分割</p>
</a-upload>
<!-- <p class="split-panel-item" >地类图斑分割</p> -->
<!-- <a-dropdown>
<p @click.prevent>地类图斑分割 <DownOutlined /></p>
<template #overlay>
<a-menu>
<a-menu-item @click="handlerSelectLandType('gengdi')">
<p>耕地地类分割</p>
</a-menu-item>
<a-menu-item @click="handlerSelectLandType('jianshe')">
<p>建设用地地类分割</p>
</a-menu-item>
</a-menu>
</template>
</a-dropdown> -->
</div>
</template>
<div class="split-line" ></div>
</a-popover>
<a-tooltip>
<template #title>线分割图斑</template>
</a-tooltip>
<a-tooltip>
<template #title>{{isShowPicture?'显示选中图片方位角':'显示全部图片方位角'}}</template>
<div :class="isShowPicture?'picture-azimuth':'picture-azimuth-active'" @click="handlerChangePictureVisible()"></div>
</a-tooltip>
<div class="split-polygon" @click="handlerDrawPolygon()" v-if="false"> </div>
</div>
<!-- 坐标输入框 -->
<div class="to-location-input" v-if="LocationShow">
<div class="location-operation">
<a-button type="default" size="small" @click="handlerPushLocationItem"
><PlusOutlined />添加</a-button
>
&nbsp;
<a-upload
name="file"
:before-upload="handleImportCoorinateChange"
:showUploadList="false"
>
<a-button
type="default"
size="small"
><CloudUploadOutlined />导入
</a-button>
</a-upload>
&nbsp;
<a-button type="default" size="small" @click="handlerClearLocationItem"
><ClearOutlined />清空</a-button
>
&nbsp;
<a-button
type="default"
size="small"
v-if="props.splitPlugin"
@click="onHandlerSplitPolygon"
><SplitCellsOutlined />分割图斑</a-button>
<span style="float: right">
<CloseOutlined @click="handlerLocationClose" />
</span>
</div>
<!-- <a-empty v-if="locationArrays.length == 0" /> -->
<div class="location-item-list-coantienr">
<a-table :dataSource="locationArrays" size="small" :pagination="false" >
<a-table-column-group>
<a-table-column key="lng" title="经度(Y)" data-index="lng">
<template #default="{ record }">
<a-input
v-model:value="record.lng"
@chagne="handlerLocationChange"
size="small"
/>
</template>
</a-table-column>
<a-table-column key="lat" title="纬度(X)" data-index="lat">
<template #default="{record}">
<a-input
v-model:value="record.lat"
@chagne="handlerLocationChange"
size="small"
/>
</template>
</a-table-column>
<a-table-column key="operation" title="操作" data-index="operation" width="100px">
<template #default="{record,index}">
<a-button type="default" size="small" @click="handlerLocationFlyTo(index)"
><EnvironmentOutlined
/></a-button>
&nbsp;
<a-button type="default" size="small" @click="handlerLocationRemove(index)"
><DeleteOutlined
/></a-button>
</template>
</a-table-column>
</a-table-column-group>
</a-table>
<!-- <div class="location-item" v-for="(item, index) in locationArrays" :key="index">
<a-button type="default" size="small" @click="handlerLocationFlyTo(item)"
><EnvironmentOutlined
/></a-button>
<a-input
v-model:value="item.lng"
@chagne="handlerLocationChange"
addon-before=""
size="small"
style="width: 140px; margin: 0px 12px"
/>
<a-input
v-model:value="item.lat"
@chagne="handlerLocationChange"
addon-before=""
size="small"
style="width: 140px; margin-right: 12px"
/>
<a-button type="default" size="small" @click="handlerLocationRemove(index)"
><DeleteOutlined
/></a-button>
</div> -->
</div>
</div>
<!-- 地类选择 -->
<a-modal v-model:open="landTypeVisible" title="请选择分割依据的地类" @ok="handlerSplitByLandType">
<div style="padding:15px">
<a-table
rowKey="id"
:rowSelection="{type:'radio',onChange:onLandTypeChange}"
:filterMultiple="false"
:pagination="false"
:dataSource="landTypeList"
:columns="[{title: '地类名称',dataIndex: 'name',key: 'name'}]" />
</div>
</a-modal>
</div>
</template>
<script lang="ts" setup>
import {
onMounted,
onUnmounted,
defineProps,
defineEmits,
reactive,
ref,
defineExpose,
watch,
inject,
} from 'vue';
import { useMessage } from '@/hooks/web/useMessage';
import {
CloseOutlined,
EnvironmentOutlined,
DeleteOutlined,
CopyOutlined,
PlusOutlined,
ClearOutlined,
SplitCellsOutlined,
CloudUploadOutlined,
Loading3QuartersOutlined,
DownOutlined,
} from '@ant-design/icons-vue';
import mapboxgl, { Map, Popup } from 'mapbox-gl';
import Icon from '@/components/Icon/Icon.vue';
import CloudQueryContent from '@/components/CloudQueryContent/index.vue';
// 图形绘制工具类
import MapboxDraw from '@mapbox/mapbox-gl-draw';
import { generateUUID, getGeometryCenter } from './src/tool';
// 测量工具
import { SwitchLayerControl, MeasureControl } 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';
// POLYGON分割函数
import { polygonCut } from './lib/segmentation';
import { splitPolygonByLine, splitPolygonByFill,splitPolygonByMultiFill,handlerToMultiPolygonGeoJson} from './lib/splitpolygon';
// 线分割
import {chunkUtil} from './lib/chunkutil.ts';
// 图片切换
import { userFormFileStore } from '@/store/modules/formFileUrl';
import { storeToRefs } from 'pinia';
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,wktCollectionToGeoJson } from './src/WktGeojsonTransform';
import { features } from 'process';
import { getAppEnvConfig } from '@/utils/env';
import { message, Modal } from 'ant-design-vue';
import { useCloudQueryStore } from '@/store/modules/cloudquery';
// 地类分割
import { splitAndCalTubanArea,splitTubanBackYuan } from '@/api/sys/layerManagement';
import { CalTubanAreaModel } from '@/api/sys/model/layerModel';
import { AddDroneTask, LoadLandType, AddDroneLandTask, LoadCloudQueryByCaseNo } from '@/api/demo/cloudQuery';
import { signal } from '@/utils/signalR';
// 坐标系转换
import proj4 from 'proj4'
// shp数据转换
import JSZip from 'jszip'
import shp from 'shpjs'
// 这里的zip为上传的zip文件
const parseZip = async(zip)=>{
// 解析zip数据为二进制数据
const jsZip = new JSZip()
const zipData = await jsZip.loadAsync(zip)
// 将zip文件转化为二进制流
const data = await zipData.generateAsync({ type: 'arraybuffer' })
return await shp(data)
}
// 文件选择
const handleImportShapeFileChange = (e)=>{
parseZip(e).then(res=>{
let geojson = JSON.parse(JSON.stringify(res))
// 绘制导入的shapgefile图斑
handlerDetails(
res,
'shapefileSource',
'shapefileLayer',
{
lineStyle: { 'line-color': '#ff0000', 'line-width': 3 },
fillStyle: { 'fill-color': '#ff0000', 'fill-opacity': 0.1 },
}
)
Modal.confirm({
title: '是否确认分割图斑?',
onCancel() {
handlerDetails(
{type:"FeatureCollection",features:[]},
'shapefileSource',
'shapefileLayer',
{
lineStyle: { 'line-color': '#ff0000', 'line-width': 3 },
fillStyle: { 'fill-color': '#ff0000', 'fill-opacity': 0.1 },
}
)
},
async onOk() {
// splitFeatureByFill(geojson.features[0].geometry.coordinates[0]);
splitFeatureByMultiFill(geojson);
handlerDetails(
{type:"FeatureCollection",features:[]},
'shapefileSource',
'shapefileLayer',
{
lineStyle: { 'line-color': '#ff0000', 'line-width': 3 },
fillStyle: { 'fill-color': '#ff0000', 'fill-opacity': 0.1 },
}
)
},
});
}).catch((e)=>{
createMessage.error("分割失败请检查上传的Shapefile文件压缩包数据是否正确");
})
}
const landTypeVisible = ref<boolean>(false);
const landTypeList = ref([])
const splitLandTypeForm = ref({
name:null,
code:null,
geomData:null,
caseid:null,
})
//
function splitMultiPolygons(str) {
let hadnlerStr = str.replace(",MULTIPOLYGON","-MULTIPOLYGON");
let result = hadnlerStr.split("-");
// 移除开头的 "MULTIPOLYGON" 和多余的括号
// const cleanedStr = str.replace(/^MULTIPOLYGON\(/, '').replace(/\)+$/, '');
// // 使用正则表达式分割多个多边形
// const polygonStrings = cleanedStr.split(/\)\),\s*MULTIPOLYGON\(\(/);
// // 重新构建每个 MULTIPOLYGON
// const result = polygonStrings.map(poly => {
// // 确保每个多边形有正确的括号结构
// const fixedPoly = poly.startsWith('((') ? poly : `((${poly}`;
// return `MULTIPOLYGON(${fixedPoly}))`;
// });
return result;
}
// 地类分割图斑
const handlerSelectLandType = (type)=>{
emit('handlerStartSpliting',true);
try{
let geom = GeojsonToWkt(JSON.parse(JSON.stringify(currentGeoJson.value.geometry)));
// let geom = "POLYGON ((118.309424037556 34.547670781228 , 118.309595164318 34.5475487203142 , 118.30958905415 34.5475220510643 , 118.309594872126 34.5475037441097 , 118.309650493845 34.5474667417388 , 118.309649079958 34.5474500627085 , 118.309623826 34.54738605 , 118.309575552961 34.5472698959146 , 118.309522643 34.5471425680001 , 118.309730137 34.5466727850001 , 118.309679115776 34.5465914577158 , 118.309360468678 34.5467523126098 , 118.309316608846 34.5466467673944 , 118.309288715084 34.5466132635055 , 118.309269848483 34.5467056718441 , 118.309247005657 34.5468275002474 , 118.309298402015 34.5468998358621 , 118.309285967432 34.5469646580605 , 118.309324410141 34.5469494810228 , 118.309340280529 34.5469759786143 , 118.309344087666 34.547027374972 , 118.309400751348 34.5471162294817 , 118.309323166839 34.5471455373382 , 118.309357412648 34.5473528852375 , 118.309424037556 34.547670781228 ))"
// let geom = "POLYGON((118.30942404 34.54767078,118.30959516 34.54754872,118.30958905 34.54752205,118.30959487 34.54750374,118.30965049 34.54746674,118.30964908 34.54745006,118.30962383 34.54738605,118.30957555 34.5472699,118.30952264 34.54714257,118.30973014 34.54667279,118.30967912 34.54659146,118.30936047 34.54675231,118.30931661 34.54664677,118.30928872 34.54661326,118.30928872 34.54661326,118.30926985 34.54670567,118.30924701 34.5468275,118.3092984 34.54689984,118.30928597 34.54696466,118.30932441 34.54694948,118.30934028 34.54697598,118.30934409 34.54702737,118.30940075 34.54711623,118.30932317 34.54714554,118.30935741 34.54735289,118.30942404 34.54767078,118.30942404 34.54767078))";
let calAreaParams = {
"wktgeom":geom,
"type":type
}
splitTubanBackYuan(calAreaParams).then(res=>{
let geojson = {
type:"FeatureCollection",
features:[]
};
let wktArray = splitMultiPolygons(res.gengdituban);
if(wktArray.length>0){
wktArray?.forEach((item,index)=>{
console.log("item",item);
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": WktToGeojson(item)
}
geojson.features.push(feature);
})
}else{
//
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": WktToGeojson(res.gengdituban)
}
}
console.log("splitTubanBackYuan",geojson)
splitFeatureByMultiFill(geojson);
handlerDetails(
{type:"FeatureCollection",features:[]},
'shapefileSource',
'shapefileLayer',
{
lineStyle: { 'line-color': '#ff0000', 'line-width': 3 },
fillStyle: { 'fill-color': '#ff0000', 'fill-opacity': 0.1 },
}
)
})
return null;
splitAndCalTubanArea(calAreaParams).then(res=>{
if(res){
let splitAfterFeatures = {
type: 'FeatureCollection',
features: [],
};
// 耕地
if(res.gengdituban && !res.gengdituban.match("EMPTY")){
// let geojsonData = wktCollectionToGeoJson(res.gengdituban);
let geometry = WktToGeojson(res.gengdituban)
// let geomtry_01 = WktToGeojson("POLYGON((118.3093166 34.5466468,118.3095756 34.5472699,118.3095226 34.5471426,118.3097301 34.5466728,118.3096917 34.5466115,118.3096791 34.5465915,118.3096252 34.5466187,118.3093605 34.5467523,118.3093166 34.5466468))");
// let geomtry_02 = WktToGeojson("POLYGON((118.3096238 34.5473861,118.3095893 34.5473029,118.309624 34.5473866,118.3096238 34.5473861))");
// let geomtry_03 = WktToGeojson("POLYGON((118.3096266 34.547393,118.3096408 34.5474354,118.3096491 34.5474501,118.3096266 34.547393))");
console.log("geomtry_01");
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": geometry
}
splitAfterFeatures.features.push(feature)
// splitAfterFeatures.features?.push({
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geomtry_01
// })
// splitAfterFeatures.features?.push({
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geomtry_02
// })
// splitAfterFeatures.features?.push({
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geomtry_03
// })
}
// 农用地
if(res.nongyongdituban && !res.nongyongdituban.match("EMPTY")){
let geometry = WktToGeojson(res.nongyongdituban)
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": geometry
}
splitAfterFeatures.features.push(feature)
}
// 基本农田
if(res.jibennongtiantuban && !res.jibennongtiantuban.match("EMPTY")){
let geometry = WktToGeojson(res.jibennongtiantuban)
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": geometry
}
splitAfterFeatures.features.push(feature)
}
//
if(res.remaintuban && !res.remaintuban.match("EMPTY")){
let geometry = WktToGeojson(res.remaintuban)
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": geometry
}
splitAfterFeatures.features.push(feature)
}
// 生态保护红线
if(res.shengtaihongxiantuban && !res.shengtaihongxiantuban.match("EMPTY")){
let geometry = WktToGeojson(res.shengtaihongxiantuban)
let feature = {
"type": "Feature",
"properties": {
"id": generateUUID()
},
"geometry": geometry
}
splitAfterFeatures.features.push(feature)
}
// 分割数据返回父组件中
emit('handlerSplitPolygon', splitAfterFeatures.features);
handlerUnDraw();
}
}).catch((e)=>{
emit('handlerStartSpliting',false);
})
}catch(e){
emit('handlerStartSpliting',false);
}
// let res = {
// "wktgeom": null,
// "gengdi": 0.17,
// "nongyongdi": 1.64,
// "jibennongtian": 0,
// "shengtaihongxian": 0,
// "gengdituban": "POLYGON((118.204530452946 34.6149319373947,118.204383402255 34.6149647739564,118.20439867709747 34.6150347166548,118.2045384290743 34.61501302803828,118.204530452946 34.6149319373947))",
// "nongyongdituban": "POLYGON((118.204827409679 34.6149804783991,118.204539019005 34.6150190256674,118.204530452946 34.6149319373947,118.204383402255 34.6149647739564,118.204410528111 34.615088981821,118.203870866355 34.6151889191832,118.203870866355 34.6152688690729,118.204421949524 34.6151746424171,118.204421949524 34.6151546549447,118.204847397152 34.6150918371741,118.204827409679 34.6149804783991))",
// "jibennongtiantuban": "",
// "shengtaihongxiantuban": "",
// "remaintuban": "POLYGON EMPTY"
// }
// if(res){
// let splitAfterFeatures = {
// type: 'FeatureCollection',
// features: [],
// };
// // 耕地
// if(res.gengdituban && !res.gengdituban.match("EMPTY")){
// let geometry = WktToGeojson(res.gengdituban)
// let feature = {
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geometry
// }
// splitAfterFeatures.features.push(feature)
// }
// // 农用地
// if(res.nongyongdituban && !res.nongyongdituban.match("EMPTY")){
// let geometry = WktToGeojson(res.nongyongdituban)
// let feature = {
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geometry
// }
// splitAfterFeatures.features.push(feature)
// }
// // 基本农田
// if(res.jibennongtiantuban && !res.jibennongtiantuban.match("EMPTY")){
// let geometry = WktToGeojson(res.jibennongtiantuban)
// let feature = {
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geometry
// }
// splitAfterFeatures.features.push(feature)
// }
// //
// if(res.remaintuban && !res.remaintuban.match("EMPTY")){
// let geometry = WktToGeojson(res.remaintuban)
// let feature = {
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geometry
// }
// splitAfterFeatures.features.push(feature)
// }
// // 生态保护红线
// if(res.shengtaihongxiantuban && !res.shengtaihongxiantuban.match("EMPTY")){
// let geometry = WktToGeojson(res.shengtaihongxiantuban)
// let feature = {
// "type": "Feature",
// "properties": {
// "id": generateUUID()
// },
// "geometry": geometry
// }
// splitAfterFeatures.features.push(feature)
// }
// // 分割数据返回父组件中
// emit('handlerSplitPolygon', splitAfterFeatures.features);
// handlerUnDraw();
// }
// splitAndCalTubanArea(calAreaParams).then(res=>{
// })
// splitPanelVisible.value = false;
// LoadLandType().then(res=>{
// landTypeList.value = res;
// })
// landTypeVisible.value = true;
}
// 使用地类分割
const handlerSplitByLandType = ()=>{
splitLandTypeForm.value.caseid = props.caseid || props.caseno;
let geojson = {
"type": "Feature",
"properties": {},
"geometry": {
"type": "Polygon",
"coordinates": [
[
]
]
}
}
currentGeoJson.value.geometry.coordinates[0]?.forEach((item,index)=>{
geojson.geometry.coordinates[0].push([item[0],item[1]]);
})
splitLandTypeForm.value.geomData = GeojsonToWkt(JSON.parse(JSON.stringify(geojson.geometry)));
landTypeVisible.value = false;
//console.log("splitLandTypeForm",splitLandTypeForm.value)
let paramStr = "?"
for(let key in splitLandTypeForm.value){
//console.log("key",key);
paramStr+=key+"="+splitLandTypeForm.value[key]+"&";
}
if (useCloudQuery.getIdentification) {
message.warning('已有地类分割运行,不能再次提交');
} else {
AddDroneLandTask(paramStr).then((res) => {
message.success('成功提交地类分割数据');
useCloudQuery.setIdentification(true);
});
}
}
const onLandTypeChange = (selectedRowKeys, selectedRows)=>{
splitLandTypeForm.value.name = selectedRows[0].name;
splitLandTypeForm.value.code = selectedRows[0].id;
}
// 投影转地理坐标系
function GkToCGCS2000(lngLat){
try{ // 需要根据投影度带确定转换参数
let from_system = "";
if(lngLat[0]>=37000000 && lngLat[0] < 38000000){
from_system = "+proj=tmerc +lat_0=0 +lon_0=111 +k=1 +x_0=37500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}if(lngLat[0]>=38000000 && lngLat[0] < 39000000){
from_system = "+proj=tmerc +lat_0=0 +lon_0=114 +k=1 +x_0=38500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}if(lngLat[0]>=39000000 && lngLat[0] < 40000000){ // CGCS2000 / 3-degree Gauss-Kruger zone 39
from_system = "+proj=tmerc +lat_0=0 +lon_0=117 +k=1 +x_0=39500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}else if(lngLat[0] >= 40000000){ // CGCS2000 / 3-degree Gauss-Kruger zone 40
from_system = "+proj=tmerc +lat_0=0 +lon_0=120 +k=1 +x_0=40500000 +y_0=0 +ellps=GRS80 +units=m +no_defs +type=crs"
}
// China Geodetic Coordinate System 2000
// let to_system = "+proj=longlat +ellps=GRS80 +no_defs +type=crs";
// WGS 84 -- WGS84 - World Geodetic System 1984,
let to_system = "+proj=longlat +datum=WGS84 +no_defs +type=crs";
// transform
let trasnformLnglat = proj4(from_system,to_system,lngLat);
return trasnformLnglat;
}catch(e){
return null;
}
}
const useCloudQuery = useCloudQueryStore();
const { VITE_GLOB_API_URL } = getAppEnvConfig();
const VITE_GLOB_API_URL_VAR = ref<String>(VITE_GLOB_API_URL + '/');
const mapContainerName = ref<String>();
mapContainerName.value = 'mapContainer-' + generateUUID();
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: '',
},
splitPlugin: {
type: Boolean,
default: false,
},
geomsList: {
type: Array,
default: null,
},
caseid: {
type: String,
default: '',
},
caseno: {
type: String,
default: '',
},
countyname: {
type: String,
default: '',
}
});
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: [],
},
});
let switchLayerControler;
const { createConfirm, createMessage } = useMessage();
// 定义地图回调emit
// 地图加载完成回调
const emit = defineEmits([
'mapOnLoad',
'mapDraw',
'handlerDrawComplete',
'handlerGetFormDetail',
'handlerSplitPolygon',
'handlerStartSpliting',
'onFeatureClick',
]);
watch(
() => props.mapConfig,
(newVal, oldVal) => {
handlerLoadMapLayer();
},
);
const formFileStore = userFormFileStore();
const formFileState = storeToRefs(formFileStore);
watch(formFileState.url, (newValue, oldValue) => {});
function mapmouseover(e) {}
onMounted(() => {
// let mapDiv = window.document.getElementById(mapContainerName.value);
// mapDiv?.onmouseover = function(e){
// alert(e);
// }
mapboxgl.accessToken = MapboxConfig.ACCESS_TOKEN;
map = initMap();
map.on('load', () => {
//挂载mapbox-gl-utils
U.init(map);
mp = new MP(map);
// 根据地图配置信息加载地形数据
if (props.mapConfig.mode == '3D') {
// handlerLoadTerrain();
}
// 初始化绘图空间
// handlerInitDrawTool(null);
map.on('click', (e) => {
// handlerPreviewFeatureInfo(e);
clickPoisition = e.lngLat;
//console.log("clickPoisition",clickPoisition);
});
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',
);
// 加载图层
handlerLoadMapLayer();
// 应用图层绑定点击事件
// applicationLayers.forEach((item,index)=>{
// map.on("click",item.layer.id,(e)=>{
// let state = findLayerAttributeInfo(applicationLayers,e.features[0].layer.id);
// if(state){
// let formDetailParams = {
// attributeTable:state.attributeTable,
// attributeField:state.attributeField,
// value:e.features[0].properties.gid
// }
// // 调用父组件查询表单详情信息
// emit("handlerGetFormDetail",formDetailParams)
// createMessage.success("数据表:"+state.attributeTable+";查询字段:"+state.attributeField+"字段值:"+e.features[0].properties.gid)
// }else{
// createMessage.warning("当前点击图层未绑定信息");
// }
// })
// })
// 分割多边形
// splitFeature();
// 添加地类分割图斑
// map.addLayer({
// id: 'yingxiang',
// type: 'raster',
// source: {
// type: 'raster',
// tiles: [
// "http://192.168.10.131:8080/geoserver/my_workspace/wms?service=WMS&version=1.1.0&request=GetMap&layers=my_workspace:geoserver371302&CQL_FILTER=dlmc='旱地'&styles=&bbox={bbox-epsg-3857}&width=256&height=256&srs=EPSG:3857&format=image/png&TRANSPARENT=TRUE",
// ],
// tileSize: 256,
// },
// layout: {
// }
// })
// map.addLayer(
// {
// 'id': 'geoserver371302Layer',
// 'type': 'fill',
// 'source': {
// type: 'vector',
// tiles: [VITE_GLOB_API_URL_VAR.value+'api/DroneCaseInfoSingle/QueryVectorTileByTable?z={z}&x={x}&y={y}&table=geoserver371302'],
// minzoom: 1,
// maxzoom: 20,
// 'cluster': true, // 启用聚合
// 'clusterMaxZoom': 0, // 最大聚合缩放级别
// 'clusterRadius': 0 // 聚合半径
// },
// "source-layer": "geoserver371302",
// 'layout': {
// 'line-join': 'round',
// 'line-cap': 'round',
// },
// 'paint': {
// 'line-color': "#408eff",
// 'line-width': 2
// }
// }
// )
});
});
function handlerLayerChange() {
var allLayers = map.getStyle().layers;
if (map.getLayer('detailsLayerLine'))
map.moveLayer('detailsLayerLine', allLayers[allLayers.length - 1].id);
allLayers.forEach(function (layer) {});
// allLayers.forEach(function(layer){
// //console.log("layersssss",layer.id);
// // map.moveLayer('detailsLayer', layer.id);
// });
}
// 地图图层控制
const handlerLoadMapLayer = () => {
if (switchLayerControler) {
// var allLayers = map.getStyle().layers;
// allLayers.forEach(function(layer){
// //console.log("layerEEEEEE",layer);
// //console.log(layer.id);
// // map.removeLayer(layer.id);
// });
// var allSources = Object.keys(map.style.sourceCaches);
// allSources.forEach(function(sourceId){
// map.removeSource(sourceId);
// });
map.removeControl(switchLayerControler);
}
let configlayers = {};
let baseLayers = [];
props.mapConfig.layers?.forEach((item, index) => {
let applicationLayers = [];
item?.layers?.forEach((it, idx) => {
let style = JSON.parse(it.style);
let layers = {
name: it.name,
layer: style,
fixed: true,
zoom: 18,
easeToOptions: {},
mutex: false,
mutexIdentity: generateUUID(),
active: it.checked,
backgroundImage: '',
backgroundImageActive: '',
selectAndClearAll: true,
selectAllLabel: 'select all',
clearAllLabel: 'clear all',
onVisibleChange: (visible: boolean) => {},
};
applicationLayers.push(layers);
});
configlayers[item.name] = {
uiType: 'SwitchBtn',
collapse: !0,
defaultCollapsed: !0,
layers: applicationLayers,
};
});
props.mapConfig.baseLayers?.forEach((item, index) => {
//console.log('baselayers', item);
let layer = JSON.parse(item.style);
let image = item.image.replace('\\', '/');
let layers = {
name: item.name,
layer: layer,
fixed: false,
// zoom:0,
easeToOptions: {},
active: item.checked,
backgroundImage: VITE_GLOB_API_URL_VAR.value + image,
backgroundImageActive: '',
onVisibleChange: (visible: boolean) => {
handlerLayerChange();
},
};
//console.log('layersssss', layers);
baseLayers.push(layers);
});
configlayers['地图底图'] = {
collapse: !0,
defaultCollapsed: !0,
uiType: 'ImgTxtBtn',
layers: baseLayers,
};
if (props?.mapConfig) {
if (props?.mapConfig?.baseLayers?.length > 0 && props?.mapConfig?.layers?.length > 0) {
// 图层管理工具
switchLayerControler = new SwitchLayerControl({
name: '图层管理',
position: 'top-left',
showToTop: true,
layerGroups: configlayers,
});
map.addControl(switchLayerControler, 'top-left');
}
}
handlerLayerChange();
};
// 销毁地图
const findLayerAttributeInfo = (layers, id) => {
let layer = layers?.find((itme, index) => {
return itme.layer.id == id;
});
if (layer) {
if (layer.layer.state) {
return layer.layer.state;
} else {
return false;
}
}
};
// 加载地形
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: mapContainerName.value,
language: 'zh-cmn',
projection: 'equirectangular', // wgs84参考系
style: MapboxDefaultStyle,
// maxZoom: props.mapConfig.maxZoom ? props.mapConfig.maxZoom:18,
maxZoom:50,
minZoom: props.mapConfig.minZoom ? props.mapConfig.minZoom : 1,
zoom: props.mapConfig.zoom ? props.mapConfig.zoom : 10,
pitch: props.mapConfig.angle ? props.mapConfig.angle : 0,
center: props.mapConfig.center?.split(',')
? props.mapConfig.center?.split(',')
: [118.340253, 35.092481],
});
};
const handlerMapControlClick = (handler: string) => {
handler === 'handlerDrawPoint' && handlerDrawPoint();
handler === 'handlerDrawLineString' && handlerDrawLineString();
handler === 'handlerDrawPolygon' && handlerDrawPolygon();
};
// 使用坐标点分割图斑
const onHandlerSplitPolygon = () => {
if (locationArrays.value.length < 2) {
createMessage.warning('必须绘制2个以上点');
} else {
let feature = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [],
},
};
locationDrawArrays.value?.forEach((item, index) => {
if (item.lng && item.lat) {
let coor = [parseFloat(item.lng), parseFloat(item.lat)];
feature.geometry.coordinates.push(coor);
}
});
splitFeature(feature.geometry.coordinates);
}
};
// 分割图斑
const splitFeature = (line) => {
let turfSplitLine = turf.lineString(line);
let splitLineString = turf.cleanCoords(turfSplitLine);
let splitPolygon = currentGeoJson.value;
try {
// let features = polygonCut(splitPolygon,splitLineString,0.1,"meters");
splitPolygon?.geometry.coordinates[0].forEach((item,index)=>{
splitPolygon.geometry.coordinates[0][index] = [item[0],item[1]];
})
console.log("splitLineString",splitLineString);
let features = splitPolygonByLine(splitLineString, JSON.parse(JSON.stringify(editGeoJson.value)));
if(features){
let tempFeatures = JSON.parse(JSON.stringify(features))
let splitAfterFeatures = {
type: 'FeatureCollection',
features: [],
};
splitAfterFeatures.features = tempFeatures;
console.log("tempFeatures",tempFeatures);
// 分割数据返回父组件中
emit('handlerSplitPolygon', tempFeatures);
handlerUnDraw();
}else{
createMessage.warning("分割失败,请重新绘制")
handlerUnDraw();
}
} catch (e) {
console.error(e);
createMessage.warning('分割线起点、终点需要在图斑外,多个图斑时需要点击选择需要分割的图斑!');
handlerUnDraw();
}
};
// 根据面分割
const splitFeatureByFill = (fill) => {
// 去除重复点坐标
let turfPolygon = turf.polygon([fill]);
let drawPolygon = turf.cleanCoords(turfPolygon);
//console.log("drawPolygon",drawPolygon);
// let drawPolygon = {
// type: 'Feature',
// properties: {
// id:null,
// },
// geometry: {
// coordinates: [fill],
// type: 'Polygon',
// },
// };
let splitPolygon = currentGeoJson.value;
try{
splitPolygonByFill(drawPolygon, JSON.parse(JSON.stringify(editGeoJson.value))).then(features=>{
if(features){
features?.forEach((item,index)=>{
features[index].properties.id = generateUUID();
})
let tempFeatures = JSON.parse(JSON.stringify(features))
let splitAfterFeatures = {
type: 'FeatureCollection',
features: [],
};
splitAfterFeatures.features = tempFeatures;
emit('handlerSplitPolygon', tempFeatures);
handlerUnDraw();
}
})
}catch(e){
//console.log(e);
createMessage.warning('分割失败,请重新绘制数据!');
handlerUnDraw();
}
};
// shapefile多面分割数据
const splitFeatureByMultiFill = (geojson)=>{
let splitPolygon = currentGeoJson.value;
splitPolygonByMultiFill(geojson.features,JSON.parse(JSON.stringify(editGeoJson.value))).then(features=>{
if(features){
features?.forEach((item,index)=>{
features[index].properties.id = generateUUID();
})
let tempFeatures = JSON.parse(JSON.stringify(features))
let splitAfterFeatures = {
type: 'FeatureCollection',
features: [],
};
splitAfterFeatures.features = tempFeatures;
emit('handlerSplitPolygon', tempFeatures);
handlerUnDraw();
}
})
}
//绘制点
const handlerDrawPoint = () => {
mp.draw('Point');
mp.on('Point', function (e) {
emit('mapDraw', 'Point', e);
});
};
const splitPanelVisible = ref<Boolean>(false);
//绘制线
const handlerDrawLineString = () => {
splitPanelVisible.value = false;
mp.draw('LineString');
mp.on('LineString', function (e) {
Modal.confirm({
title: '是否确认分割图斑?',
onCancel() {
handlerUnDraw();
},
async onOk() {
let coordinates = [];
e?.forEach((item, index) => {
coordinates?.push([item.lng, item.lat]);
});
splitFeature(coordinates);
},
});
emit('mapDraw', 'LineString', e);
});
};
//绘制面
const handlerDrawPolygon = () => {
splitPanelVisible.value = false;
mp.draw('Polygon');
mp.on('Polygon', function (e) {
Modal.confirm({
title: '是否确认分割图斑?',
onCancel() {
handlerUnDraw();
},
async onOk() {
let coordinates = [];
e?.forEach((item, index) => {
coordinates?.push([item.lng, item.lat]);
});
coordinates.push(coordinates[0]);
splitFeatureByFill(coordinates);
handlerUnDraw();
},
});
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 currentPosition = ref(null);
// 图斑定位
const handlerLocation = (lngLat) => {
map.flyTo({
center: lngLat,
zoom: 17,
speed: 10, // 飞行速度
curve: 1, // 飞行曲线
easing(t) {
// 飞行动画函数
return t;
},
});
};
// 定位
const handlerToPosition = () => {
if (currentPosition.value) {
map.flyTo({
center: currentPosition.value,
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 = () => {
if (drawTool) {
map.removeControl(drawTool);
drawTool = null;
drawing.value = false;
}
// 清空详情图层
if (map.getSource('detailsSource')) {
map.getSource('detailsSource').setData({
type: 'FeatureCollection',
features: [],
});
}
};
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);
// let lngLat = getGeometryCenter(geo.features[0]);
currentPosition.value = lngLat;
handlerLocation(lngLat);
}
} catch (e) {
console.error('wktParse', e);
createMessage.error('WKT数据格式解析错误请检查WKT数据格式是否有误');
}
}
}
}
switch (status) {
case 'Add':
handlerInitDrawTool(geo, bool);
break;
case 'Edit':
handlerInitDrawTool(geo, bool);
break;
case 'Details':
handlerDetails(geo,'detailsSource',
'detailsLayer',
{
lineStyle: { 'line-color': '#fcf003', 'line-width': 3 },
fillStyle: { 'fill-color': '#fcf003', 'fill-opacity': 0.1 },
},true);
break;
default:
createMessage.error('请传入操作类型!');
}
};
const currentGeoJson = ref({});
const editGeoJson = ref({})
const handlerDetails = (
geojson,
source = 'detailsSource',
layer = 'detailsLayer',
style = {
lineStyle: { 'line-color': '#fcf003', 'line-width': 3 },
fillStyle: { 'fill-color': '#fcf003', 'fill-opacity': 0.1 },
},
isFirstLoad=false,
) => {
let fillLayerName = layer + 'Fill';
let lineLayerName = layer + 'Line';
if (source == 'detailsSource' || source == "splitPolygonSource") {
// 判断是单面还是多面
if(isFirstLoad){
geojson = handlerToMultiPolygonGeoJson(geojson);
}else{
}
let coordinates = null;
editGeoJson.value = geojson.features[0];
if (geojson.features.length>0 && geojson.features[0].geometry.type == 'MultiPolygon') { // 多面
// 默认取了第一个面的数据
coordinates = geojson.features[0].geometry.coordinates[0];
} else if (geojson.features.length>0 && geojson.features[0].geometry.type == 'Polygon') { // 单面
coordinates = geojson.features[0].geometry.coordinates;
}
// 天坑! 判读端传回的的图斑数据 最后2个坐标完全相同导致Mapbox解析不了报错
if (coordinates) {
if((coordinates[0][coordinates[0].length - 1][0] == coordinates[0][coordinates[0].length - 2][0]) && (coordinates[0][coordinates[0].length - 1][1] == coordinates[0][coordinates[0].length - 2][1])) {
coordinates[0]?.pop();
}
}
let singleFeature = {
type: 'Feature',
properties: {},
geometry: {
coordinates:[],
type: 'Polygon',
},
};
if(coordinates){
let turfPolygon = turf.polygon(coordinates);
singleFeature = turf.cleanCoords(turfPolygon);
}
// 处理清除数据重复的点数据
// 需要将传入的geojson处理成单面才能在分割工具中使用
currentGeoJson.value = singleFeature;
}
if (map.getSource(source)) {
map.getSource(source).setData(geojson);
} else {
map.addSource(source, {
type: 'geojson',
data: geojson,
});
map.addLayer({
id: fillLayerName,
type: 'fill',
source: source,
layout: {},
paint: style.fillStyle,
});
map.addLayer({
id: lineLayerName,
type: 'line',
source: source,
layout: {},
paint: style.lineStyle,
});
map.on('click', fillLayerName, function (e) {
// handlerPreviewFeatureInfo(e);
if (e.features.length > 0) {
var feature = e.features[0];
emit('onFeatureClick', feature);
}
if(fillLayerName == 'detailsLayerFill' || fillLayerName == 'detailsLayerLine'){
}
});
}
};
// 创建查看图斑图层
// 粘贴坐标实现定位、绘图相关
interface LocationItem {
lng: string;
lat: string;
}
const LocationShow = ref<Boolean>(false);
const locationColumns = ref([
{
title: '定位',
dataIndex: 'position',
key: 'position',
},
{
title: '经度',
dataIndex: 'lng',
key: 'lng',
},
{
title: '纬度',
dataIndex: 'lat',
key: 'lat',
},
{
title: '操作',
dataIndex: 'operation',
key: 'operation',
},
])
const locationArrays = ref<LocationItem[]>([]);
const locationDrawArrays = ref<LocationItem[]>();
const locationGeoJson = reactive({
point: {
type: 'FeatureCollection',
features: [],
},
polyline: {
type: 'FeatureCollection',
features: [],
},
polygon: {
type: 'FeatureCollection',
features: [],
},
});
const handlerPushLocationItem = () => {
let item: LocationItem = {
lng: '',
lat: '',
};
locationArrays.value.push(item);
};
// 通过上传txt文件方式导入坐标数据
const handleImportCoorinateChange = (e)=>{
const reader = new FileReader();
reader.readAsText(e);
reader.onload = function(text){
//console.log(text.target?.result?.split("\r\n"))
handlerImportCoor(text.target?.result?.split("\r\n"));
}
}
const handlerImportCoor = (arr)=>{
arr?.forEach((item,index)=>{
let coor = item.split(",");
if(coor[0] && coor[1]){
let obj = {
lng:parseFloat(coor[1]),
lat:parseFloat(coor[0])
}
locationArrays.value?.push(obj);
}
})
}
const handlerClearLocationItem = () => {
locationArrays.value = [];
locationGeoJson.point.features = [];
locationGeoJson.polygon.features = [];
locationGeoJson.polyline.features = [];
handlerLocationLoadLayer();
};
const handlerLocationClose = () => {
LocationShow.value = false;
};
const handlerLocationRemove = (index: number) => {
locationArrays.value.splice(index, 1);
locationDrawArrays.value?.splice(index, 1);
handlerLocationGeoJson();
};
const handlerLocationChange = (e) => {};
// 定位跳转
const handlerLocationFlyTo = (clickIndex:number) => {
locationDrawArrays.value = [];
locationArrays.value?.forEach((location)=>{
let obj={...location}
//console.log(obj);
locationDrawArrays.value?.push(obj)
})
locationDrawArrays.value?.forEach((item,index)=>{
// 坐标系转换
if(item.lng > 180){
let coor = GkToCGCS2000([parseFloat(item.lng),parseFloat(item.lat)]);
item.lng = coor[0];
item.lat = coor[1];
}
if (item.lng && item.lat) {
handlerLocationGeoJson();
}
})
// 跳转坐标
handlerLocation([locationDrawArrays.value[clickIndex].lng, locationDrawArrays.value[clickIndex].lat]);
};
// 处理生成geojson数据
const handlerLocationGeoJson = () => {
locationGeoJson.point.features = [];
locationGeoJson.polyline.features = [];
locationGeoJson.polygon.features = [];
locationDrawArrays.value?.forEach((item, index) => {
if (item.lng && item.lat) {
let feature = {
type: 'Feature',
geometry: {
type: 'Point',
coordinates: [parseFloat(item.lng), parseFloat(item.lat)],
},
};
locationGeoJson.point.features.push(feature);
}
});
if (locationDrawArrays.value?.length >= 2) {
let feature = {
type: 'Feature',
geometry: {
type: 'LineString',
coordinates: [],
},
};
locationDrawArrays.value?.forEach((item, index) => {
if (item.lng && item.lat) {
let coor = [parseFloat(item.lng), parseFloat(item.lat)];
feature.geometry.coordinates.push(coor);
}
});
feature.geometry.coordinates.push([
parseFloat(locationDrawArrays.value[0].lng),
parseFloat(locationDrawArrays.value[0].lat),
]);
locationGeoJson.polyline.features[0] = feature;
}
if (locationDrawArrays.value?.length >= 3) {
let feature = {
type: 'Feature',
geometry: {
type: 'Polygon',
coordinates: [[]],
},
};
locationDrawArrays.value?.forEach((item, index) => {
if (item.lng && item.lat) {
let coor = [parseFloat(item.lng), parseFloat(item.lat)];
feature.geometry.coordinates[0].push(coor);
}
});
feature.geometry.coordinates[0].push([
parseFloat(locationDrawArrays.value[0].lng),
parseFloat(locationDrawArrays.value[0].lat),
]);
locationGeoJson.polygon.features[0] = feature;
}
handlerLocationLoadLayer();
//console.log('locationGeoJson', locationGeoJson);
};
// 加载点、线、面图层
const handlerLocationLoadLayer = () => {
//console.log("locationGeoJson123",locationGeoJson);
// 绘制点
if (map.getSource('LocationPointSource')) {
map.getSource('LocationPointSource').setData(locationGeoJson.point);
} else {
map.addSource('LocationPointSource', {
type: 'geojson',
data: locationGeoJson.point,
});
map.addLayer({
id: 'LocationPointLayer',
type: 'circle',
source: 'LocationPointSource',
paint: {
'circle-radius': 5,
'circle-color': '#408eff', // 设置点的颜色
},
});
}
// 绘制线
if (map.getSource('LocationPolylineSource')) {
map.getSource('LocationPolylineSource').setData(locationGeoJson.polyline);
} else {
map.addSource('LocationPolylineSource', {
type: 'geojson',
data: locationGeoJson.polyline,
});
map.addLayer({
id: 'LocationLineLayer',
type: 'line',
source: 'LocationPolylineSource',
paint: {
'line-color': '#408eff', // 设置线的颜色
'line-width': 2, // 设置线的宽度
},
});
}
// 绘制面
if (map.getSource('LocationPolygonSource')) {
map.getSource('LocationPolygonSource').setData(locationGeoJson.polygon);
} else {
map.addSource('LocationPolygonSource', {
type: 'geojson',
data: locationGeoJson.polygon,
});
map.addLayer({
id: 'LocationPolygonLayer',
type: 'fill',
source: 'LocationPolygonSource',
paint: {
'fill-color': '#408eff', // 设置填充颜色
'fill-opacity': 0.5, // 设置填充透明度
},
});
}
};
// 绘制图片方位角
// 是否显示全部方位角
const isShowPicture = ref<Boolean>(true);
const imageList = ref<Array>([]);
const pictureArrowElementArray = ref([]);
const pictureArrowMarker = ref([]);
const pictureParentArrowElementArray = ref([]);
const currentPictureIndex = ref(null);
const currentPictureZIndex = ref(0);
function handlerLoadPictureAzimuth(list) {
pictureArrowMarker.value?.forEach((marker,index)=>{
if(marker){
marker.remove();
}
})
imageList.value = list;
pictureArrowMarker.value = [];
pictureArrowElementArray.value = [];
pictureParentArrowElementArray.value = [];
list.forEach((item, index) => {
if (item.lng && item.lat) {
let arrowElement = document.createElement('div');
arrowElement.className = 'picArrow';
arrowElement.style.width = '43px';
arrowElement.style.height = '57px';
let childElement = document.createElement('div');
childElement.className = 'childArrow';
childElement.style.width = '43px';
childElement.style.height = '57px';
childElement.style.transform = 'rotate(' + item.orientation + 'deg)';
childElement.style.backgroundImage = 'url(/map/arrow.png)';
childElement.style.backgroundSize = '43px 57px';
childElement.style.position = "relative";
arrowElement.appendChild(childElement);
pictureArrowElementArray.value?.push(childElement);
pictureParentArrowElementArray.value?.push(arrowElement);
let arrowMark = new mapboxgl.Marker(arrowElement)
.setLngLat([item.lng, item.lat])
.addTo(map);
pictureArrowMarker.value?.push(arrowMark);
}
});
currentPictureZIndex.value = list?.length;
// setTimeout(function(){
// handlerCurrentImageChange(0);
// },10000)
}
function handlerCurrentImageChange(fileName) {
// 根据图片名检索标签
let currentIndex = null;
imageList.value?.forEach((item, index) => {
if (item.filePath?.match(fileName)) {
currentIndex = index;
currentPictureIndex.value = index;
}
});
try {
pictureArrowElementArray.value?.forEach((itme, index) => {
pictureArrowElementArray.value[index].style.backgroundImage = 'url(/map/arrow.png)';
if(isShowPicture.value){
pictureArrowElementArray.value[index].style.display = 'block';
}else{
pictureArrowElementArray.value[index].style.display = 'none';
}
});
pictureArrowElementArray.value[currentIndex].style.backgroundImage = 'url(/map/arrow-a.png)';
pictureArrowElementArray.value[currentIndex].style.display = 'block';
// 设置显示在最上层
currentPictureZIndex.value = currentPictureZIndex.value + 1;
pictureParentArrowElementArray.value[currentIndex].style.zIndex = currentPictureZIndex.value;
} catch (e) {}
return;
}
function handlerChangePictureVisible(){
isShowPicture.value = !isShowPicture.value;
// 展示全部
if(isShowPicture.value){
pictureArrowElementArray.value?.forEach((itme, index) => {
pictureArrowElementArray.value[index].style.display = 'block';
});
}else{
pictureArrowElementArray.value?.forEach((itme, index) => {
pictureArrowElementArray.value[index].style.display = 'none';
});
if(pictureArrowElementArray.value?.length){
pictureArrowElementArray.value[currentPictureIndex.value].style.display = 'block';
}
}
// 展示选中
}
// 绘制点
const handlerLocationDrawPoint = () => {};
// 绘制线
const handlerLocationDrawLine = () => {};
// 绘制面
const handlerLocationDrawPolygon = () => {};
// 云查询按钮-启动
function initiateCloudQuery1() {
let geomidStr = props.geomsList.map((item) => item.key).join(',');
AddDroneTask({ geomid: geomidStr, caseno: props.caseno, countyname: props.countyname }).then(
(res) => {
if (res) {
message.success('成功提交云查询');
useCloudQuery.setGeomid(geomidStr);
useCloudQuery.setCaseno(props.caseno);
useCloudQuery.setIdentification(true);
let expires =
'; expires=' + new Date(new Date().getTime() + 60 * 60 * 1000).toUTCString();
document.cookie = 'geomid=' + encodeURIComponent(geomidStr) + expires + '; path=/';
document.cookie = 'caseno=' + encodeURIComponent(props.caseno) + expires + '; path=/';
document.cookie = 'identification=true' + expires + '; path=/';
} else {
message.error('提交云查询失败');
useCloudQuery.setIdentification(false);
}
},
);
}
// 云查询按钮-查询中
function initiateCloudQuery2() {
let geomidStr = props.geomsList.map((item) => item.key).join(',');
// 查看当前后台云查询图斑的情况
LoadCloudQueryByCaseNo({
geomid: useCloudQuery.geomid,
caseno: useCloudQuery.caseno,
}).then((res) => {
if (res) {
if (geomidStr == useCloudQuery.geomid && props.caseno == useCloudQuery.caseno) {
if (res.state == 1 || res.state == 0) {
message.warning('当前图斑的云查询正在运行,请稍候等待');
} else {
useCloudQuery.setIdentification(false);
useCloudQuery.setBeforeId(res.queryId);
useCloudQuery.setCloudQueryInfo({ id: res.queryId });
let expires =
'; expires=' + new Date(new Date().getTime() + 60 * 60 * 1000).toUTCString();
document.cookie = 'beforeId=' + encodeURIComponent(res.queryId) + expires + '; path=/';
open.value = true;
}
} else {
// 非当前后台云查询的图斑
message.warning('已有云查询运行,不能再次提交');
}
}
});
}
// 云查询按钮-查看结果
function initiateCloudQuery3() {
open.value = true;
}
// 云查询内容提示---------------------------------------------------------
function closeCloudQuery() {
useCloudQuery.setCloudQueryVisable(false);
useCloudQuery.identification = false;
}
//接口推送
signal.on('RevMsg', (user, cloudDataString, time, id, issystem) => {
// CloudQuery 云查询
if (user == 'CloudQuery') {
let cloudData = JSON.parse(cloudDataString);
if (
cloudData.geomid == useCloudQuery.getGeomid &&
cloudData.caseno == useCloudQuery.getCaseno
) {
if (useCloudQuery.beforeId == '' || cloudData.queryid != useCloudQuery.beforeId) {
let expires =
'; expires=' + new Date(new Date().getTime() + 24 * 60 * 60 * 1000).toUTCString();
document.cookie =
'beforeId=' + encodeURIComponent(cloudData.queryId) + expires + '; path=/';
}
useCloudQuery.setBeforeId(cloudData.queryid);
}
}
});
const compare = ref(false);
const open = ref(false);
const changeCompare = (value) => {
compare.value = value;
};
const closeCloudQueryModal = () => {
open.value = false;
compare.value = false;
}
defineExpose({
handlerDraw,
handlerDetails,
handlerLocation,
handlerCancleDraw,
handlerLoadPictureAzimuth,
handlerCurrentImageChange,
});
</script>
<style scoped>
.cloud-query-div {
position: absolute;
top: 50px;
left: 10px;
width: 66px;
height: 66px;
background: #fff;
display: flex;
align-items: center;
justify-content: center;
padding: 5px;
border-radius: 5px;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
user-select: none;
cursor: pointer;
}
.cloud-query-icon {
display: flex;
align-items: center;
justify-content: center;
margin-bottom: 8px;
}
.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;
right: 0px;
}
.mapbox-gl-draw_ctrl-draw-btn {
width: 20px !important;
height: 20px !important;
float: left;
}
.mapboxgl-ctrl-top-right {
width: 360px;
}
.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;
}
::v-deep .jas-ctrl-extend-desktop-container {
width: 320px !important;
}
.position-by-lnglat {
height: 29px;
background: #fff;
position: absolute;
top: 10px;
right: 131px;
border-radius: 3px;
box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
.to-location {
width: 29px;
height: 29px;
float: left;
background: url(/map/location.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
.picture-azimuth {
width: 29px;
height: 29px;
float: left;
background: url(/map/is_show_picture.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
.picture-azimuth-active {
width: 29px;
height: 29px;
float: left;
background: url(/map/not_show_picture.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
.draw-polygon {
width: 29px;
height: 29px;
float: left;
background: url(/map/draw_polygon.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
.split-line {
width: 29px;
height: 29px;
float: left;
background: url(/map/split_polygon.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
.split-polygon {
width: 29px;
height: 29px;
float: left;
background: url(/map/split_polygon_polygon.png);
background-size: 20px 20px;
background-repeat: no-repeat;
background-position: 4px 5px;
&:hover {
cursor: pointer;
}
}
}
.to-location-input {
padding: 16px;
padding-right: 4px;
width: 418px;
min-height: 60px;
background: #fff;
position: absolute;
top: 48px;
right: 10px;
z-index: 999999;
border-radius: 5px;
box-shadow: 0px 0px 10px rgba(0, 0, 0, 0.1);
.location-operation {
width: 100%;
height: 40px;
border-bottom: 1px solid #f1f1f1;
margin-bottom: 12px;
}
.location-item-list-coantienr {
width: 100%;
max-height: 400px;
overflow-y: auto;
.location-item {
line-height: 20px;
margin-bottom: 6px;
}
}
}
.split-panel-item:hover {
cursor: pointer;
color: #999;
}
.cloudqueryNotice {
background: rgba(0, 0, 0, 0.53);
padding: 0px 14px;
border-radius: 6px;
position: fixed;
top: 20px;
right: 5vw;
width: 700px;
color: #fff;
z-index: 10;
.cloudquery-title {
height: 40px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
}
.cloudquery-left {
display: flex;
align-items: center;
}
.cloudquery-right {
display: flex;
align-items: center;
justify-content: space-around;
width: 130px;
}
img {
width: 34px;
height: 29px;
}
.cloudquery-btn {
display: flex;
justify-content: flex-end;
}
.line {
background: #ededed;
width: 1px;
height: 20px;
}
.anticon.anticon-close {
height: 30px;
}
button {
width: 70px;
height: 26px;
background: linear-gradient(-74deg, #086dec, #0b4bdd);
box-shadow: 3px 4px 5px 1px rgba(13, 13, 13, 0.05);
border-radius: 16px;
display: flex;
align-items: center;
justify-content: center;
}
.title-box {
margin-left: 10px;
font-size: 14px;
}
}
</style>