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

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

@ -18,6 +18,7 @@
"dependencies": {
"@element-plus/icons-vue": "2.3.1",
"@icon-park/vue-next": "^1.4.2",
"@turf/turf": "^6.5.0",
"@vuemap/vue-amap": "^2.1.1",
"@vueup/vue-quill": "1.2.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位小数
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,21 +10,23 @@ const router = useRouter()
const toBaseTable = () => {
router.push('/system/base/baseTable')
}
const control = reactive({
const control = defineModel({
default: {
//
dataType:1,
dataType: 1,
//
massifLabel:false,
massifLabel: false,
//
massifGrid:false,
massifGrid: false,
//
showRidge:false,
showRidge: false,
//
ridgeLabel:false,
ridgeLabel: false,
//
showPlant:false,
showPlant: false,
//
plantLabel:false,
plantLabel: false,
}
})
</script>

@ -2,23 +2,100 @@
<script setup>
import {ElAmap, useGeolocation, lazyAMapApiLoaderInstance} from "@vuemap/vue-amap";
import BaseRightControl from "@/views/system/base/baseRightControl.vue";
import {areaConversion} from "@/utils/ruoyi.js";
import {ElMessageBox} from "element-plus";
import {areaConversion, calculateCenter, drawGridLines} from "@/utils/ruoyi.js";
import {ElMessage, ElMessageBox} from "element-plus";
import useSettingsStore from "@/store/modules/settings.js";
import * as turf from '@turf/turf'
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 route = useRoute();
// ()
const floorSpace = ref(0)
const maxHeight = ref(window.innerHeight - 100);
const zoom = ref(13);
//
const zoom = ref(17);
//
const protract = ref(false)
//
const createdMouse = ref(false)
// id
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 draw = (value) => {
@ -72,17 +149,61 @@ const resetMassif = () => {
'重置后本次绘制内容将会被清空,是否确认重置?重置后可重新绘制',
'重置地块',
{
confirmButtonText: '不,我再想想',
cancelButtonText: '确认重置',
confirmButtonText: '确认重置',
cancelButtonText: '不,我再想想',
customClass:'message-box'
}
)
.then(() => {
if (mouseToolRef.value){
mouseToolRef.value.$$close(true)
mouseToolRef.value.$$open()
}
addMassif()
})
.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>
<template>
@ -107,6 +228,7 @@ const resetMassif = () => {
/>
<!--鼠标工具-->
<el-amap-mouse-tool
ref="mouseToolRef"
v-if="createdMouse"
type="polyline"
:auto-clear="true"
@ -117,7 +239,8 @@ const resetMassif = () => {
v-for="(polygon, index) in polygonList"
:path="polygon.path"
:visible="true"
:editable="polygon.edit"
:fillColor="polygon.fillColor"
:editable="false"
/>
<!--多边形-->
<el-amap-polygon
@ -130,13 +253,31 @@ const resetMassif = () => {
:visible="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">
<el-button v-if="!protract" class="operate" @click="addMassif"></el-button>
<base-right-control v-if="!protract"/>
<base-right-control v-if="!protract" v-model="control"/>
<!--左侧操作区-->
<div v-if="!protract" class="operate map-left">
<el-button @click="addMassif"></el-button>
</div>
<!--绘制操作区-->
<div v-if="protract" class="protract-control operate">
<el-button type="primary" :disabled="createdMouse">确认({{ floorSpace }})</el-button>
<el-button @click="resetMassif" :disabled="createdMouse">重置</el-button>
<el-button type="primary" :disabled="createdMouse" @click="submitMassif">({{ floorSpace }})</el-button>
<el-button @click="resetMassif"></el-button>
<el-button @click="cancelMassif"></el-button>
</div>
</div>
@ -145,6 +286,7 @@ const resetMassif = () => {
</template>
<style scoped lang="scss">
//
.top-block {
position: absolute;
top: 0;
@ -156,17 +298,30 @@ const resetMassif = () => {
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 {
width: 30px;
height: 30px;
}
//
:deep(.amap-marker-label) {
border: none;
border-radius: 5px;
padding: 5px 10px;
}
//
.protract-control {
position: absolute;
right: 20px;
@ -174,6 +329,7 @@ const resetMassif = () => {
}
</style>
<style lang="scss">
//
.message-box{
--el-messagebox-width: 450px;
padding: 20px;

Loading…
Cancel
Save