|
@@ -18,16 +18,14 @@ import WMTSCapabilities from 'ol/format/WMTSCapabilities';
|
|
|
import { Fill, Stroke } from 'ol/style';
|
|
|
import proj4 from 'proj4';
|
|
|
import { register } from 'ol/proj/proj4';
|
|
|
-import { defaults } from 'ol/control';
|
|
|
+import { defaults, ScaleLine } from 'ol/control';
|
|
|
import Vector from 'ol/layer/Vector';
|
|
|
import SourceVector from 'ol/source/Vector';
|
|
|
import GeoJSON from 'ol/format/GeoJSON';
|
|
|
-import { fromLonLat } from 'ol/proj';
|
|
|
import axios from 'axios';
|
|
|
import { fromExtent } from 'ol/geom/Polygon';
|
|
|
import { LinearRing, LineString, Polygon } from 'ol/geom';
|
|
|
import { Graticule } from 'ol/layer';
|
|
|
-import { getPointsCenter, mergeGeoJsonPolygons } from '@/utils/gisUtils';
|
|
|
import { Cluster } from 'ol/source';
|
|
|
import CircleStyle from 'ol/style/Circle';
|
|
|
import Overlay from 'ol/Overlay';
|
|
@@ -40,6 +38,8 @@ import * as turf from '@turf/turf';
|
|
|
import { nanoid } from 'nanoid';
|
|
|
import carImg from '@/assets/images/car.png';
|
|
|
import { globalHeaders } from '@/utils/request';
|
|
|
+import { iconList } from '@/views/globalMap/data/mapData';
|
|
|
+import gdJson from '@/assets/json/gd.json';
|
|
|
|
|
|
const tk = 'a8df87f1695d224d2679aa805c1268d9';
|
|
|
const commonUrl = import.meta.env.VITE_APP_BASE_API2 + 'api/oneShare/proxyHandler/gd/';
|
|
@@ -79,7 +79,6 @@ export class olMap {
|
|
|
icon: '',
|
|
|
iconName: ''
|
|
|
};
|
|
|
- private plot;
|
|
|
private drawVector;
|
|
|
private drawTool;
|
|
|
private vectorLayer;
|
|
@@ -87,6 +86,7 @@ export class olMap {
|
|
|
private maskLayer;
|
|
|
private maskLayer2;
|
|
|
// 显示信息框
|
|
|
+ private clickMarker;
|
|
|
private infoWindow;
|
|
|
private select;
|
|
|
// 车辆轨迹
|
|
@@ -95,10 +95,14 @@ export class olMap {
|
|
|
private traceFeature;
|
|
|
// 自定义绘制结束调用方法
|
|
|
private drawEndMethod;
|
|
|
- private selectedFeature;
|
|
|
private drawing;
|
|
|
private path;
|
|
|
private anyLine;
|
|
|
+ private scale;
|
|
|
+ // 标绘图层
|
|
|
+ private plotLayers = {};
|
|
|
+ private addressMarker;
|
|
|
+ private addPoints = [];
|
|
|
|
|
|
constructor(options) {
|
|
|
this.options = options;
|
|
@@ -119,7 +123,8 @@ export class olMap {
|
|
|
});
|
|
|
// 初始化比例尺
|
|
|
if (options.showScale) {
|
|
|
- // this.map.addControl(new AMap.Scale());
|
|
|
+ this.scale = new ScaleLine();
|
|
|
+ this.map.addControl(this.scale);
|
|
|
}
|
|
|
if (options.drawTool?.use) {
|
|
|
this.initMouseTool(options.drawTool);
|
|
@@ -144,44 +149,53 @@ export class olMap {
|
|
|
condition: click,
|
|
|
style: null,
|
|
|
filter: (feature, layer) => {
|
|
|
- // 只有vectorLayer图层可选择
|
|
|
- return layer === this.vectorLayer;
|
|
|
+ // 检查当前图层是否在 plotLayers 中
|
|
|
+ return Object.values(this.plotLayers).includes(layer);
|
|
|
}
|
|
|
});
|
|
|
this.map.addInteraction(this.select);
|
|
|
// 监听Select交互的select事件
|
|
|
this.select.on('select', (event) => {
|
|
|
- const selectedFeatures = event.selected[0]; // 获取被选中的要素集合
|
|
|
- const features = selectedFeatures.get('features');
|
|
|
- if (selectedFeatures && !!features) {
|
|
|
- const originalFeature = features[0];
|
|
|
- const size = features.length;
|
|
|
- if (size === 1) {
|
|
|
- if (this.selectedFeature !== originalFeature) {
|
|
|
- if (this.selectedFeature) {
|
|
|
- this.selectedFeature.set('icon', this.selectedFeature.get('image'));
|
|
|
- }
|
|
|
- this.selectedFeature = originalFeature;
|
|
|
- const icon = originalFeature.get('imageHover');
|
|
|
- const extData = originalFeature.get('extData');
|
|
|
- originalFeature.set('icon', icon);
|
|
|
+ const feature = event.selected[0]; // 获取被选中的要素集合
|
|
|
+ const extData = feature.get('extData');
|
|
|
+ if (!!feature) {
|
|
|
+ if (this.clickMarker) {
|
|
|
+ const selectData = this.clickMarker.get('extData');
|
|
|
+ this.clickMarker.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: selectData.image,
|
|
|
+ scale: selectData.scale,
|
|
|
+ anchor: [0.5, 0.5],
|
|
|
+ anchorXUnits: 'fraction',
|
|
|
+ anchorYUnits: 'fraction'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (['1', '2'].includes(extData.type)) {
|
|
|
+ // 多点位 单点
|
|
|
+ if (this.clickMarker !== feature) {
|
|
|
+ this.clickMarker = feature;
|
|
|
+ feature.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: extData.imageHover,
|
|
|
+ scale: extData.scale,
|
|
|
+ anchor: [0.5, 0.5],
|
|
|
+ anchorXUnits: 'fraction',
|
|
|
+ anchorYUnits: 'fraction'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
options.onMarkerClick(extData);
|
|
|
}
|
|
|
- } else {
|
|
|
+ } else if (extData.type === '3') {
|
|
|
// 聚合要素
|
|
|
- this.select.getFeatures().clear();
|
|
|
+ // this.select.getFeatures().clear();
|
|
|
const currentZoom = this.map.getView().getZoom();
|
|
|
this.map.getView().setZoom(currentZoom + 1);
|
|
|
- const points = [];
|
|
|
- features.forEach((feature) => {
|
|
|
- const geometry = feature.getGeometry(); // 获取要素的几何对象
|
|
|
- const type = geometry.getType(); // 获取几何类型
|
|
|
- if (type === 'Point') {
|
|
|
- points.push(geometry.getCoordinates());
|
|
|
- }
|
|
|
- });
|
|
|
- const newFeature = getPointsCenter(points);
|
|
|
- this.map.getView().setCenter(newFeature.geometry.coordinates);
|
|
|
+ this.map.getView().setCenter([Number(extData.longitude), Number(extData.latitude)]);
|
|
|
event.selected = [];
|
|
|
}
|
|
|
}
|
|
@@ -191,7 +205,11 @@ export class olMap {
|
|
|
// 添加新的图层
|
|
|
if (Array.isArray(options.id)) {
|
|
|
for (const layer of options.id) {
|
|
|
- await this.formatXml(layer);
|
|
|
+ if (layer.layerType === 'JSON') {
|
|
|
+ await this.createJsonLayer(layer);
|
|
|
+ } else {
|
|
|
+ await this.formatXml(layer);
|
|
|
+ }
|
|
|
}
|
|
|
} else if (options.id === 'tianditu') {
|
|
|
await this.formatXml2();
|
|
@@ -202,7 +220,8 @@ export class olMap {
|
|
|
this.vectorLayer = new VectorLayer({
|
|
|
source: new VectorSource({
|
|
|
features: []
|
|
|
- })
|
|
|
+ }),
|
|
|
+ zIndex: options.zIndex ? options.zIndex : 100
|
|
|
});
|
|
|
this.map.addLayer(this.vectorLayer);
|
|
|
if (typeof this.options.onLoadCompleted === 'function') {
|
|
@@ -235,28 +254,40 @@ export class olMap {
|
|
|
}
|
|
|
formatXml(options) {
|
|
|
const xml = new WMTSCapabilities();
|
|
|
- return this.getCapabilities(options.code).then((res) => {
|
|
|
- const geoJson = xml.read(res.data);
|
|
|
- const data = geoJson.Contents.Layer[0];
|
|
|
- const layerParam = {
|
|
|
- layerName: data.Abstract,
|
|
|
- styleName: data.Identifier,
|
|
|
- tilematrixset: data.TileMatrixSetLink[0].TileMatrixSet,
|
|
|
- format: data.Format[0]
|
|
|
- };
|
|
|
- this.createWmsLayer(options, layerParam);
|
|
|
+ return this.getCapabilities(options.code, options.layerType).then((res) => {
|
|
|
+ if (options.layerType === 'WMTS') {
|
|
|
+ const geoJson = xml.read(res.data);
|
|
|
+ const data = geoJson.Contents.Layer[0];
|
|
|
+ const layerParam = {
|
|
|
+ layerName: data.Abstract,
|
|
|
+ styleName: data.Identifier,
|
|
|
+ tilematrixset: data.TileMatrixSetLink[0].TileMatrixSet,
|
|
|
+ format: data.Format[0]
|
|
|
+ };
|
|
|
+ this.createWmtsLayer(options, layerParam);
|
|
|
+ } else if (options.layerType === 'WFS') {
|
|
|
+ const parser = new DOMParser();
|
|
|
+ const xmlDoc = parser.parseFromString(res.data, 'text/xml');
|
|
|
+ const featureType = xmlDoc.getElementsByTagName('FeatureType')[0];
|
|
|
+ const layerParam = {
|
|
|
+ layerName: featureType.getElementsByTagName('Title')[0].textContent,
|
|
|
+ typeName: featureType.getElementsByTagName('Name')[0].textContent,
|
|
|
+ srsName: featureType.getElementsByTagName('SRS')[0].textContent
|
|
|
+ };
|
|
|
+ this.createWfsLayer(options, layerParam);
|
|
|
+ }
|
|
|
});
|
|
|
}
|
|
|
|
|
|
// 请求接口获取地图信息
|
|
|
- getCapabilities(code) {
|
|
|
- return axios.get(commonUrl + code + '?SERVICE=WMTS&REQUEST=GetCapabilities', {
|
|
|
+ getCapabilities(code, service) {
|
|
|
+ return axios.get(commonUrl + code + '?SERVICE=' + service + '&REQUEST=GetCapabilities', {
|
|
|
headers: globalHeaders()
|
|
|
});
|
|
|
}
|
|
|
|
|
|
- // 请求地图图片加载图层
|
|
|
- createWmsLayer(options, layerParam) {
|
|
|
+ // 请求WMTS地图图片加载图层
|
|
|
+ createWmtsLayer(options, layerParam) {
|
|
|
const source = new WMTS({
|
|
|
url: commonUrl + options.code,
|
|
|
crossOrigin: 'Anonymous',
|
|
@@ -305,7 +336,50 @@ export class olMap {
|
|
|
layer.set('id', options.code);
|
|
|
this.map.addLayer(layer);
|
|
|
}
|
|
|
+ //
|
|
|
+ createWfsLayer(options, layerParam) {
|
|
|
+ const source = new VectorSource({
|
|
|
+ format: new GeoJSON(),
|
|
|
+ url: `${commonUrl}${options.code}?SERVICE=WFS&VERSION=1.0.0&REQUEST=GetFeature&typeName=流域:GEO_BAS_POLYGON&outputFormat=application/json& srsName=EPSG:4490`
|
|
|
+ });
|
|
|
+
|
|
|
+ const vectorLayer = new VectorLayer({
|
|
|
+ source: source,
|
|
|
+ style: new Style({
|
|
|
+ fill: new Fill({
|
|
|
+ color: 'rgba(255, 255, 255, 0.6)'
|
|
|
+ }),
|
|
|
+ stroke: new Stroke({
|
|
|
+ color: '#319FD3',
|
|
|
+ width: 1
|
|
|
+ })
|
|
|
+ })
|
|
|
+ });
|
|
|
|
|
|
+ this.map.addLayer(vectorLayer);
|
|
|
+ }
|
|
|
+ // 加载json图层
|
|
|
+ createJsonLayer(layer) {
|
|
|
+ return new Promise((resolve, reject) => {
|
|
|
+ const geojsonParser = new GeoJSON();
|
|
|
+ console.log(this.map.getView().getProjection());
|
|
|
+ const features = geojsonParser.readFeatures(gdJson, {
|
|
|
+ dataProjection: 'EPSG:4326',
|
|
|
+ featureProjection: this.map.getView().getProjection()
|
|
|
+ });
|
|
|
+ const jsonLayer = new VectorLayer({
|
|
|
+ source: new VectorSource({ features }),
|
|
|
+ style: new Style({
|
|
|
+ // 必须设置样式才能显示
|
|
|
+ fill: new Fill({ color: '#ffffff' }),
|
|
|
+ stroke: new Stroke({ color: 'rgba(0,0,0, 1)', width: 1 })
|
|
|
+ }),
|
|
|
+ zIndex: layer.zIndex ? layer.zIndex : -99
|
|
|
+ });
|
|
|
+ this.map.addLayer(jsonLayer);
|
|
|
+ resolve({});
|
|
|
+ });
|
|
|
+ }
|
|
|
// 初始化绘画工具
|
|
|
initMouseTool(options) {
|
|
|
this.drawOptions = {
|
|
@@ -659,6 +733,32 @@ export class olMap {
|
|
|
}
|
|
|
return style;
|
|
|
}
|
|
|
+ // 添加搜索的标记的
|
|
|
+ addSearchMarker(item) {
|
|
|
+ const view = this.map.getView();
|
|
|
+ view.setZoom(18);
|
|
|
+ view.setCenter([Number(item.longitude), Number(item.latitude)]);
|
|
|
+ // 获取到上一次的搜索标记并移除
|
|
|
+ const index = this.markers.findIndex((m) => {
|
|
|
+ return m.dataType === 'search';
|
|
|
+ });
|
|
|
+ if (index > -1) {
|
|
|
+ this.markers.splice(index, 1);
|
|
|
+ }
|
|
|
+ if (!this.plotLayers['search']) {
|
|
|
+ this.plotLayers['search'] = new VectorLayer({
|
|
|
+ source: new VectorSource({
|
|
|
+ features: []
|
|
|
+ })
|
|
|
+ });
|
|
|
+ this.map.addLayer(this.plotLayers['search']);
|
|
|
+ } else {
|
|
|
+ this.plotLayers['search'].getSource().clear();
|
|
|
+ }
|
|
|
+ this.addMarker2({ 'search': item });
|
|
|
+ this.clickMarker = item;
|
|
|
+ this.options.onMarkerClick(item);
|
|
|
+ }
|
|
|
addMarker(points) {
|
|
|
this.clearMarker();
|
|
|
const vectorSource = new VectorSource({
|
|
@@ -699,19 +799,161 @@ export class olMap {
|
|
|
this.vectorLayer.setStyle(this.clusterStyle);
|
|
|
this.vectorLayer.setSource(clusterSource);
|
|
|
}
|
|
|
+ addMarker2(obj) {
|
|
|
+ this.clearMarker2('point');
|
|
|
+ if (!!this.plotLayers['point']) {
|
|
|
+ this.markers = [];
|
|
|
+ }
|
|
|
+ let hideInfoFlag = true;
|
|
|
+ Object.keys(obj).forEach((key: string) => {
|
|
|
+ const data = obj[key];
|
|
|
+ const name = key === 'search' ? 'search' : 'point';
|
|
|
+ if (this.clickMarker) {
|
|
|
+ const extData = this.clickMarker.get('extData');
|
|
|
+ if (data.id === extData.id && data.dataType === extData.dataType) {
|
|
|
+ hideInfoFlag = false;
|
|
|
+ data.isHover = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (data.type === '3') {
|
|
|
+ // 聚合点
|
|
|
+ const outerCircle = new CircleStyle({
|
|
|
+ radius: 20,
|
|
|
+ fill: new Fill({
|
|
|
+ color: 'rgba(79, 176, 206, 0.5)'
|
|
|
+ }),
|
|
|
+ stroke: new Stroke({
|
|
|
+ color: 'rgba(79, 176, 206, 1)'
|
|
|
+ })
|
|
|
+ });
|
|
|
+ const feature = new Feature({
|
|
|
+ // 必须是数字类型,字符串不识别
|
|
|
+ geometry: new Point([Number(data.longitude), Number(data.latitude)]),
|
|
|
+ name: data.name,
|
|
|
+ pointer: true,
|
|
|
+ extData: data
|
|
|
+ });
|
|
|
+
|
|
|
+ feature.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: outerCircle,
|
|
|
+ text: new Text({
|
|
|
+ text: data.count.toString(),
|
|
|
+ font: '14px sans-serif',
|
|
|
+ fill: new Fill({
|
|
|
+ color: '#ffff'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ this.plotLayers[name].getSource().addFeature(feature);
|
|
|
+ this.markers.push(data);
|
|
|
+ } else {
|
|
|
+ // 单个点
|
|
|
+ const iconConfig = iconList[data.dataType] || (name === 'search' ? iconList.common2 : iconList.common);
|
|
|
+ data.image = iconConfig.image;
|
|
|
+ data.imageHover = iconConfig.imageHover;
|
|
|
+ data.size = iconConfig.size;
|
|
|
+ if (data.materia_name) {
|
|
|
+ data.name = data.materia_name;
|
|
|
+ }
|
|
|
+ if (data.dataType === 43) {
|
|
|
+ data.showName = true;
|
|
|
+ }
|
|
|
+ if (!data.id) {
|
|
|
+ data.id = nanoid(8);
|
|
|
+ }
|
|
|
+ data.lnglat = [data.longitude, data.latitude];
|
|
|
+ const feature = new Feature({
|
|
|
+ // 必须是数字类型,字符串不识别
|
|
|
+ geometry: new Point([Number(data.longitude), Number(data.latitude)]),
|
|
|
+ name: data.name,
|
|
|
+ pointer: true,
|
|
|
+ extData: data
|
|
|
+ });
|
|
|
+ // 设置自定义属性
|
|
|
+ const img = new Image();
|
|
|
+ img.onload = () => {
|
|
|
+ // 图片加载完成后,可以访问其 width 和 height 属性
|
|
|
+ const scale = data.size[0] ? data.size[0] / img.width : 1;
|
|
|
+ data.scale = scale;
|
|
|
+ feature.set('extData', data);
|
|
|
+ feature.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: data.isHover ? data.imageHover : data.image,
|
|
|
+ scale: scale,
|
|
|
+ anchor: [0.5, 0.5],
|
|
|
+ anchorXUnits: 'fraction',
|
|
|
+ anchorYUnits: 'fraction'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ this.plotLayers[name].getSource().addFeature(feature);
|
|
|
+ if (data.isHover) {
|
|
|
+ this.clickMarker = feature;
|
|
|
+ this.options.onMarkerClick(data);
|
|
|
+ }
|
|
|
+ };
|
|
|
+ img.src = data.image; // 设置图片的 URL,触发加载
|
|
|
+ this.markers.push(data);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if (hideInfoFlag) {
|
|
|
+ this.clickMarker = null;
|
|
|
+ this.hideInfo(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
// 清除所有标加
|
|
|
clearMarker() {
|
|
|
if (!this.vectorLayer) return;
|
|
|
this.vectorLayer.getSource().clear();
|
|
|
}
|
|
|
-
|
|
|
- showInfo(content, position, isCustom) {
|
|
|
+ clearMarker2(name) {
|
|
|
+ // 新增图层
|
|
|
+ if (!this.plotLayers[name]) {
|
|
|
+ this.plotLayers[name] = new VectorLayer({
|
|
|
+ source: new VectorSource({
|
|
|
+ features: []
|
|
|
+ })
|
|
|
+ });
|
|
|
+ this.map.addLayer(this.plotLayers[name]);
|
|
|
+ } else {
|
|
|
+ this.plotLayers[name].getSource().clear();
|
|
|
+ // this.clickMarker = null;
|
|
|
+ // this.hideInfo();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 设置灾害地点 单独图册
|
|
|
+ setAddress(data) {
|
|
|
+ this.clearMarker2('address');
|
|
|
+ this.addressMarker = new Feature({
|
|
|
+ // 必须是数字类型,字符串不识别
|
|
|
+ geometry: new Point([Number(data.longitude), Number(data.latitude)]),
|
|
|
+ name: data.name,
|
|
|
+ pointer: true,
|
|
|
+ extData: data
|
|
|
+ });
|
|
|
+ this.addressMarker.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: data.image,
|
|
|
+ scale: [0.288, 0.288],
|
|
|
+ anchor: [0.5, 0.5],
|
|
|
+ anchorXUnits: 'fraction',
|
|
|
+ anchorYUnits: 'fraction'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ this.plotLayers['address'].getSource().addFeature(this.addressMarker);
|
|
|
+ }
|
|
|
+ showInfo(content, position, offsetY, isCustom) {
|
|
|
this.hideInfo();
|
|
|
if (!this.infoWindow) {
|
|
|
this.infoWindow = new Overlay({
|
|
|
element: content,
|
|
|
positioning: 'bottom-center', // 你可以根据需要调整定位方式
|
|
|
- offset: [0, -10] // 偏移量,用于调整覆盖层相对于要素的位置
|
|
|
+ offset: [0, offsetY ? offsetY : 0] // 偏移量,用于调整覆盖层相对于要素的位置
|
|
|
});
|
|
|
}
|
|
|
this.infoWindow.setPosition(position);
|
|
@@ -722,8 +964,20 @@ export class olMap {
|
|
|
hideInfo(flag?: boolean) {
|
|
|
this.map.removeOverlay(this.infoWindow);
|
|
|
this.infoWindow = null;
|
|
|
- if (!!flag && this.select) {
|
|
|
- this.select.getFeatures().clear();
|
|
|
+ if (!!flag && this.clickMarker) {
|
|
|
+ const selectData = this.clickMarker.get('extData');
|
|
|
+ this.clickMarker.setStyle(
|
|
|
+ new Style({
|
|
|
+ image: new Icon({
|
|
|
+ src: selectData.image,
|
|
|
+ scale: selectData.scale,
|
|
|
+ anchor: [0.5, 0.5],
|
|
|
+ anchorXUnits: 'fraction',
|
|
|
+ anchorYUnits: 'fraction'
|
|
|
+ })
|
|
|
+ })
|
|
|
+ );
|
|
|
+ this.clickMarker = null;
|
|
|
}
|
|
|
}
|
|
|
/**
|
|
@@ -1227,6 +1481,9 @@ export class olMap {
|
|
|
getMap() {
|
|
|
return this.map;
|
|
|
}
|
|
|
+ getScale() {
|
|
|
+ return this.scale;
|
|
|
+ }
|
|
|
getMouseTool() {
|
|
|
return this.drawTool;
|
|
|
}
|