知识点
- 获取地图层级
map.getView().getZoom()。
- 获取地图当前屏幕范围
map.getView().calculateExtent(map.getSize())。
- 地图的双击事件
dblclick。
- 地图移动结束事件
moveend。
- 地图的鼠标移动事件
pointermove。
- 计算两个坐标之间的距离
ol.sphere.getDistance(),单位米,传入的经纬度是WGS84坐标系下的。
- 用户绘制的圆,获取圆的中心坐标
geometry.getCenter()。获取圆的半径geometry.getRadius()。
- 隐藏显示图层
layer.setVisible(true/false)。
- 获取图层隐藏/显示状态
layer.getVisible()。
- 设置图层层级
layer.setZIndex()。
- 获取图层层级
layer.getZIndex()。
- 查看版本号
ol.util.VERSION。
- 获取地图投影方式
map.getView().getProjection().getCode()。
代码HTML+CSS+JS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/ol.min.css" integrity="sha512-bc9nJM5uKHN+wK7rtqMnzlGicwJBWR11SIDFJlYBe5fVOwjHGtXX8KMyYZ4sMgSL0CoUjo4GYgIBucOtqX/RUQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<title>openlayers离散知识点</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--top-height: 50px;
}
html,
body {
height: 100%;
height: 100%;
}
#container {
width: 100%;
height: 100%;
overflow: hidden;
position: absolute;
}
button {
border-radius: 0;
background-color: #07c160;
border: none;
outline: none;
cursor: pointer;
height: 40px;
line-height: 40px;
color: #fff;
padding: 0 20px;
}
select {
height: 40px;
line-height: 40px;
outline: none;
}
.ml10 {
margin-left: 10px;
}
#app {
width: 100vw;
height: 100vh;
display: flex;
}
.info,
.app-map {
height: 100vh;
width: 50vw;
}
.info {
padding: 30px;
}
.info > div {
margin-bottom: 12px;
}
.log {
max-height: 400px;
overflow: auto;
}
.log div {
height: 30px;
line-height: 30px;
}
.distance,
.msg {
height: 40px;
line-height: 40px;
font-size: 16px;
}
.distance label {
width: 50px;
display: inline-block;
}
.distance select {
width: 120px;
margin-right: 12px;
}
</style>
</head>
<body>
<div id="app">
<div class="app-map" id="app-map"></div>
<div class="info">
<div class='msg'>openlayers 版本号: <b>{{version}}</b></div>
<div class='msg'>地图展示层级: <b>{{level}}</b></div>
<div class='msg'>地图投影方式: <b>{{epsg}}</b></div>
<div class="distance">
<label for="start">起点</label>
<select name="start" id="start" v-model='start'>
<option v-for='point in pointData' :key='point.name' :value="point.center.join(',')">{{point.name}}</option>
</select>
<label for="end">终点</label>
<select name="end" id="end" v-model='end'>
<option v-for='point in pointData' :key='point.name' :value="point.center.join(',')">{{point.name}}</option>
</select>
<button @click='handleClickCalcDistance'>计算距离</button>
<span class="ml10"><b>{{distanceText}}</b></span>
</div>
<div>
<button @click='handleClickDrawCircle'>绘制圆</button>
<span class="ml10" v-show='center !== ""'>圆的中心坐标: ({{center}})</span>
<span class="ml10" v-show='radius !== ""'>圆的半径: {{radius}}米</span>
</div>
<div>
<button @click='handleClickTogglePointLayer'>{{this.pointLayerIsVisible ? '隐藏' : '显示'}}点位图层</button>
<span class="ml10">点位图层状态: {{pointLayerIsVisible ? '显示着' : '隐藏着'}}</span>
</div>
<div>
<button @click='handleClickUpZIndex(2)'>提高点位图层层级</button>
<button @click='handleClickUpZIndex(1)' class="ml10">提高多边形图层层级</button>
<span class='index ml10'>点位图层层级:<b>{{pointZIndex}}</b></span>
<span class='index ml10'>多边形图层层级:<b>{{polygonZIndex}}</b></span>
</div>
<div class="log">
<div v-for='(log, index) in logs' :key='log'>{{index + 1}} {{log}}</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/openlayers/8.2.0/dist/ol.min.js" integrity="sha512-+nvfloZUX7awRy1yslYBsicmHKh/qFW5w79+AiGiNcbewg0nBy7AS4G3+aK/Rm+eGPOKlO3tLuVphMxFXeKeOQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.4.14/vue.global.prod.min.js" integrity="sha512-huEQFMCpBzGkSDSPVAeQFMfvWuQJWs09DslYxQ1xHeaCGQlBiky9KKZuXX7zfb0ytmgvfpTIKKAmlCZT94TAlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
const { createApp } = Vue;
const base64Img = 'data:image/png;base64,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';
const baseStyle = new ol.style.Style({
image: new ol.style.Icon({
src: base64Img,
scale: 1.5,
anchor: [0.5, 0.5],
rotateWithView: true,
rotation: 0,
opacity: 1
}),
});
const pointData = [{
name: '北京市',
center: [116.405285, 39.904989]
},
{
name: '天津市',
center: [117.190182, 39.125596]
},
{
name: '河北省',
center: [114.502461, 38.045474]
},
{
name: '山西省',
center: [112.549248, 37.857014]
},
{
name: '内蒙古自治区',
center: [111.670801, 40.818311]
},
{
name: '辽宁省',
center: [123.429096, 41.796767]
},
{
name: '吉林省',
center: [125.3245, 43.886841]
},
{
name: '黑龙江省',
center: [126.642464, 45.756967]
},
{
name: '上海市',
center: [121.472644, 31.231706]
},
{
name: '江苏省',
center: [118.767413, 32.041544]
},
{
name: '浙江省',
center: [120.153576, 30.287459]
},
{
name: '安徽省',
center: [117.283042, 31.86119]
},
{
name: '福建省',
center: [119.306239, 26.075302]
},
{
name: '江西省',
center: [115.892151, 28.676493]
},
{
name: '山东省',
center: [117.000923, 36.675807]
},
{
name: '河南省',
center: [113.665412, 34.757975]
},
{
name: '湖北省',
center: [114.298572, 30.584355]
},
{
name: '湖南省',
center: [112.982279, 28.19409]
},
{
name: '广东省',
center: [113.280637, 23.125178]
},
{
name: '广西壮族自治区',
center: [108.320004, 22.82402]
},
{
name: '海南省',
center: [110.33119, 20.031971]
},
{
name: '重庆市',
center: [106.504962, 29.533155]
},
{
name: '四川省',
center: [104.065735, 30.659462]
},
{
name: '贵州省',
center: [106.713478, 26.578343]
},
{
name: '云南省',
center: [102.712251, 25.040609]
},
{
name: '西藏自治区',
center: [91.132212, 29.660361]
},
{
name: '陕西省',
center: [108.948024, 34.263161]
},
{
name: '甘肃省',
center: [103.823557, 36.058039]
},
{
name: '青海省',
center: [101.778916, 36.623178]
},
{
name: '宁夏回族自治区',
center: [106.278179, 38.46637]
},
{
name: '新疆维吾尔自治区',
center: [87.617733, 43.792818]
},
{
name: '台湾省',
center: [121.509062, 25.044332]
},
{
name: '香港特别行政区',
center: [114.173355, 22.320048]
},
{
name: '澳门特别行政区',
center: [113.54909, 22.198951]
},
]
function transform (e) {
return ol.proj.transform(e, 'EPSG:4326', 'EPSG:3857');
};
const vm = createApp({
data() {
return {
map: {},
polygonLayer: {},
pointLayer: {},
drawSource: {},
center: '',
radius: '',
version: ol.util.VERSION,
epsg: '',
level: 4,
logs: [],
start: pointData[0].center.join(','),
end: pointData[1].center.join(','),
distanceText: '',
pointData,
draw: null,
pointLayerIsVisible: true,
pointZIndex: 2,
polygonZIndex: 2
}
},
methods: {
initMap() {
const vectorLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
}),
name: '初始化地图图层'
});
this.drawSource = new ol.source.Vector();
const drawLayer = new ol.layer.Vector({
source: this.drawSource,
});
this.map = new ol.Map({
target: 'app-map',
layers: [vectorLayer, drawLayer],
view: new ol.View({
projection: 'EPSG:3857',
center: transform([111.8453154, 32.7383500]),
zoom: 4,
})
});
this.bindMapEvt();
this.renderPoint();
this.renderPolygon();
},
bindMapEvt() {
this.map.on('click', (evt) => {
const clickPoint = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
this.logs.push(`触发了点击事件,点击的经纬度是(${clickPoint[0].toFixed(7)}, ${clickPoint[1].toFixed(7)})`);
});
this.map.on('dblclick', (evt) => {
evt.stopPropagation();
const clickPoint = ol.proj.transform(evt.coordinate, 'EPSG:3857', 'EPSG:4326')
this.logs.push(`触发了双击事件,双击的经纬度是(${clickPoint[0].toFixed(7)}, ${clickPoint[1].toFixed(7)})`);
});
this.map.on('pointermove', (e) => {
let pixel = this.map.getEventPixel(e.originalEvent);
let feature = this.map.forEachFeatureAtPixel(pixel, (feature) => {
return feature;
});
if (feature && feature.get('pointer')) {
console.log(`鼠标移动事件,鼠标移动到了点位上`);
this.map.getTargetElement().style.cursor = 'pointer';
} else {
this.map.getTargetElement().style.cursor = 'auto';
}
});
this.map.on('moveend', (e) => {
const nlevel = this.map.getView().getZoom();
if (nlevel === this.level) {
this.logs.push(`移动结束事件,根据层级变化,判断为平移 ${nlevel} -> ${nlevel}`);
} else {
this.logs.push(`移动结束事件,根据层级变化,判断为缩放 ${this.level} -> ${nlevel}`);
this.level = nlevel;
}
});
},
renderPoint(numPoints) {
const vectorSource = new ol.source.Vector({
features: pointData.map(e => {
const feature = new ol.Feature({
geometry: new ol.geom.Point(ol.proj.fromLonLat(e.center)),
pointer: true
});
feature.setStyle(baseStyle);
return feature;
})
});
this.pointLayer = new ol.layer.Vector({
source: vectorSource,
layerID: 'addpointLayer'
});
this.map.addLayer(this.pointLayer);
this.pointLayer.setZIndex(this.pointZIndex);
this.pointLayerIsVisible = this.pointLayer.getVisible();
},
renderPolygon () {
const coordinates = [
[116.405285, 39.904989],
[87.617733, 43.792818],
[91.132212, 29.660361],
[110.33119, 20.031971],
[116.405285, 39.904989]
];
const coordinates3857 = coordinates.map(e => {
return transform(e);
});
const polygonFeature = new ol.Feature({
geometry: new ol.geom.Polygon([coordinates3857]),
});
polygonFeature.setStyle(new ol.style.Style({
fill: new ol.style.Fill({
color: 'rgba(0, 255, 0, 0.8)'
}),
}));
this.polygonLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [polygonFeature]
})
});
this.map.addLayer(this.polygonLayer);
this.polygonLayer.setZIndex(this.polygonZIndex);
},
handleClickCalcDistance () {
const start = (this.start.split(',').map(e => parseFloat(e)));
const end = (this.end.split(',').map(e => parseFloat(e)));
this.distanceText = '距离是: ' + ol.sphere.getDistance(start, end) + '米';
const lineString = new ol.geom.LineString([transform(start), transform(end)]);
const lineFeature = new ol.Feature(lineString);
lineFeature.setStyle(new ol.style.Style({
stroke: new ol.style.Stroke({
color: '#' + Math.random().toString(16).slice(2, 8),
width: 3
})
}));
this.polygonLayer.getSource().addFeature(lineFeature);
},
handleClickDrawCircle () {
const { map } = this;
this.draw && map.removeInteraction(this.draw);
this.draw = new ol.interaction.Draw({
source: this.drawSource,
type: 'Circle'
});
map.addInteraction(this.draw);
this.draw.on('drawend', (event) => {
const feature = event.feature;
const center = ol.proj.transform(feature.getGeometry().getCenter(), 'EPSG:3857', 'EPSG:4326');
const radius = feature.getGeometry().getRadius();
this.logs.push(`绘制的圆形的中心经纬度是:(${center[0]}, ${center[1]})`)
this.logs.push(`绘制的圆形的半径是:${radius},投影方式是 EPSG:3857,返回的单位是米`);
this.center = center.map(e => e.toFixed(6)).join(',')
this.radius = radius.toFixed(6);
this.map.removeInteraction(this.draw);
});
},
handleClickTogglePointLayer () {
this.pointLayer.setVisible(!this.pointLayerIsVisible);
this.pointLayerIsVisible = this.pointLayer.getVisible();
},
handleClickUpZIndex (type) {
const layer = type === 1 ? this.polygonLayer : this.pointLayer;
const text = type === 1 ? '多边形' : '点位';
let index = layer.getZIndex();
layer.setZIndex(index + 1);
type === 1 && (this.polygonZIndex = layer.getZIndex());
type === 2 && (this.pointZIndex = layer.getZIndex());
this.logs.push(text + '图层zindex设置为' + (index + 1));
}
},
mounted() {
this.initMap();
this.epsg = this.map.getView().getProjection().getCode();
}
}).mount('#app')
</script>
</body>
</html>
参考文章
获取图层显示/隐藏状态方法官方文档
设置图层显示/隐藏状态方法官方文档
获取图层zIndex方式方法官方文档
获取投影方式方法官方文档
设置投影方式方法官方文档
计算点位距离方法官方文档