gis模块

This commit is contained in:
xc
2022-01-24 09:17:22 +08:00
parent f1e5f53cad
commit f7892df366
48 changed files with 6131 additions and 22226 deletions

View File

@@ -0,0 +1,56 @@
<template>
<div class="map-nominal-container">
<div class="map-nominal-container-inner" v-for="(item,index) in param" v-bind:key="index">
<div class="map-nominal-container-inner-text">{{item.common}}</div>
<div class="map-nominal-container-inner-label" :style="{'backgroundColor':item.color}"></div>
<div class="map-nominal-container-inner-text">{{item.data}}</div>
</div>
</div>
</template>
<script>
export default {
name: "mapNominal",
props:{
param:{
type:Array
}
}
}
</script>
<style scoped>
.map-nominal-container {
width: auto;
position: absolute;
bottom: 10px;
left: 16px;
box-sizing: border-box;
padding: 6px;
background-color: #fff;
display: flex;
}
.map-nominal-container-inner-text {
width: 100%;
height: 29px;
line-height: 29px;
color: #606060;
font-size: 12px;
text-align: center;
}
.map-nominal-container-inner-label {
width: 100%;
height: 8px;
}
.map-nominal-container-inner {
width: 70px;
display: flex;
flex-direction: column;
margin-left: 3px;
}
</style>

View File

@@ -0,0 +1,88 @@
<template>
<div class="map-table-container " :style="{'right':type1 == 1 ? '0px':'-500px'}">
<a-card title="监测数据" :headStyle="{'padding':'0px 5px'}"
:bodyStyle="{'padding':'0px 5px','height':'200px','overFlow':'scroll'}">
<div class="left-close-button" @click="showTable(0)" v-if="type1 == 1">
<img src="https://sqtt.oss-cn-qingdao.aliyuncs.com/Uploads/image/goods/2022-01-08/61d8e51ac94d2.png" alt=""
style="width: 30px;height: 30px">
</div>
<div class="left-close-button" @click="showTable(1)" v-if="type1 == 0">
<img src="https://sqtt.oss-cn-qingdao.aliyuncs.com/Uploads/image/goods/2022-01-08/61d8e83754c7e.png" alt=""
style="width: 30px;height: 30px">
</div>
<a-table :columns="columns" :data-source="rowData" size="mini" :scroll="{y:150,x:500}" :pagination="false">
</a-table>
</a-card>
</div>
</template>
<script>
const columns = [
{
title: "站点名称",
dataIndex: 'place'
},
{
title: '类别',
dataIndex: 'placeFunctionalAreaCategory',
},
{
title: 'Aqi',
dataIndex: 'avgAqi',
},
{
title: '点位级别',
dataIndex: 'attributes',
}
];
export default {
props: {
rowData: {
type: Array
}
},
methods: {
showTable: function (type) {
this.type1 = type
}
},
data() {
return {
columns,
pagination: {
total: 0
},
type1: 0
};
},
}
</script>
<style scoped>
.map-table-container {
box-sizing: border-box;
width: 500px;
padding: 10px;
position: absolute;
bottom: 0px;
transition: right 0.8s;
}
::v-deep .ant-table-thead > tr > th, ::v-deep .ant-table-tbody > tr > td {
padding: 3px 3px;
}
.left-close-button {
width: 40px;
height: 40px;
background-color: #fff;
position: absolute;
left: -40px;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,93 @@
<template>
<div class="map-table-container " :style="{'right':type1 == 1 ? '0px':'-500px'}">
<a-card title="环境空气点位" :headStyle="{'padding':'0px 5px'}"
:bodyStyle="{'padding':'0px 5px','height':'200px','overFlow':'scroll'}">
<div class="left-close-button" @click="showTable(0)" v-if="type1 == 1">
<img src="https://sqtt.oss-cn-qingdao.aliyuncs.com/Uploads/image/goods/2022-01-08/61d8e51ac94d2.png" alt=""
style="width: 30px;height: 30px">
</div>
<div class="left-close-button" @click="showTable(1)" v-if="type1 == 0">
<img src="https://sqtt.oss-cn-qingdao.aliyuncs.com/Uploads/image/goods/2022-01-08/61d8e83754c7e.png" alt=""
style="width: 30px;height: 30px">
</div>
<a-table :columns="columns" :data-source="rowData" size="mini" :scroll="{y:150,x:500}" :pagination="false">
</a-table>
</a-card>
</div>
</template>
<script>
const columns = [
{
title: '点位名称',
dataIndex: 'place',
},
{
title: '点位等级',
className: 'regionLevel',
dataIndex: 'regionLevel',
},
{
title: '所属地区',
dataIndex: 'area',
},
{
title: '所属路段',
dataIndex: 'road',
},
{
title: '噪声 dB(A)',
dataIndex: 'leq',
},
];
export default {
props: {
rowData: {
type: Array
}
},
methods: {
showTable: function (type) {
this.type1 = type
}
},
data() {
return {
columns,
pagination: {
total: 0
},
type1: 0
};
},
}
</script>
<style scoped>
.map-table-container {
box-sizing: border-box;
width: 500px;
padding: 10px;
position: absolute;
bottom: 300px;
transition: right 0.8s;
}
::v-deep .ant-table-thead > tr > th, ::v-deep .ant-table-tbody > tr > td {
padding: 3px 3px;
}
.left-close-button {
width: 40px;
height: 40px;
background-color: #fff;
position: absolute;
left: -40px;
bottom: 0;
display: flex;
justify-content: center;
align-items: center;
}
</style>

View File

@@ -0,0 +1,94 @@
<template>
<div id="tip-tool-container" class="tip-tool-container"
:style="{'top':`${currentY}px`,'left':`${currentX}px`}">
<div class="tip-tool-container-top">
点位名称 {{data.place}}
</div>
<div class="tip-tool-container-text">
点位属性 {{data.attributes}}
</div>
<div class="tip-tool-container-text">
片区名称 {{data.districtName}}
</div>
<div class="tip-tool-container-text">
所属功能区分类 {{data.placeFunctionalAreaCategory}}
</div>
<div class="tip-tool-container-text">
SO2 {{data.avgSo2}} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NO2 {{data.avgNo2}}
</div>
<div class="tip-tool-container-text">
PM10 {{data.avgPm10}} &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CO {{data.avgCo}}
</div>
<div class="tip-tool-container-text">
O3 {{data.avgO3}}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PM2.5 {{data.avgPm25}}
</div>
</div>
</template>
<script>
export default {
props: {
x: {
type: Number,
default:30000
},
y: {
type: Number,
default: 0
},
flag: {
type: Boolean,
default: false
},
data:{
type:Object
}
},
watch: {
x(val) {
let tipToolInfo = document.getElementById("tip-tool-container")
let tipToolWidth = tipToolInfo.offsetWidth
this.currentX = val - tipToolWidth / 2
},
y(val) {
let tipToolInfo = document.getElementById("tip-tool-container")
let tipToolHeight = tipToolInfo.offsetHeight
this.currentY = val - tipToolHeight
}
},
data() {
return {
currentX: 30000,
currentY: 0,
currentFlag: false
}
}
}
</script>
<style scoped>
.tip-tool-container {
min-width: 150px;
min-height: 150px;
padding: 15px;
box-sizing: border-box;
border-radius: 15px;
background-color: rgba(0, 0, 0, .6);
color: #fff;
position: absolute;
z-index: 9999;
overflow: hidden;
&-top {
font-size: 18px;
font-weight: 550;
text-align: left;
}
&-text {
font-size: 15px;
line-height: 30px;
text-align: left;
}
}
</style>

View File

@@ -2,65 +2,133 @@
<div class="ele-body">
<a-card class="ele-card" :bordered="false">
<a-space>
<a-select @change="whereChange" v-model:value="where.year">
<a-select-option v-for="item in yearOptions" :key="item.value">{{
item.label
}}</a-select-option>
<a-auto-complete :filterOption="true" :backfill="false" @select="autoInput" :dataSource="dataSource"
placeholder="请输入需要搜索的点位">
</a-auto-complete>
<a-select @change="whereChange" name="year" v-model:value="where.year">
<a-select-option v-for="item in yearOptions" :key="item.value">
{{
item.label
}}
</a-select-option>
</a-select>
<a-radio-group @change="whereChange" v-model:value="where.regionLevel">
<a-radio-button value="city"> 市级 </a-radio-button>
<a-radio-button value="county"> 县级 </a-radio-button>
<a-radio-button value="place"> 站点 </a-radio-button>
<a-radio-group @change="whereChange" name="area" v-model:value="where.regionLevel">
<a-radio-button value="city">市级</a-radio-button>
<a-radio-button value="county">县级</a-radio-button>
<a-radio-button value="place">站点</a-radio-button>
</a-radio-group>
<!-- <a-radio-group name="day" v-model:value="where.timeSlot">-->
<!-- <a-radio-button value="昼"></a-radio-button>-->
<!-- <a-radio-button value="夜"></a-radio-button>-->
<!-- </a-radio-group>-->
<!-- <a-button @click="exportMap">导出</a-button> -->
</a-space>
</a-card>
<div id="map"></div>
<div id="map" ref="map" style="overflow: hidden"></div>
<tip-tool :flag="tipFlag" :x="currentX" :y="currentY" :data="tipData"></tip-tool>
<mapNominal :param="nominalList"></mapNominal>
<!-- <map-table-center :rowData="pointData"></map-table-center>-->
<map-table :rowData="pointData"></map-table>
</div>
</template>
<script>
import { Scene, PointLayer, Popup } from "@antv/l7";
import { GaodeMap } from "@antv/l7-maps";
// import {
// getGisCountList
// } from "@/api/ecology/noise/road-sound";
import {
getPlaceGis,
} from "@/api/ecology/atmosphere/air";
getAirGis,
} from "@/api/gis/gisApi";
import {
getColumnOptions,
} from "@/api/ecology/atmosphere/air-plcae";
import tipTool from "./components/tipTool";
import mapNominal from "./components/mapNominal";
import mapTable from "./components/mapTable";
// import mapTableCenter from "./components/mapTableCenter";
let scene = null;
let pointLayer = null;
let cityLayer = null;
var that
export default {
components: {
tipTool,
mapNominal,
mapTable,
// mapTableCenter
},
data() {
return {
yearOptions: [],
arriveCoor: [108.33, 22.84],//坐标点
where: {
regionLevel: "place",
year: "选择年份",
// timeSlot: "昼",
regionLevel: "city",
year: "",
},
map: {},
pointData: [],
currentY: 0,
currentX: 30000,
tipFlag: false,
tipData: [],
zoom: 13,
nominalList: [
{"text": "一级", "color": "#09952b", "data": "≤ 50.0", "min": "0", "max": "50.0", "common": "优"},
{"text": "二级", "color": "#c6c303", "data": "50.1~100.0", "min": "50.1", "max": "100.0", "common": "良"},
{"text": "三级", "color": "#ee7606", "data": "100.1~150.0", "min": "100.1", "max": "150.0", "common": "轻度污染"},
{"text": "四级", "color": "#f52b07", "data": "150.1~200.0", "min": "150.1", "max": "200.0", "common": "中度污染"},
{"text": "五级", "color": "#d50121", "data": "200.1~300.0", "min": "200.1", "max": "300", "common": "重度污染"},
{"text": "六级", "color": "#710000", "data": ">=300.1", "min": "300.1", "max": "100000", "common": "严重污染"},
],
points: [],//数据准备
dataSource: [],
value: '',
result: [],
searchKey: "",
searchId: -1
};
},
mounted() {
scene = new Scene({
id: "map",
map: new GaodeMap({
style: "light",
center: [108.33, 22.84],
// pitch: 48.62562,
// rotation: -0.76,
zoom: 12,
}),
});
scene.on("loaded", () => {
this.initData();
});
// const control = new DrawControl(scene, {
// });
that = this
this.newInitMap();
},
methods: {
initData() {
autoInput(e) {
that.dataSource.forEach((item, index) => {
if (item == e) {
if (that.searchId > 0) {
document.getElementById("id" + that.searchId).className = ""
}
that.searchId = index
// eslint-disable-next-line no-undef
that.map.centerAndZoom(new BMap.Point(that.pointData[that.searchId]['longitude'], that.pointData[that.searchId]['latitude']), that.zoom); // 初始化地图,设置中心点坐标和地图级别
document.getElementById("id" + that.searchId).className += "animation_check"
}
})
},
newInitMap() {
// eslint-disable-next-line no-undef
that.map = new BMap.Map(this.$refs.map); // 创建Map实例
// eslint-disable-next-line no-undef
that.map.centerAndZoom(new BMap.Point(that.arriveCoor[0], that.arriveCoor[1]), that.zoom); // 初始化地图,设置中心点坐标和地图级别
that.map.addControl(
// eslint-disable-next-line no-undef
new BMap.MapTypeControl({
// eslint-disable-next-line no-undef
mapTypes: [BMAP_NORMAL_MAP, BMAP_HYBRID_MAP],
})
)
that.map.enableDragging();
that.map.enableScrollWheelZoom();
that.map.enableDoubleClickZoom();
that.map.enableKeyboard();
getColumnOptions("year").then((res) => {
if (res.data.code == 0) {
this.yearOptions = res.data.data.map((item) => {
@@ -72,76 +140,146 @@ export default {
this.where.year = res.data.data[res.data.data.length - 1];
this.whereChange();
}
});
})
},
setPlaceData() {},
whereChange() {
if(scene && pointLayer){
scene.removeLayer(pointLayer)
}
getPlaceGis(this.where).then((res) => {
if (res.data.code == 0) {
if(cityLayer){
cityLayer.destroy()
scene.removeLayer(cityLayer)
}
pointLayer = new PointLayer({})
.source(res.data.data, {
parser: {
type: "json",
x: "longitude",
y: "latitude",
},
})
.shape('circle').size(10)
// .size("leq", acid (level) {
// return [4, 4, level];
// })
.active(true)
.color("leq", () => {
// const { timeSlot } = this.where;
// const color =
// timeSlot == "昼"
// ? leq > 70
// ? "#f5222d"
// : "#13c2c2"
// : leq > 65
// ? "#f5222d"
// : "#13c2c2";
return "#13c2c2";
})
.style({
opacity: 1,
});
pointLayer.on("mousemove", (e) => {
const popup = new Popup({
offsets: [0, 0],
closeButton: false,
})
.setLnglat(e.lngLat)
.setHTML(
`<p>点位名称: ${e.feature.place}</p><p>点位属性: ${e.feature.attributes}</p><p>片区名称: ${e.feature.districtName}</p><p>所在功能区类别: ${e.feature.placeFunctionalAreaCategory}</p>
<p>SO2: ${e.feature.avgSo2} NO2: ${e.feature.avgNo2}</p><p>PM10: ${e.feature.avgPm10} CO: ${e.feature.avgCo}</p><p>O3: ${e.feature.avgO3} PM2.5: ${e.feature.avgPm25}</p>`
);
scene.addPopup(popup);
});
pointLayer.setData(res.data.data);
scene.addLayer(pointLayer);
scene.setZoomAndCenter(12, [108.33, 22.84]);
// scene.setPitch(48);
scene.render()
addMarker: function () { // 创建图标对象
//1、定义构造函数并继承Overlay
//定义自定义覆盖物的构造函数
function ComplexCustomOverlay(point, index, color) {
this._point = point
this._index = index
this._color = color
}
// eslint-disable-next-line no-undef
ComplexCustomOverlay.prototype = new BMap.Overlay();
ComplexCustomOverlay.prototype.initialize = function (map) {
this._map = map;
var div = this._div = document.createElement("div");
div.style.position = "absolute";
div.style.float = "left"
div.style.cursor = "pointer"
// eslint-disable-next-line no-undef
div.style.zIndex = BMap.Overlay.getZIndex(this._point.lat);
div.style.height = "20px";
div.style.width = "10px";
var arrow = this._arrow = document.createElement("div");
arrow.style.width = "0px";
arrow.style.height = "0px";
arrow.style.borderLeftWidth = "10px"
arrow.style.borderLeftColor = "transparent"
arrow.style.borderStyle = "solid"
arrow.style.borderRightWidth = "10px"
arrow.style.borderRightColor = "transparent"
arrow.style.borderBottomWidth = "20px"
arrow.style.borderTopWidth = "0"
arrow.style.position = "absolute"
arrow.style.borderBottomColor = `${this._color}`
arrow.setAttribute("id", "id" + this._index)
arrow.style.top = "22px";
arrow.style.left = "10px";
div.appendChild(arrow);
that.map.getPanes().labelPane.appendChild(div);
return div;
}
ComplexCustomOverlay.prototype.draw = function () {
var map = this._map;
var pixel = map.pointToOverlayPixel(this._point);
this._div.style.left = pixel.x - parseInt(this._arrow.style.left) + "px";
this._div.style.top = pixel.y - 30 + "px";
}
ComplexCustomOverlay.prototype.addEventListener = function (event, fun) {
this._arrow['on' + event] = fun;
}
that.pointData.forEach(async (item, index) => {
let color = ""
that.nominalList.forEach((it, ins) => {
if (Number(item.avgAqi) >= it.min && Number(item.avgAqi) <= it.max) {
color = that.nominalList[ins]['color']
return false
}
});
})
// eslint-disable-next-line no-undef
var myCompOverlay = new ComplexCustomOverlay(new BMap.Point(item.longitude, item.latitude), index, color);
that.map.addOverlay(myCompOverlay);//将标注添加到地图中
myCompOverlay.addEventListener('mouseover', function (e) {
let currentId = e.target.getAttribute("id")
setTimeout(() => {
}, 300)
let bodyInfo = document.getElementsByTagName("body")[0]
let screenWidth = bodyInfo.offsetWidth
// let screenHeight = bodyInfo.offsetHeight
let mapInfo = document.getElementById("map")
let mapWidth = mapInfo.offsetWidth; // 返回元素的总宽度
// let mapHeight = mapInfo.offsetHeight; // 返回元素的总高度
let calcWidth = screenWidth - mapWidth
// let calcHeight = screenHeight - mapHeight
that.tipFlag = true
that.tipData = that.pointData[currentId.substring(2, currentId.length)]
that.currentX = e.pageX - calcWidth
that.currentY = e.pageY - 80
})
myCompOverlay.addEventListener('mouseout', function () {
setTimeout(() => {
}, 300)
that.currentX = 30000
that.currentY = 0
that.tipFlag = false
})
})
},
getAreaData() {},
exportMap(){
console.log("exportMap");
scene.exportMap("png");
}
},
};
whereChange(e) {
if (typeof (e) == "object") {
if (e.target.name == "area") {
that.where.regionLevel = e.target.value
if (that.where.regionLevel == "county") {
that.zoom = 8
} else {
that.zoom = 13
}
}
// if (e.target.name == "day") {
// that.where.timeSlot = e.target.value
// }
} else {
if (e > 0) {
that.where.year = e
}
}
that.map.clearOverlays();
// eslint-disable-next-line no-undef
that.map.centerAndZoom(new BMap.Point(108.33, 22.84), that.zoom);
// GIS
// that.getGisCountList()
if (scene && pointLayer) {
scene.removeLayer(pointLayer)
}
getAirGis(this.where).then((res) => {
that.pointData = []
that.dataSource = []
if (res.data.code == 0 && res.data.data.length > 0) {
that.pointData = res.data.data
that.pointData.forEach(item => {
that.dataSource.push(`${item.place}`)
})
that.addMarker()
}
})
},
}
}
;
</script>
<style scoped>
<style >
::-webkit-scrollbar {
display: none;
}
@@ -150,21 +288,85 @@ html,
body {
overflow: hidden;
margin: 0;
width: 100vw;
height: 100vh;
}
.ele-body {
position: relative;
height: 100%;
padding: 16px 0;
height: 100%;
}
.ele-card {
z-index: 10;
margin: 0 16px;
display: inline-block;
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
</style>
.anchorBL {
display: none;
}
::v-deep .amap-logo {
right: 0 !important;
left: auto !important;
display: none !important;
}
::v-deep .amap-copyright {
right: 70px !important;
left: auto !important;
opacity: 0 !important;
}
::v-deep .amap-info-content {
background-color: rgba(0, 0, 0, .4);
border-radius: 5px;
color: #fff;
padding: 0;
}
::v-deep .bottom-center .amap-info-sharp {
border-top-color: rgba(0, 0, 0, .6);
}
::v-deep .amap-info-close {
display: none;
}
::v-deep #map-mark {
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 20px solid rgba(0, 0, 255, 0.6);
}
.animation_check {
animation: myfirst 1s infinite;
}
@keyframes myfirst {
0% {
top: 0px
}
25% {
top: 5px;
}
50% {
top: 0px;
}
75% {
top: -5px;
}
100% {
top: 0px;
}
}
</style>