epmet pc工作端
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

514 lines
18 KiB

<template>
<div id="map">
<div class="search">
<el-input placeholder="请输入内容"
v-model="input"
clearable
size="medium">
<template slot="append">
<span style="cursor: pointer;"
@click="goSearch">搜索</span>
</template>
</el-input>
</div>
<div id="mapContent"
style="width: 100%;height: 100%;">
<div id="popup">
<a href="#"
id="popup-closer"></a>
<div id="popup-title">
场所信息
</div>
<div>
<div>
<span>场所名称{{featureInfo.place_name||"--"}}</span>
</div>
<div style="margin: 12px 0;">
<span>场所类型{{featureInfo.place_type||"--"}}</span>
</div>
<div>
<span>场所地址{{featureInfo.place_address||"--"}}</span>
</div>
<div class="moreInfo"
@click="ifShowDetails=true">更多信息</div>
</div>
</div>
</div>
<el-dialog :visible.sync="ifShowDetails"
width="60%"
:modal="false">
<span slot="title"
style="font-size:20px;font-weight:700">
{{ featureInfo.place_name }}的更多信息
</span>
<Dialog :info="featureInfo"></Dialog>
<div slot="footer"
style="display: flex;justify-content: space-evenly;">
<el-button @click="ifShowDetails = false"> </el-button>
<el-button type="primary"
@click="ifShowDetails = false"> </el-button>
</div>
</el-dialog>
</div>
</template>
<script>
2 years ago
import dy from '@/assets/images/fifteen/dy.png';
import education from '@/assets/images/fifteen/education.png';
import jr from '@/assets/images/fifteen/jr.png';
import qt from '@/assets/images/fifteen/qt.png';
import sy from '@/assets/images/fifteen/sy.png';
import sz from '@/assets/images/fifteen/sz.png';
import wt from '@/assets/images/fifteen/wt.png';
import xz from '@/assets/images/fifteen/xz.png';
import yl from '@/assets/images/fifteen/yl.png';
import { requestPostBi } from "@/js/dai/request-bipass";
import { Feature, Overlay } from 'ol';
import Map from 'ol/Map';
import View from 'ol/View';
import { defaults as defaultControls } from 'ol/control.js';
2 years ago
import { Circle, Point, Polygon } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
2 years ago
import { getPointResolution } from 'ol/proj';
import { METERS_PER_UNIT } from 'ol/proj/Units';
import { Vector as VectorSource, XYZ } from 'ol/source';
import { Fill, Icon, Stroke, Style, Text } from 'ol/style';
import Dialog from "./dialog.vue";
2 years ago
export default {
components: {
Dialog
},
data() {
return {
map: null,
vectorSource: null,
vectorLayer: null,
rangeSource: null,
rangeLayer: null,
positionSource: null,
positionLayer: null,
circleSource: null,
circleLayer: null,
featureInfo: {},
overlay: null,
input: "",
ifShowDetails: false,
dialogTitle: ""
}
},
mounted() {
this.init();
},
methods: {
init() {
//高德地图也是一种瓦片图层,是通过行列号与层级(zoom)关系加载的
let gaodeMapLayer = new TileLayer({
title: "高德地图",
source: new XYZ({
url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=7',
wrapX: true
})
});
this.map = new Map({
layers: [gaodeMapLayer],
view: new View({
center: [120.38140448734, 36.09344959486],
projection: 'EPSG:4326',
zoom: 14,
maxZoom: 18
}),
controls: defaultControls({
zoom: false,//禁用缩放控件
rotate: false,
}),
target: 'mapContent'
});
this.getRange()
let container = document.getElementById('popup');
//构建一个覆盖标注
this.overlay = new Overlay({
element: container,//将最外面的div容器放在覆盖标注中
autoPan: {
animation: {
duration: 250,//拖动动画的效果
},
},
});
//添加标注
this.map.addOverlay(this.overlay);
const _this = this;
_this.map.on("click", function (e) {
_this.featureInfo = {}
let feature = _this.map.forEachFeatureAtPixel(e.pixel, function (feature) {
return feature
});
if (feature && Object.keys(feature.values_).length > 1) {
container.style.display = "inline-block"
_this.featureInfo = feature.values_ || {}
if (_this.featureInfo && Object.keys(_this.featureInfo).length > 0) {
_this.initPop(e)
}
} else {
container.style.display = "none"
}
})
},
initPop(e) {
let coordinate = e.coordinate;//单击事件的坐标
this.overlay.setPosition(coordinate);//设置覆盖标注位置
//将视口的中心位置设置为鼠标点击的位置
// this.map.getView().setCenter(coordinate);
},
goMarker(data) {
document.getElementById('popup').style.display = "none"
if (this.positionLayer) {
this.map.removeLayer(this.positionLayer)
this.positionLayer = null
}
if (Array.isArray(data) && data.length > 1) {
if (this.vectorLayer) {
this.map.removeLayer(this.vectorLayer)
this.vectorLayer = null
}
//矢量标注的数据源
this.vectorSource = new VectorSource();
//矢量标注图层
this.vectorLayer = new VectorLayer({
source: this.vectorSource
});
this.map.addLayer(this.vectorLayer);
data.forEach(f => {
if (f.longitude && f.latitude) {
this.addImageVectorLabel(f)
}
})
}
if (Array.isArray(data) && data.length == 1) {
//矢量标注的数据源
this.positionSource = new VectorSource();
//矢量标注图层
this.positionLayer = new VectorLayer({
source: this.positionSource
});
this.map.addLayer(this.positionLayer);
this.addImageVectorLabel(data[0], "listClick")
if (data[0]['longitude'] && data[0]['latitude']) {
this.map.getView().setCenter([data[0]['longitude'], data[0]['latitude']]);
}
}
},
//添加图片标注
addImageVectorLabel(data, type) {
//新建一个点要素 ol.Feature
let newFeature = new Feature({
//几何信息
geometry: new Point([Number(data.longitude), Number(data.latitude)]),
});
newFeature.setProperties(data);
//设置要素的样式
data.place_type_code
if (type == "listClick") {
data.place_type_code = "listClick"
newFeature.setStyle(this.createImageLabelStyle(data.place_type_code));
//将新要素添加到数据源中
this.positionSource.addFeature(newFeature);
} else {
newFeature.setStyle(this.createImageLabelStyle(data.place_type_code));
//将新要素添加到数据源中
this.vectorSource.addFeature(newFeature);
}
},
createImageLabelStyle(type) {
let url
switch (type) {
case "commerce_service":
url = sy
break;
case "edu":
url = education
break;
case "finance_post":
url = jr
break;
case "medical":
url = yl
break;
case "administration":
url = xz
break;
case "culture_sport":
url = wt
break;
case "municipal":
url = sz
break;
case "others":
url = qt
break;
case "listClick":
url = dy
break;
default:
break;
}
return new Style({
image: new Icon(//返回一个图片标注
({
// anchor: [0.5, 60],
// anchorOrigin: 'top-right',
// anchorXUnits: 'fraction',
// anchorYUnits: 'pixels',
// offsetOrigin: 'top-right',
// offset:[0,10],
//图标缩放比例
scale: 1,
//透明度
opacity: 1,
//图标的url
src: url
})
)
});
},
async getRange() {
const url = "regional_scope";
const param = {
"org_id": localStorage.getItem("agencyId") || "",
}
const { data, code, msg } = await requestPostBi(
url,
{
queryParam: param
}
);
if (code == 0) {
data.forEach((f, i) => {
this.addPolygon(f, i)
})
}
},
addPolygon(value, index) {
if (this.rangeLayer) {
this.map.removeLayer(this.rangeLayer)
}
//矢量标注的数据源
this.rangeSource = new VectorSource();
//矢量标注图层
this.rangeLayer = new VectorLayer({
source: this.rangeSource
});
let arr = value.community_coordinates.split(",") || []
let res = [];
for (let index = 0; index < arr.length; index += 2) {
res.push([arr[index], arr[index + 1]]);
}
let polygon = new Feature({
geometry: new Polygon([res]),
});
let pointsCenter = this.getPointsCenter(res)
let point = new Feature({
geometry: new Point(pointsCenter),
});
if (index == 0) {
this.map.getView().setCenter(pointsCenter);
}
//设置区样式信息
polygon.setStyle(
new Style({
//填充色
fill: new Fill({
color: 'rgba(255, 255, 255, 0)',
}),
//边线颜色
stroke: new Stroke({
color: '#4095e5',
width: 4,
lineDash: [6],
}),
}),
);
point.setStyle(
new Style({
text: new Text({
//位置
textAlign: 'center',
//基准线
textBaseline: 'middle',
//文字样式
font: 'normal 14px 微软雅黑',
scale: 1.2,
//文本内容
text: value.grid_name,
//文本填充样式(即文字颜色)
fill: new Fill({ color: '#fff' }),
backgroundFill: new Fill({//背景设置必须是placement为point的形式
color: "#36a3ff"
}),
padding: [5, 5, 5, 5]
})
})
);
this.rangeSource.addFeature(polygon);
this.rangeSource.addFeature(point);
this.map.addLayer(this.rangeLayer);
},
async goSearch() {
if (!this.input) {
this.$parent.getClassify()
this.$parent.getTableList()
if (this.circleLayer) {
this.map.removeLayer(this.circleLayer)
}
return
}
const url = "search_all";
const param = {
"org_id": localStorage.getItem("agencyId") || "",
"name": this.input
}
const { data, code, msg } = await requestPostBi(
url,
{
queryParam: param
}
);
if (code == 0) {
if (data.length == 0) {
this.$message({
message: '未搜索到数据',
type: 'warning'
});
return
}
this.loadCircleLayer(data[0])
}
},
loadCircleLayer(data) {
if (!Number(data.longitude) || !Number(data.latitude)) {
this.$message({
message: '缺失坐标!',
type: 'warning'
});
return
}
if (this.circleLayer) {
this.map.removeLayer(this.circleLayer)
}
this.circleSource = new VectorSource();
//矢量标注图层
this.circleLayer = new VectorLayer({
source: this.circleSource
});
let center = [Number(data.longitude), Number(data.latitude)]
this.$parent.getTableList(center)
this.$parent.getClassify(center)
const view = this.map.getView()
const resolutionAtEquator = view.getResolution()
const pointResolution = getPointResolution('EPSG:4326', resolutionAtEquator, center, METERS_PER_UNIT.m)
const resolutionFactor = resolutionAtEquator / pointResolution
let radius = (100 / METERS_PER_UNIT.m) * resolutionFactor
let circle = new Circle(center, radius);// 新建圆对象
let newFeature = new Feature(circle);// 新建Feature对象 并将circle传入
newFeature.setStyle(
new Style({
//填充色
fill: new Fill({
color: 'rgba(127, 131, 247, 0.5)',
}),
})
);
this.map.addLayer(this.circleLayer);
this.circleSource.addFeature(newFeature);
view.animate(
{ zoom: 16, duration: 1000 },
{ center: center, duration: 1000 });
},
getPointsCenter(points) {
points.forEach((f, i, arr) => {
arr[i] = f.join(",")
})
let point_num = points.length; //坐标点个数
let X = 0, Y = 0, Z = 0;
for (let i = 0; i < points.length; i++) {
if (points[i] == '') {
continue;
}
let point = points[i].split(',');
let lat, lng, x, y, z;
lat = parseFloat(point[1]) * Math.PI / 180;
lng = parseFloat(point[0]) * Math.PI / 180;
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 / point_num;
Y = Y / point_num;
Z = Z / point_num;
let tmp_lng = Math.atan2(Y, X);
let tmp_lat = Math.atan2(Z, Math.sqrt(X * X + Y * Y));
return [tmp_lng * 180 / Math.PI, tmp_lat * 180 / Math.PI];
}
}
}
</script>
<style scoped lang="scss">
#map {
position: relative;
#popup {
background-color: #0e2849;
color: #fff;
padding: 16px;
border-radius: 8px;
font-size: 18px;
.moreInfo {
margin: 12px 0;
padding: 4px;
background-color: #fff;
color: #000;
border-radius: 2px;
width: 80px;
cursor: pointer;
}
}
#popup-title {
color: #4090db;
margin-bottom: 12px;
}
.search {
position: absolute;
left: 50px;
top: 50px;
z-index: 99;
}
::v-deep {
.el-input-group__append {
background-color: #0e2849;
}
.el-input--medium {
font-size: 22px;
}
.el-input--medium .el-input__inner {
height: 45px;
line-height: 45px;
}
}
}
</style>