本地图的加载类包含矢量底图切换、图上量算、经纬度显示、以及图层控制、流动线等

html代码:
<template>
<div id="ol_map">
</div>
</template>
<script>
import xyMap from '@/map/init'
export default {
data() {
return {
mapInstance: null,
};
},
components:{
},
mounted() {
this.initMap();
},
methods: {
initMap() {
this.mapInstance = new xyMap({
targetEle: 'ol_map',
center: [104.043622,30.672401],
zoom: 17,
minZoom: 1,
maxZoom: 18,
toolBar: true,
layerControl: true,
vueEle: this,
});
var data = [
{
id: '12311231',
pipeCoordinatePoints: '[[104.043847,30.67543],[104.044188,30.675453],[104.044242,30.675748],[104.045113,30.675585],[104.045113,30.675585],[104.047979,30.675243],[104.047979,30.675243]]',
}
]
this.mapInstance.renderPipeLine(data);
},
},
beforeUnmount() {
if (this.mapInstance && this.mapInstance.mapObj) {
this.mapInstance.mapObj.setTarget(undefined);
}
}
};
</script>
<style>
</style>
直接附上js源码
import 'ol/ol.css';
import Map from 'ol/Map';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import XYZ from 'ol/source/XYZ';
import Overlay from 'ol/Overlay';
import Feature from 'ol/Feature';
import { unByKey } from 'ol/Observable';
import { transform } from 'ol/proj';
import { createStringXY } from 'ol/coordinate';
import { altKeyOnly, click, pointerMove } from 'ol/events/condition.js';
import VectorSource from 'ol/source/Vector';
import { getArea, getLength } from 'ol/sphere';
import { LineString, Point, Polygon } from 'ol/geom';
import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
import { Circle as CircleStyle, Fill, Icon, Stroke, Style } from 'ol/style';
import { Draw } from 'ol/interaction';
import { fromLonLat } from 'ol/proj';
import Select from 'ol/interaction/Select.js';
import {
ScaleLine,
MousePosition,
Attribution,
OverviewMap,
defaults as defaultControls,
} from 'ol/control';
import xymap from '@/utils/mapUtil';
export default class map {
constructor({ targetEle, center, zoom, minZoom, maxZoom, toolBar, layerControl, vueEle }) {
this.customLayersArr = [];
this.index = 0;
this.zoom = zoom;
this.toolBar = toolBar;
this.layerControl = layerControl;
this.position = null;
this.draw = null;
this.mapObj = null;
this.markerLayer = null;
this.pipelineLayer = null;
this.infoWindows = [];
this.helpTooltip = null;
this.moveMarker = null;
this.vector = null;
this.source = null;
this.points = null;
this.sketch = null;
this.center = center;
this.measureTooltip = null;
this.animating = false;
this.lineString = null;
this.minZoom = minZoom;
this.maxZoom = maxZoom;
this.targetEle = targetEle;
this.measureTooltipElement = null;
this.helpTooltipElement = null;
this.isMeasuring = false;
this.select = null;
this.vueEle = vueEle;
this.init();
}
init() {
this.createMapInstance();
this.createLayers();
this.showPopup();
this.initHight();
if (this.toolBar) {
this.loadToolbar();
}
if (this.layerControl) {
this.loadLayerControl();
}
this.searchMap();
}
selectStyle(feature) {
const selected = new Style({
fill: new Fill({
color: 'rgba(245, 108, 108, 1)',
}),
stroke: new Stroke({
color: 'rgba(227, 53, 19, 0.9)',
width: 4,
}),
});
const color = feature.get('COLOR') || '#eeeeee';
selected.getFill().setColor(color);
return selected;
}
initHight() {
const _this = this;
this.highlightLayer = null;
this.select = new Select({
condition: click,
layers: [this.markerLayer, this.pipelineLayer],
style: null,
hitTolerance: 10,
filter: feature => {
const params = feature.get('params');
return params && Object.keys(params).length > 0;
},
});
this.mapObj.addInteraction(this.select);
this.select.on('select', e => {
if (e.selected.length > 0) {
const feature = e.selected[0];
if (feature.get('layerType') == 'marker_layer') {
var state = feature.values_?.params?.状态 == '报警' ? true : false;
this.focusFeature(e, state);
} else {
this.focusLine(e);
}
}
});
}
focusFeature(feature, state) {
const targetFeature = feature.selected ? feature.selected[0] : feature;
if (!targetFeature) return;
if (this.highlightLayer) {
this.highlightLayer.getSource().clear();
this.mapObj.removeLayer(this.highlightLayer);
}
this.highlightLayer = new VectorLayer({
source: new VectorSource(),
zIndex: 10,
isHightLayer: true,
updateWhileInteracting: false,
renderMode: 'vector',
style: new Style({
image: new Icon({
src: '/assets/images/focus.png',
scale: 0.9,
}),
}),
});
this.mapObj.addLayer(this.highlightLayer);
const highlight = new Feature({
geometry: targetFeature.getGeometry().clone(),
});
this.highlightLayer.getSource().addFeature(highlight);
}
focusLine(feature) {
if (this.highlightLayer) {
this.highlightLayer.getSource().clear();
this.mapObj.removeLayer(this.highlightLayer);
}
this.highlightLayer = new VectorLayer({
source: new VectorSource(),
isHightLayer: true,
updateWhileInteracting: false,
renderMode: 'vector',
zIndex: 10,
});
this.mapObj.addLayer(this.highlightLayer);
const lineStyle = new Style({
stroke: new Stroke({
color: '#F5F5DC',
width: 16,
lineDash: [5, 5],
}),
});
const fea = feature.selected[0];
const coor = JSON.parse(fea.values_.coordinates);
const transformedCoords = coor.map(coord => fromLonLat(coord));
const pipeLine = new LineString(transformedCoords);
const pipeFeature = new Feature(pipeLine);
pipeFeature.setStyle(lineStyle);
this.highlightLayer.getSource().addFeature(pipeFeature);
}
createMapInstance() {
const positionElement = document.createElement('div');
positionElement.className = 'mouse-position';
document.getElementById(this.targetEle).appendChild(positionElement);
this.mapObj = new Map({
target: this.targetEle,
layers: [],
view: this.getView(),
controls: defaultControls({
attribution: true,
}).extend([
new Attribution(),
new ScaleLine({
units: 'metric',
}),
new MousePosition({
target: positionElement,
projection: 'EPSG:4326',
coordinateFormat: createStringXY(4),
className: 'custom-mouse-position',
undefinedHTML: ' ',
}),
]),
});
}
showPopup() {
var _this = this;
const container = document.createElement('div');
container.id = 'popup';
container.className = 'ol-popup';
const closer = document.createElement('a');
closer.id = 'popup-closer';
closer.className = 'ol-popup-closer';
container.appendChild(closer);
const content = document.createElement('div');
content.id = 'popup-content';
container.appendChild(content);
closer.onclick = () => (container.style.display = 'none');
const popupOverlay = new Overlay({
element: container,
offset: [15, 0],
positioning: 'center-left',
autoPanAnimation: { duration: 250 },
});
this.mapObj.addOverlay(popupOverlay);
this.mapObj.on('singleclick', evt => {
if (this.isMeasuring) return;
content.innerHTML = '';
container.style.display = 'none';
const features = this.mapObj.getFeaturesAtPixel(evt.pixel, {
layerFilter: layer => {
return layer instanceof VectorLayer && !layer.get('isHightLayer');
},
hitTolerance: 10,
});
if (features.length > 0) {
const feature = features[0];
if (
feature.getProperties('values').layerType &&
feature.getProperties('values').layerType !== 'pipe_line_layer'
) {
const obj = feature.get('params');
if (obj) {
const contentDiv = document.createElement('div');
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const p = document.createElement('p');
const label = document.createElement('label');
label.textContent = `${key}:`;
const span = document.createElement('span');
span.textContent = obj[key];
if (key === '状态') {
span.style.color =
obj[key] === '在线'
? 'green'
: obj[key] === '离线'
? 'gray'
: obj[key] === '报警'
? 'red'
: '';
span.style.fontWeight = 'bold';
}
p.appendChild(label);
p.appendChild(span);
contentDiv.appendChild(p);
}
}
const historyP = document.createElement('p');
historyP.className = 'history_p';
historyP.textContent = '历史数据⨠';
historyP.onclick = function () {
var id = feature.id_;
_this.vueEle.deviceId = id;
_this.vueEle.getHistoryDec();
};
contentDiv.appendChild(historyP);
content.appendChild(contentDiv);
popupOverlay.setPosition(evt.coordinate);
container.style.display = 'block';
}
} else {
const feature = features[0];
this.vueEle.pipelineId = feature.id_;
this.vueEle.deviceVisible = true;
}
} else {
document.querySelector('.search-result').style.display = 'none';
if (this.highlightLayer) {
this.highlightLayer.getSource().clear();
}
}
});
}
getView() {
let view = new View({
center: transform(this.center, 'EPSG:4326', 'EPSG:3857'),
zoom: this.zoom,
minZoom: this.minZoom,
maxZoom: this.maxZoom,
});
return view;
}
createLayers() {
this.createBaseLayers();
this.createOverlayLayers();
this.customLayersArr.forEach(item => {
this.mapObj.addLayer(item.layer);
});
}
createBaseLayers() {
this.markerLayer = new VectorLayer({
source: new VectorSource({ features: [] }),
visible: true,
zIndex: 110,
});
this.pipelineLayer = new VectorLayer({
source: new VectorSource(),
zIndex: 100,
});
}
createOverlayLayers() {
this.customLayersArr = [
this.createTianDiTuLayer('tianditu_img', '影像地图', 'img_w'),
this.createTianDiTuLayer('tianditu_cia', '影像注记', 'cia_w'),
{
id: 'pipe_line_layer',
mapType: 'pipe_line_layer',
redress: '0',
showText: '管线',
layer: this.pipelineLayer,
},
];
}
createTianDiTuLayer(mapType, showText, layerType) {
return {
id: mapType,
mapType,
redress: '0',
showText,
layer: this.setTianDiTuSource(
`https://t0.tianditu.gov.cn/DataServer?T=${layerType}_w&x={x}&y={y}&l={z}&tk=3c147dbe940e0c4464f2b582bd92fde0`,
true
),
};
}
setTianDiTuSource(url, visible) {
const subDomains = ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'];
return new TileLayer({
visible,
zIndex: 1,
source: new XYZ({
url: url,
tileUrlFunction: tileCoord => {
const z = tileCoord[0];
const x = tileCoord[1];
const y = -tileCoord[2] - 1;
const subDomain = subDomains[(x + y) % subDomains.length];
return url
.replace('{subDomain}', subDomain)
.replace('{col}', x)
.replace('{row}', y)
.replace('{level}', z)
},
crossOrigin: 'anonymous',
}),
});
}
createPolygonMap() {
if (!this.source) {
this.source = new VectorSource({ wrapX: false });
this.vector = new VectorLayer({
source: this.source,
zIndex: 100,
style: new Style({
fill: new Fill({ color: 'rgba(255, 0, 0, 0.2)' }),
stroke: new Stroke({ color: 'red', width: 2 }),
}),
});
this.mapObj.addLayer(this.vector);
}
this.addInteraction('Polygon');
}
addInteraction(drawType) {
if (this.draw) {
this.mapObj.removeInteraction(this.draw);
this.draw = null;
}
this.measureTooltips = this.measureTooltips || [];
this.currentListeners = this.currentListeners || [];
this.draw = new Draw({
source: this.source,
type: drawType,
style: new Style({
fill: new Fill({ color: 'rgba(255, 204, 51, 0.2)' }),
stroke: new Stroke({
color: 'rgba(255, 204, 51)',
width: 2,
lineDash: [10, 10],
}),
image: new CircleStyle({
radius: 5,
stroke: new Stroke({ color: 'rgba(0, 0, 0, 0.7)', lineDash: [10, 10] }),
fill: new Fill({ color: 'rgba(255, 255, 255, 0.2)' }),
}),
}),
condition: event => {
return !event.originalEvent.ctrlKey && !event.originalEvent.shiftKey;
},
});
this.mapObj.addInteraction(this.draw);
this.draw.on('drawstart', evt => {
this.sketch = evt.feature;
const tooltipElement = document.createElement('div');
tooltipElement.className = 'ol-tooltip ol-tooltip-measure';
tooltipElement.style.whiteSpace = 'nowrap';
tooltipElement.style.padding = '4px';
const tooltip = new Overlay({
element: tooltipElement,
offset: [0, -15],
positioning: 'bottom-center',
stopEvent: false,
});
this.mapObj.addOverlay(tooltip);
this.measureTooltips.push(tooltip);
const listener = this.sketch.getGeometry().on('change', evt => {
const geom = evt.target;
let output, coord;
if (geom instanceof Polygon) {
output = this.formatArea(geom);
coord = geom.getInteriorPoint().getCoordinates();
} else if (geom instanceof LineString) {
output = this.formatLength(geom);
coord = geom.getLastCoordinate();
}
tooltipElement.innerHTML = output;
tooltip.setPosition(coord);
});
this.currentListeners.push({
feature: this.sketch,
listener: listener,
});
});
this.draw.on('drawend', evt => {
const feature = evt.feature;
const lastTooltip = this.measureTooltips[this.measureTooltips.length - 1];
if (lastTooltip) {
lastTooltip.getElement().className = 'ol-tooltip ol-tooltip-static';
lastTooltip.setOffset([-10, -10]);
}
feature.setStyle(
new Style({
fill: new Fill({ color: 'rgba(255, 204, 51, 0.2)' }),
stroke: new Stroke({
color: 'rgba(255, 204, 51)',
width: 2,
lineDash: [10, 10],
}),
})
);
this.sketch = null;
});
this.mapObj.on('pointermove', this.pointerMoveHandler);
this.mapObj.on('pointerout', this.mouseoutHandler);
}
pointerMoveHandler = evt => {
if (evt.dragging || !this.helpTooltip) return;
let helpMsg = '单击开始绘制';
if (this.sketch) {
const geom = this.sketch.getGeometry();
if (geom instanceof Polygon) {
helpMsg = '点击继续绘制多边形';
} else if (geom instanceof LineString) {
helpMsg = '点击继续绘制线条';
}
}
this.helpTooltipElement.innerHTML = helpMsg;
this.helpTooltip.setPosition(evt.coordinate);
this.helpTooltipElement.classList.remove('hidden');
};
clearAllMeasurements() {
if (this.draw) {
this.mapObj.removeInteraction(this.draw);
this.draw = null;
}
this.currentListeners.forEach(item => {
unByKey(item.listener);
});
this.currentListeners = [];
this.measureTooltips.forEach(tooltip => {
this.mapObj.removeOverlay(tooltip);
});
this.measureTooltips = [];
if (this.helpTooltip) {
this.helpTooltipElement.classList.add('hidden');
}
if (this.source) {
this.source.clear();
}
this.isMeasuring = false;
this.sketch = null;
this.mapObj.on('singleclick', evt => {
if (this.isMeasuring) return;
const content = document.getElementById('popup-content');
content.innerHTML = '';
const features = this.mapObj.getFeaturesAtPixel(evt.pixel);
if (features.length > 0) {
const feature = features[0];
const obj = feature.getProperties('values').params;
const contentDiv = document.createElement('div');
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
const p = document.createElement('p');
const label = document.createElement('label');
label.textContent = `${key}:`;
const span = document.createElement('span');
span.textContent = obj[key];
p.appendChild(label);
p.appendChild(span);
contentDiv.appendChild(p);
}
}
content.appendChild(contentDiv);
this.mapObj.getOverlayById('popup').setPosition(evt.coordinate);
document.getElementById('popup').style.display = 'block';
} else {
document.getElementById('popup').style.display = 'none';
}
});
}
mouseoutHandler() {
this.helpTooltipElement.classList.add('hidden');
}
drawPolygon(drawType) {
this.isMeasuring = true;
if (!this.source) {
this.createPolygonMap();
}
if (this.draw) {
this.mapObj.removeInteraction(this.draw);
}
this.addInteraction(drawType || 'LineString');
}
formatArea(polygon) {
let area = getArea(polygon);
let output = '';
output = Math.round(area * 100) / 100 + ' ' + 'm<sup>2</sup>';
return output;
}
formatLength(line) {
let length = getLength(line, { projection: 'EPSG:3857' });
let output = '';
output = Math.round(length * 100) / 100 + ' m';
return output;
}
createPopupMap() {
this.init();
this.markerLayer = new VectorLayer({
source: new VectorSource({
features: [],
}),
});
this.mapObj.addLayer(this.markerLayer);
this.markerLayer.setVisible(true);
}
getPoint(point) {
return new Point(point).transform('EPSG:4326', 'EPSG:3857');
}
createMarker(id, point, url, info) {
const marker = new Feature({
geometry: this.getPoint(point),
});
const canvas = document.createElement('canvas');
const size = 30;
canvas.width = size;
canvas.height = size;
const context = canvas.getContext('2d');
gifler(url)
.frames(canvas, (ctx, frame) => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.beginPath();
ctx.arc(size / 2, size / 2, size / 2, 0, Math.PI * 2, true);
ctx.clip();
ctx.drawImage(frame.buffer, 0, 0, size, size);
ctx.restore();
marker.setStyle(
new Style({
image: new Icon({
img: canvas,
imgSize: [canvas.width, canvas.height],
scale: 1,
}),
})
);
})
.catch(err => {
marker.setStyle(
new Style({
image: new Icon({
src: url,
scale: 1,
}),
})
);
});
marker.setId(id);
marker.set('layerType', 'marker_layer');
marker.set('params', info);
this.markerLayer.getSource().addFeature(marker);
return marker;
}
renderPipeLine(item) {
if (!item || !item.length) return;
this.pipelineLayer.getSource().clear();
const arrowAnimations = [];
item.forEach((item, index) => {
if (item.pipeCoordinatePoints) {
const poiArr = JSON.parse(item.pipeCoordinatePoints);
var transformedPipeCoords = poiArr.map(coord => fromLonLat(coord));
const pipeLine = new LineString(transformedPipeCoords);
const pipeFeature = new Feature(pipeLine);
pipeFeature.setId(`${item.id}`);
pipeFeature.set('params', { 管线名称: '测试管线', 状态: '在用', 管线编号: 'S6802' });
pipeFeature.set('layerType', 'pipe_line_layer');
pipeFeature.set('coordinates', item.pipeCoordinatePoints);
const lineStyle = new Style({
stroke: new Stroke({
color: '#FFA500',
width: 8,
}),
});
pipeFeature.setStyle(lineStyle);
this.pipelineLayer.getSource().addFeature(pipeFeature);
const numberOfArrows = 5;
const distanceBetweenArrows = 1 / (numberOfArrows + 1);
for (let i = 0; i < numberOfArrows; i++) {
const progress = (i + 1) * distanceBetweenArrows;
const arrowFeature = new Feature({
geometry: new Point(pipeLine.getCoordinateAt(progress)),
});
arrowAnimations.push({
pipeLine: pipeLine,
arrowFeature: arrowFeature,
progress: progress,
speed: 0.0004,
});
this.pipelineLayer.getSource().addFeature(arrowFeature);
}
}
});
if (arrowAnimations.length === 0) return;
arrowAnimations.forEach(animation => {
const segments = [];
animation.pipeLine.forEachSegment((start, end) => {
const dx = end[0] - start[0];
const dy = end[1] - start[1];
segments.push({
start: start,
end: end,
rotation: Math.atan2(dy, dx),
});
});
animation.segments = segments;
});
const animateArrows = () => {
arrowAnimations.forEach(animation => {
animation.progress += animation.speed;
if (animation.progress >= 1) {
animation.progress = 0;
}
const currentCoord = animation.pipeLine.getCoordinateAt(animation.progress);
animation.arrowFeature.getGeometry().setCoordinates(currentCoord);
let arrowRotation = 0;
for (const segment of animation.segments) {
if (isPointOnSegment(currentCoord, segment.start, segment.end)) {
arrowRotation = segment.rotation;
break;
}
}
animation.arrowFeature.setStyle(
new Style({
image: new Icon({
src: '/assets/images/arrow.png',
anchor: [0.45, 0.5],
scale: 0.8,
rotateWithView: true,
rotation: -arrowRotation,
}),
})
);
});
requestAnimationFrame(animateArrows);
};
animateArrows();
function isPointOnSegment(point, segmentStart, segmentEnd, tolerance = 0.1) {
const crossProduct =
(point[1] - segmentStart[1]) * (segmentEnd[0] - segmentStart[0]) -
(point[0] - segmentStart[0]) * (segmentEnd[1] - segmentStart[1]);
if (Math.abs(crossProduct) > tolerance) return false;
const dotProduct =
(point[0] - segmentStart[0]) * (segmentEnd[0] - segmentStart[0]) +
(point[1] - segmentStart[1]) * (segmentEnd[1] - segmentStart[1]);
if (dotProduct < 0) return false;
const squaredLength =
Math.pow(segmentEnd[0] - segmentStart[0], 2) + Math.pow(segmentEnd[1] - segmentStart[1], 2);
return dotProduct <= squaredLength;
}
}
removeAllMarker() {
this.markerLayer.getSource().clear();
}
loadToolbar() {
var _this = this;
var container = document.createElement('div');
container.id = 'ol-toolbar';
container.className = 'ol-toolbar';
document.getElementById(this.targetEle).appendChild(container);
var panel = document.createElement('div');
panel.className = 'ol-toolbar-panel';
container.appendChild(panel);
var switcher = document.createElement('div');
switcher.className = 'ol-toolbar-switch';
switcher.title = '工具栏';
switcher.innerHTML = '<i></i>';
container.appendChild(switcher);
switcher.addEventListener('click', function (e) {
if (panel.style.display == 'block') {
panel.style.display = 'none';
xymap.util.addClass(switcher, 'active');
} else {
panel.style.display = 'block';
xymap.util.removeClass(switcher, 'active');
}
});
var measure = document.createElement('div');
measure.className = 'toolbar-item toolbar-measure';
var measure_switcher = document.createElement('a');
measure_switcher.innerHTML =
'<span class="item-icon icon-tool"></span><span class="item-text">测量</span><em class="icon-switch"></em>';
measure.appendChild(measure_switcher);
panel.appendChild(measure);
var measure_ul = document.createElement('ul');
measure_ul.className = 'measure-panel';
measure_ul.style.display = 'none';
var distance = document.createElement('li');
distance.innerHTML =
'<span class="item-icon icon-distance"></span><span class="item-text">距离</span>';
measure_ul.appendChild(distance);
var area = document.createElement('li');
area.innerHTML = '<span class="item-icon icon-area"></span><span class="item-text">面积</span>';
measure_ul.appendChild(area);
var clear = document.createElement('li');
clear.innerHTML =
'<span class="item-icon icon-clear"></span><span class="item-text">清空</span>';
measure_ul.appendChild(clear);
measure.appendChild(measure_ul);
measure_switcher.addEventListener('click', function (e) {
if (measure_ul.style.display == 'block') {
measure_ul.style.display = 'none';
xymap.util.removeClass(measure_switcher, 'active');
} else {
measure_ul.style.display = 'block';
xymap.util.addClass(measure_switcher, 'active');
}
});
distance.addEventListener('click', function (e) {
measure_ul.style.display = 'none';
xymap.util.removeClass(measure_switcher, 'active');
_this.drawPolygon('LineString');
});
area.addEventListener('click', function (e) {
measure_ul.style.display = 'none';
xymap.util.removeClass(measure_switcher, 'active');
_this.drawPolygon('Polygon');
});
clear.addEventListener('click', function (e) {
measure_ul.style.display = 'none';
xymap.util.removeClass(measure_switcher, 'active');
if (_this.source) {
_this.source.clear();
_this.clearAllMeasurements();
}
if (_this.draw) {
_this.mapObj.removeInteraction(_this.draw);
_this.draw = null;
_this.isMeasuring = false;
}
});
var view = document.createElement('div');
view.className = 'toolbar-item toolbar-xyz';
var view_switcher = document.createElement('a');
var switcher_icon = document.createElement('span');
switcher_icon.className = 'item-icon icon-map-road';
view_switcher.appendChild(switcher_icon);
var switcher_text = document.createElement('span');
switcher_text.className = 'item-text';
switcher_text.innerHTML = '影像';
view_switcher.appendChild(switcher_text);
view.appendChild(view_switcher);
panel.appendChild(view);
view_switcher.addEventListener('click', function (e) {
var text = switcher_text.innerHTML;
if (text == '影像') {
xymap.util.removeClass(switcher_icon, 'icon-map-road');
xymap.util.addClass(switcher_icon, 'icon-map-img');
switcher_text.innerHTML = '地图';
_this.switchToVectorMap();
} else {
xymap.util.removeClass(switcher_icon, 'icon-map-img');
xymap.util.addClass(switcher_icon, 'icon-map-road');
switcher_text.innerHTML = '影像';
_this.switchToImageMap();
}
if (_this.layerControl) {
_this.updateLayerControl();
}
});
}
updateLayerControl() {
const layerControl = document.getElementById('ol-layer-container');
if (layerControl) {
layerControl.remove();
}
this.loadLayerControl();
}
switchToImageMap() {
this.removeLayers(['tianditu_vec', 'tianditu_cva']);
const imgLayer = this.createTianDiTuLayer('tianditu_img', '影像地图', 'img_w');
const ciaLayer = this.createTianDiTuLayer('tianditu_cia', '影像注记', 'cia_w');
this.mapObj.addLayer(imgLayer.layer);
this.mapObj.addLayer(ciaLayer.layer);
this.customLayersArr.push(imgLayer, ciaLayer);
this.updateLayerControl();
}
switchToVectorMap() {
this.removeLayers(['tianditu_img', 'tianditu_cia']);
const vecLayer = this.createTianDiTuLayer('tianditu_vec', '矢量地图', 'vec_w');
const cvaLayer = this.createTianDiTuLayer('tianditu_cva', '矢量注记', 'cva_w');
this.mapObj.addLayer(vecLayer.layer);
this.mapObj.addLayer(cvaLayer.layer);
this.customLayersArr.push(vecLayer, cvaLayer);
this.updateLayerControl();
}
removeLayers(layerTypes) {
layerTypes.forEach(type => {
const layerObj = this.customLayersArr.find(layer => layer.mapType === type);
if (layerObj) {
this.mapObj.removeLayer(layerObj.layer);
const index = this.customLayersArr.indexOf(layerObj);
if (index > -1) {
this.customLayersArr.splice(index, 1);
}
}
});
}
toggleLayerVisibility(layerId, visible) {
const layer = this.customLayersArr.find(item => item.mapType === layerId);
if (layer) {
layer.layer.setVisible(visible);
}
}
loadLayerControl(params = {}) {
if (params == false) {
return;
}
params = params || {};
if (params.visible == false) {
const layerControl = document.getElementById('ol-layer-container');
if (layerControl) {
layerControl.remove();
}
return;
}
const container = document.createElement('div');
container.id = 'ol-layer-container';
container.className = 'ol-layer-container';
document.getElementById(this.targetEle).appendChild(container);
const switcher = document.createElement('div');
switcher.className = 'ol-layer-switch';
switcher.title = '图层控制';
switcher.innerHTML = '<i></i>';
container.appendChild(switcher);
const panel = document.createElement('div');
panel.className = 'ol-layer-panel';
panel.style.display = 'none';
container.appendChild(panel);
switcher.addEventListener('click', function (e) {
if (panel.style.display == 'block') {
panel.style.display = 'none';
switcher.classList.remove('active');
} else {
panel.style.display = 'block';
switcher.classList.add('active');
}
});
this.customLayersArr.sort((a, b) => {
const zIndexA = a.layer.getZIndex() || 0;
const zIndexB = b.layer.getZIndex() || 0;
return zIndexA - zIndexB;
});
this.addLayerControl();
}
addLayerControl(layerIds = []) {
const panel = document.querySelector('.ol-layer-panel');
if (!panel) return;
panel.innerHTML = '';
if (layerIds.length === 0) {
layerIds = this.customLayersArr.map(layer => layer.mapType);
}
this.customLayersArr
.slice()
.reverse()
.forEach(item => {
if (layerIds.includes(item.mapType)) {
const layerItem = document.createElement('div');
layerItem.className = 'ol-layer-item';
const layerName = document.createElement('span');
layerName.className = 'layer-item-name';
layerName.textContent = item.showText;
const checkbox = document.createElement('span');
checkbox.className = item.layer.getVisible() ? 'check' : 'uncheck';
checkbox.dataset.layer = item.mapType;
layerItem.appendChild(layerName);
layerItem.appendChild(checkbox);
panel.appendChild(layerItem);
checkbox.addEventListener('click', e => {
const statusDom = e.target;
const layerId = statusDom.dataset.layer;
const layer = this.customLayersArr.find(l => l.mapType === layerId)?.layer;
if (layer) {
if (statusDom.classList.contains('check')) {
statusDom.classList.remove('check');
statusDom.classList.add('uncheck');
layer.setVisible(false);
} else {
statusDom.classList.remove('uncheck');
statusDom.classList.add('check');
layer.setVisible(true);
}
}
});
}
});
}
loadingSpinner = function () {
var spinner = document.createElement('div'),
container1 = document.createElement('div'),
container2 = document.createElement('div'),
container3 = document.createElement('div'),
circle11 = document.createElement('div'),
circle12 = document.createElement('div'),
circle13 = document.createElement('div'),
circle14 = document.createElement('div'),
circle21 = document.createElement('div'),
circle22 = document.createElement('div'),
circle23 = document.createElement('div'),
circle24 = document.createElement('div'),
circle31 = document.createElement('div'),
circle32 = document.createElement('div'),
circle33 = document.createElement('div'),
circle34 = document.createElement('div');
spinner.classList.add('xy-spinner');
container1.classList.add('spinner-container');
container1.classList.add('container1');
container2.classList.add('spinner-container');
container2.classList.add('container2');
container3.classList.add('spinner-container');
container3.classList.add('container3');
circle11.classList.add('circle1');
circle12.classList.add('circle2');
circle13.classList.add('circle3');
circle14.classList.add('circle4');
circle21.classList.add('circle1');
circle22.classList.add('circle2');
circle23.classList.add('circle3');
circle24.classList.add('circle4');
circle31.classList.add('circle1');
circle32.classList.add('circle2');
circle33.classList.add('circle3');
circle34.classList.add('circle4');
container1.appendChild(circle11);
container1.appendChild(circle12);
container1.appendChild(circle13);
container1.appendChild(circle14);
container2.appendChild(circle21);
container2.appendChild(circle22);
container2.appendChild(circle23);
container2.appendChild(circle24);
container3.appendChild(circle31);
container3.appendChild(circle32);
container3.appendChild(circle33);
container3.appendChild(circle34);
spinner.appendChild(container1);
spinner.appendChild(container2);
spinner.appendChild(container3);
return spinner;
};
searchMap() {
var _this = this;
var container = document.createElement('div'),
searchResult = document.createElement('div'),
spinner = _this.loadingSpinner(),
searchUl,
emptyDiv = document.createElement('div'),
layuiInputBlock = document.createElement('div'),
layerInput = document.createElement('input'),
layerIcon = document.createElement('i'),
searchButton = document.createElement('div');
searchButton.className = 'searchBtn';
searchButton.innerHTML = '查询';
container.id = 'search-contain';
container.className = 'search-contain';
searchResult.classList.add('search-result');
emptyDiv.classList.add('empty');
emptyDiv.innerHTML = '无查询数据';
layuiInputBlock.classList.add('layui-input-block');
layerInput.classList.add('layui-input');
layerInput.setAttribute('type', 'text');
layerInput.setAttribute('name', 'search');
layerInput.setAttribute('autocomplete', 'off');
layerInput.setAttribute('placeholder', ' 搜索');
layuiInputBlock.appendChild(layerInput);
layuiInputBlock.appendChild(layerIcon);
searchResult.appendChild(emptyDiv);
searchResult.appendChild(spinner);
container.appendChild(layuiInputBlock);
container.appendChild(searchButton);
container.appendChild(searchResult);
searchButton.onclick = function (e) {
var value = layerInput.value;
searchResult.style.display = 'block';
emptyDiv.style.display = 'none';
searchUl = document.createElement('ul');
searchUl.classList.add('search-ul');
};
document.getElementById(this.targetEle).appendChild(container);
}
setCenter(lon, lat) {
this.mapObj.getView().animate({
center: transform([lon, lat], 'EPSG:4326', 'EPSG:3857'),
zoom: 17,
duration: 1000,
});
}
}
css
#ol_map {
position: relative;
width: 98.8%;
height: 99%;
}
.ol-tooltip {
position: absolute;
left: 50px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 4px;
border-radius: 4px;
font-size: 12px;
}
.ol-tooltip-measure {
opacity: 1;
font-weight: bold;
}
.ol-toolbar {
display: flex;
z-index: 10;
position: absolute;
top: 10px;
right:35px;
height: 34px;
background: #fff;
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
}
.ol-toolbar-switch {
height: 16px;
padding: 9px 12px;
}
.ol-toolbar-switch i {
background: url(/assets/images/icon.png);
background-position: -312px -264px;
width: 12px;
height: 16px;
display: inline-block;
transform: rotate(-0deg);
-ms-transform: rotate(-0deg);
-moz-transform: rotate(-0deg);
-webkit-transform: rotate(-0deg);
-o-transform: rotate(-0deg);
-webkit-transition: .3s;
transition: .3s;
}
.ol-toolbar-switch.active i {
transform: rotate(180deg);
-ms-transform: rotate(180deg);
-moz-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
-o-transform: rotate(180deg);
}
.toolbar-item {
position: relative;
float: left;
cursor: pointer;
padding: 0 15px;
}
.toolbar-item .item-icon {
display: inline-block;
background-image: url(/assets/images/icon.png);
background-repeat: no-repeat;
width: 16px;
height: 16px;
float: left;
margin-right: 6px;
margin-top: 9px;
}
.toolbar-item .item-text {
float: left;
font-size: 12px;
font-style: normal;
color: #333;
height: 34px;
line-height: 34px;
display: inline-block;
}
.toolbar-item > .active .item-text {
color: #2f87eb;
}
.toolbar-item .item-icon.icon-tool {
background-position: -84px 0;
}
.toolbar-item > .active .icon-tool {
background-position: -187px 0;
}
.toolbar-item .icon-switch {
width: 11px;
height: 6px;
background-image: url(/assets/images/icon.png);
background-repeat: no-repeat;
background-position: -339px -222px;
-webkit-transition: .3s;
transition: .3s;
margin-left: 5px;
float: left;
margin-top: 13px;
}
.toolbar-item > .active .icon-switch {
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
}
.toolbar-item ul.measure-panel {
position: absolute;
width: 65px;
background: #fff;
top: 19px;
left: 0px;
list-style: none;
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
padding: 0;
}
.toolbar-item ul li {
height: 34px;
line-height: 34px;
padding: 0 7px 0 8px;
}
.toolbar-item ul li:not(:last-child) {
border-bottom: 1px solid #ddd;
}
.toolbar-item .item-icon.icon-distance {
background-position: -295px 0;
}
.toolbar-item .item-icon.icon-area {
background-position: -324px 0;
}
.toolbar-item .item-icon.icon-clear {
background-position: -138px 0;
}
.toolbar-item li:hover .item-text {
color: #2f87eb;
}
.toolbar-item li:hover .icon-distance {
background-position: -434px 0;
}
.toolbar-item li:hover .icon-area {
background-position: -463px 0;
}
.toolbar-item li:hover .icon-clear {
background-position: -241px 0;
}
.toolbar-item .item-icon.icon-map-img {
background-position: -558px -218px;
}
.toolbar-item .item-icon.icon-map-road {
background-position: -582px -218px;
}
.ol-layer-container {
position: absolute;
left: 25px;
bottom: 40px;
background: #fff;
box-shadow: 3px 3px 6px rgb(0 0 0 / 30%);
z-index: 9;
}
.ol-layer-container .ol-layer-switch {
position: relative;
z-index: 8;
box-shadow: 0 0 0 0 #fff;
cursor: pointer;
height: 26px;
}
.ol-layer-container .ol-layer-switch i {
background: url(/assets/images/icon.png);
background-position: -49px -265px;
width: 16px;
height: 16px;
display: inline-block;
margin: 5px;
}
.ol-layer-container > .active i {
background-position: -49px -288px;
}
.ol-layer-panel {
position: absolute;
width: 200px;
z-index: 9;
left: 32px;
bottom: 0;
background: #fff;
border-radius: 3px;
font-size: 13px;
box-shadow: 1px 2px 1px rgb(0 0 0 / 15%);
}
.ol-layer-panel .ol-layer-item {
height: 36px;
line-height: 36px;
border-top: 1px solid #eee;
display: flex;
align-items: center;
position: relative;
margin: 0 10px;
}
.ol-layer-item:first-child {
border-top: 0px;
margin-top: 10px;
}
.ol-layer-item:last-child {
border-bottom: 0px;
margin-bottom: 10px;
}
.ol-layer-item .layer-item-name {
cursor: pointer;
}
.ol-layer-item .check, .ol-layer-item .uncheck {
float: right;
display: block;
width: 14px;
height: 14px;
cursor: pointer;
position: absolute;
right: 0;
margin-top: 0px;
}
.ol-layer-item .check {
background: url(/assets/images/icon.png) -342px -53px no-repeat;
}
.ol-layer-item .uncheck {
background: url(/assets/images/icon.png) -318px -53px no-repeat;
}
.ol-popup {
position: absolute;
background-color: white;
-webkit-filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
filter: drop-shadow(0 1px 4px rgba(0, 0, 0, 0.2));
padding: 15px;
border-radius: 10px;
border: 1px solid #cccccc;
bottom: 18px;
left: -60px;
min-width: 300px;
}
.ol-popup:after, .ol-popup:before {
top: 100%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
.ol-popup:after {
border-top-color: white;
border-width: 10px;
left: 48px;
margin-left: -10px;
}
.ol-popup:before {
border-top-color: #cccccc;
border-width: 11px;
left: 48px;
margin-left: -11px;
}
.ol-popup-closer {
text-decoration: none;
position: absolute;
top: 2px;
right: 8px;
}
.ol-popup-closer:after {
content: "×";
font-weight: bold;
font-size: 24px;
color: rgb(107, 107, 107);
position: relative;
top: -2px;
}
.ol-popup-more {
text-align: right;
color: #1E9FFF;
cursor: pointer;
}
.ol-popup-road {
color: #1E9FFF;
cursor: pointer;
}
#popup-content{
font-size: 14px;
font-weight: 500;
}
#popup-content div p span{
padding-left: 5px;
}
#popup-content div p{
margin: 5px;
}
.custom-mouse-position{
position: absolute;
bottom: 15px;
left: 45%;
z-index: 999;
background-color: rgba(255, 255, 255, 0.1);
min-width: 180px;
text-align: center;
color: #fff;
border-radius: 10px;
}
#search-contain{
position: absolute;
left: 50px;
top: 10px;
width: 270px;
height: 28px;
z-index: 999;
}
.search-contain .layui-input-block {
margin-top: 5px;
margin-left: 5px;
font-size: 12px;
}
.search-contain .searchBtn{
float: right;
text-align: center;
margin-right: 5px;
height: 26px;
padding: 2px 10px 0 10px;
background:#1E9FFF;
color: #fff;
border-radius: 2px;
line-height: 26px;
cursor: pointer;
font-size: 14px;
}
.search-contain .search-result {
position: relative;
display: none;
width: 300px;
max-height: 300px;
top: 5px;
background-color: rgba(255, 255, 255, 1);
border-radius: 5px;
overflow-y: scroll;
}
.search-contain .search-ul {
padding: 0 0 0 15px;
overflow-y: auto;
overflow-x: hidden;
font-size: 0;
}
.search-ul li{
list-style-type: none;
position: relative;
color: black;
font-size: 13px;
}
.search-ul li::before {
content: '';
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
width: 18px;
height: 18px;
background-image: url('/assets/images/icon_location.png');
background-size: cover;
}
.search-contain .found-contain {
display: block;
height: 35px;
line-height: 35px;
padding-right: 10px;
text-decoration: none;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
cursor: pointer;
}
.search-contain .found-value {
font-style: normal;
color: #666;
position: relative;
z-index: 1;
padding-top: 1px;
padding-left: 20px;
}
.search-contain .found-value.active {
color: #29baf1;
}
.search-contain .found-layer-name {
font-style: normal;
color: #999;
float: right;
margin-right: 10px;
}
.search-contain .empty {
padding: 30px;
text-align: center;
color: #8e8e8e;
}
.search-contain .layui-input {
float: left;
width: 200px;
height: 26px;
background-color: rgba(255, 255, 255, 1);
border: none 0;
padding-left: 5px;
}
.xy-spinner {
position: absolute;
left: 0;
right: 0;
top: 0;
bottom: 0;
margin: auto;
width: 30px;
height: 30px;
}
.xy-spinner .spinner-container {
position: absolute;
width: 100%;
height: 100%;
}
.xy-spinner .container2 {
-webkit-transform: rotateZ(45deg);
transform: rotateZ(45deg);
}
.xy-spinner .container3 {
-webkit-transform: rotateZ(90deg);
transform: rotateZ(90deg);
}
.xy-spinner .container1>div,
.xy-spinner .container2>div,
.xy-spinner .container3>div {
width: 6px;
height: 6px;
background-color: #49a9ee;
border-radius: 100%;
position: absolute;
-webkit-animation: bouncedelay 1.2s infinite ease-in-out;
animation: bouncedelay 1.2s infinite ease-in-out;
-webkit-animation-fill-mode: both;
animation-fill-mode: both;
}
.xy-spinner .circle1 {
top: 0;
left: 0;
}
.xy-spinner .circle2 {
top: 0;
right: 0;
}
.xy-spinner .circle3 {
right: 0;
bottom: 0;
}
.xy-spinner .circle4 {
left: 0;
bottom: 0;
}
.xy-spinner .container2 .circle1 {
-webkit-animation-delay: -1.1s;
animation-delay: -1.1s;
}
.xy-spinner .container3 .circle1 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
.xy-spinner .container1 .circle2 {
-webkit-animation-delay: -0.9s;
animation-delay: -0.9s;
}
.xy-spinner .container2 .circle2 {
-webkit-animation-delay: -0.8s;
animation-delay: -0.8s;
}
.xy-spinner .container3 .circle2 {
-webkit-animation-delay: -0.7s;
animation-delay: -0.7s;
}
.xy-spinner .container1 .circle3 {
-webkit-animation-delay: -0.6s;
animation-delay: -0.6s;
}
.xy-spinner .container2 .circle3 {
-webkit-animation-delay: -0.5s;
animation-delay: -0.5s;
}
.xy-spinner .container3 .circle3 {
-webkit-animation-delay: -0.4s;
animation-delay: -0.4s;
}
.xy-spinner .container1 .circle4 {
-webkit-animation-delay: -0.3s;
animation-delay: -0.3s;
}
.xy-spinner .container2 .circle4 {
-webkit-animation-delay: -0.2s;
animation-delay: -0.2s;
}
.xy-spinner .container3 .circle4 {
-webkit-animation-delay: -0.1s;
animation-delay: -0.1s;
}
@keyframes bouncedelay {
0%,
80%,
100% {
transform: scale(0);
-webkit-transform: scale(0);
}
40% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
@-webkit-keyframes bouncedelay {
0%,
80%,
100% {
transform: scale(0);
-webkit-transform: scale(0);
}
40% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
.mapScreen .layer_nav {
background-color: rgba(6, 54, 87, 0.6);
}
.mapScreen .esri-widget--button {
background-color: rgba(6, 54, 87, 0.6);
color: rgba(255, 255, 255, 1);
}
.mapScreen .xyol_layer_ctrl_layers {
background-color: rgba(6, 54, 87, 0.6);
}
.mapScreen .xyol_layer_ctrl_layers .xyol_layer_ctrl_layer {
background-color: transparent;
color: rgb(255, 255, 255);
}
.mapScreen .xyol_sublayer_ul .xyol_sublayer_li {
background-color: transparent;
}
.mapScreen .xyol_layer_ctrl_layer {
border-bottom: 1px solid rgba(215, 216, 216, 0.1);
}
.mapScreen .xyol_layer_ctrl_layers .xyol_layer_ctrl_layer:first-child {
border-top: 0px;
}
.mapScreen .xyol_layer_ctrl_layers .xyol_layer_ctrl_layer:last-child {
border-bottom: 0px;
}
.mapScreen .xyol_sublayer_li .check,
.mapScreen .xyol_layer_ctrl_layer .check {
background: url('/assets/images/icon.png') #235077 -364px -53px no-repeat;
}
.history_p{
float: right;
color: rgb(30, 159, 255);
cursor: pointer;
font-weight: bold;
}