地图网格线,新增地块,控制标签显示

master
贾肃 5 months ago
parent f5a4eae842
commit 1a624e005e
  1. 1
      package.json
  2. 61
      src/utils/ruoyi.js
  3. 4
      src/views/system/base/baseRightControl.vue
  4. 184
      src/views/system/base/massifMap.vue

@ -18,6 +18,7 @@
"dependencies": { "dependencies": {
"@element-plus/icons-vue": "2.3.1", "@element-plus/icons-vue": "2.3.1",
"@icon-park/vue-next": "^1.4.2", "@icon-park/vue-next": "^1.4.2",
"@turf/turf": "^6.5.0",
"@vuemap/vue-amap": "^2.1.1", "@vuemap/vue-amap": "^2.1.1",
"@vueup/vue-quill": "1.2.0", "@vueup/vue-quill": "1.2.0",
"@vueuse/core": "10.9.0", "@vueuse/core": "10.9.0",

@ -322,3 +322,64 @@ export function areaConversion(value, from = '平方米', arrive = '亩') {
var rst = (v * fRate[from][arrive]).toFixed(4);//保留4位小数 var rst = (v * fRate[from][arrive]).toFixed(4);//保留4位小数
return parseFloat(rst) return parseFloat(rst)
} }
/**
* 计算中心点
* @param lnglatarr
* @returns {AMap.LngLat}
*/
export function calculateCenter(lnglatarr) {
var total = lnglatarr.length;
var X = 0,
Y = 0,
Z = 0;
lnglatarr.map((item) => {
var lng = (item[0] * Math.PI) / 180;
var lat = (item[1] * Math.PI) / 180;
var x, y, z;
x = Math.cos(lat) * Math.cos(lng);
y = Math.cos(lat) * Math.sin(lng);
z = Math.sin(lat);
X += x;
Y += y;
Z += z;
});
X = X / total;
Y = Y / total;
Z = Z / total;
var Lng = Math.atan2(Y, X);
var Hyp = Math.sqrt(X * X + Y * Y);
var Lat = Math.atan2(Z, Hyp);
return new AMap.LngLat((Lng * 180) / Math.PI, (Lat * 180) / Math.PI);
}
/**
* 计算多边形边界并返回网格线路径
* @param polygon 多边形数据
* @param grid 网格大小 默认10m
* @returns {*[]}
*/
export function drawGridLines(polygon, grid = 10) {
let gridSize = 0.00001 * grid
let minLng = Infinity;
let maxLng = -Infinity;
let minLat = Infinity;
let maxLat = -Infinity;
// 计算边界
polygon.forEach(point => {
if (point[0] < minLng) minLng = point[0];
if (point[0] > maxLng) maxLng = point[0];
if (point[1] < minLat) minLat = point[1];
if (point[1] > maxLat) maxLat = point[1];
});
// 通过边界和网格大小计算网格线
var gridLines = [];
for (var lat = minLat; lat <= maxLat; lat += gridSize) { // 约等于10m
for (var lng = minLng; lng <= maxLng; lng += gridSize) { // 同上
// 创建水平和垂直两条线
gridLines.push([[lng, lat], [lng + gridSize, lat]]);
gridLines.push([[lng, lat], [lng, lat + gridSize]]);
}
}
return gridLines
}

@ -10,7 +10,8 @@ const router = useRouter()
const toBaseTable = () => { const toBaseTable = () => {
router.push('/system/base/baseTable') router.push('/system/base/baseTable')
} }
const control = reactive({ const control = defineModel({
default: {
// //
dataType: 1, dataType: 1,
// //
@ -25,6 +26,7 @@ const control = reactive({
showPlant: false, showPlant: false,
// //
plantLabel: false, plantLabel: false,
}
}) })
</script> </script>

@ -2,23 +2,100 @@
<script setup> <script setup>
import {ElAmap, useGeolocation, lazyAMapApiLoaderInstance} from "@vuemap/vue-amap"; import {ElAmap, useGeolocation, lazyAMapApiLoaderInstance} from "@vuemap/vue-amap";
import BaseRightControl from "@/views/system/base/baseRightControl.vue"; import BaseRightControl from "@/views/system/base/baseRightControl.vue";
import {areaConversion} from "@/utils/ruoyi.js"; import {areaConversion, calculateCenter, drawGridLines} from "@/utils/ruoyi.js";
import {ElMessageBox} from "element-plus"; import {ElMessage, ElMessageBox} from "element-plus";
import useSettingsStore from "@/store/modules/settings.js";
import * as turf from '@turf/turf'
const polygonRef = ref(null) const polygonRef = ref(null)
const settingsStore = useSettingsStore()
//
const currentMassif = ref(null)
const control = reactive({
//
dataType: 1,
//
massifLabel: true,
//
massifGrid: false,
//
showRidge: false,
//
ridgeLabel: false,
//
showPlant: false,
//
plantLabel: false,
})
// ref
const mouseToolRef = ref(null)
const router = useRouter() const router = useRouter()
const route = useRoute(); const route = useRoute();
// () // ()
const floorSpace = ref(0) const floorSpace = ref(0)
const maxHeight = ref(window.innerHeight - 100); const maxHeight = ref(window.innerHeight - 100);
const zoom = ref(13); const zoom = ref(17);
// //
const protract = ref(false) const protract = ref(false)
// //
const createdMouse = ref(false) const createdMouse = ref(false)
// id // id
const baseId = Number(route.params.baseId) const baseId = Number(route.params.baseId)
//
const componentText = ref([])
// 线
const gridLines = ref([])
// //
const polygonList = reactive([]) const polygonList = reactive([
{
id: 1,
title: '测试地块1',
path:[
[
116.337325,
39.979046
],
[
116.337334,
39.978387
],
[
116.337592,
39.978374
],
[
116.337861,
39.979013
],
[
116.337799,
39.97906
]
],
fillColor:'#09a882'
},
{
id:2,
title:'测试地块2',
path:[
[
116.338296,
39.978921
],
[
116.33829,
39.978668
],
[
116.338569,
39.978657
],
[
116.33859,
39.978905
]
]
}
])
const polygonTemp = ref(null) const polygonTemp = ref(null)
// //
const draw = (value) => { const draw = (value) => {
@ -72,17 +149,61 @@ const resetMassif = () => {
'重置后本次绘制内容将会被清空,是否确认重置?重置后可重新绘制', '重置后本次绘制内容将会被清空,是否确认重置?重置后可重新绘制',
'重置地块', '重置地块',
{ {
confirmButtonText: '不,我再想想', confirmButtonText: '确认重置',
cancelButtonText: '确认重置', cancelButtonText: '不,我再想想',
customClass:'message-box' customClass:'message-box'
} }
) )
.then(() => { .then(() => {
if (mouseToolRef.value){
mouseToolRef.value.$$close(true)
mouseToolRef.value.$$open()
}
addMassif() addMassif()
}) })
.catch(() => { .catch(() => {
}) })
} }
//
const submitMassif = () => {
lazyAMapApiLoaderInstance.then(() => {
if (polygonTemp.value.length<3){
ElMessage.error('地块至少需要三个点')
return
}
for (let item of polygonList) {
if (AMap.GeometryUtil.doesRingRingIntersect(polygonTemp.value,item.path) || AMap.GeometryUtil.isRingInRing(polygonTemp.value,item.path) || AMap.GeometryUtil.isRingInRing(item.path,polygonTemp.value)){
ElMessage.error('当前地块与已有地块边界重合,请修改后再确认')
return
}
}
polygonList.push({path:polygonTemp.value,edit:false})
polygonTemp.value = undefined
createdMouse.value = false
protract.value = false
})
}
watch(()=>polygonList,(value)=>{
componentText.value = []
value.forEach(item=>{
let points = turf.points(item.path);
//
componentText.value.push({text:item.title,position:turf.center(points).geometry.coordinates})
// 线
// gridLines.value.push(drawGridLines(item.path))
var bbox = turf.bbox(turf.lineString(item.path));
// km
var cellSide = 0.01;
var options = {units: 'kilometers'};
var squareGrid = turf.squareGrid(bbox, cellSide, options);
let newList = []
squareGrid.features.map(item => item.geometry.coordinates).forEach(item =>{
newList.push(...item)
})
gridLines.value.push(newList)
})
},{deep:true,immediate:true})
</script> </script>
<template> <template>
@ -107,6 +228,7 @@ const resetMassif = () => {
/> />
<!--鼠标工具--> <!--鼠标工具-->
<el-amap-mouse-tool <el-amap-mouse-tool
ref="mouseToolRef"
v-if="createdMouse" v-if="createdMouse"
type="polyline" type="polyline"
:auto-clear="true" :auto-clear="true"
@ -117,7 +239,8 @@ const resetMassif = () => {
v-for="(polygon, index) in polygonList" v-for="(polygon, index) in polygonList"
:path="polygon.path" :path="polygon.path"
:visible="true" :visible="true"
:editable="polygon.edit" :fillColor="polygon.fillColor"
:editable="false"
/> />
<!--多边形--> <!--多边形-->
<el-amap-polygon <el-amap-polygon
@ -130,13 +253,31 @@ const resetMassif = () => {
:visible="true" :visible="true"
:editable="true" :editable="true"
/> />
<!--灵活点标记-地块名称-->
<el-amap-marker
v-if="control.massifLabel"
v-for="comText in componentText"
:position="comText.position"
:visible="true"
:label="{content:comText.text,offset:[-50,0]}">
<div></div>
</el-amap-marker>
<el-amap-polyline
v-if="control.massifGrid"
v-for="grid in gridLines"
:path="grid"
:visible="true">
</el-amap-polyline>
<div class="top-block"> <div class="top-block">
<el-button v-if="!protract" class="operate" @click="addMassif"></el-button> <base-right-control v-if="!protract" v-model="control"/>
<base-right-control v-if="!protract"/> <!--左侧操作区-->
<div v-if="!protract" class="operate map-left">
<el-button @click="addMassif"></el-button>
</div>
<!--绘制操作区--> <!--绘制操作区-->
<div v-if="protract" class="protract-control operate"> <div v-if="protract" class="protract-control operate">
<el-button type="primary" :disabled="createdMouse">确认({{ floorSpace }})</el-button> <el-button type="primary" :disabled="createdMouse" @click="submitMassif">({{ floorSpace }})</el-button>
<el-button @click="resetMassif" :disabled="createdMouse">重置</el-button> <el-button @click="resetMassif"></el-button>
<el-button @click="cancelMassif"></el-button> <el-button @click="cancelMassif"></el-button>
</div> </div>
</div> </div>
@ -145,6 +286,7 @@ const resetMassif = () => {
</template> </template>
<style scoped lang="scss"> <style scoped lang="scss">
//
.top-block { .top-block {
position: absolute; position: absolute;
top: 0; top: 0;
@ -156,17 +298,30 @@ const resetMassif = () => {
pointer-events: all; pointer-events: all;
} }
} }
//
.map-left{
background: #FFFFFF;
width: 350px;
border-radius: 5px;
padding: 10px;
position: absolute;
left: 10px;
top: 20px;
//
opacity:0.9;
}
//
.local-icon { .local-icon {
width: 30px; width: 30px;
height: 30px; height: 30px;
} }
//
:deep(.amap-marker-label) { :deep(.amap-marker-label) {
border: none; border: none;
border-radius: 5px; border-radius: 5px;
padding: 5px 10px; padding: 5px 10px;
} }
//
.protract-control { .protract-control {
position: absolute; position: absolute;
right: 20px; right: 20px;
@ -174,6 +329,7 @@ const resetMassif = () => {
} }
</style> </style>
<style lang="scss"> <style lang="scss">
//
.message-box{ .message-box{
--el-messagebox-width: 450px; --el-messagebox-width: 450px;
padding: 20px; padding: 20px;

Loading…
Cancel
Save