openlayers是一个开源免费的js库,用于在网页中实现地图的动态显示和交互
- api整理 https://segmentfault.com/a/1190000020297846
- 常用api
- feature.getProperties()获取marker私有属性数据
初始化地图
- 首先,引用ol.css和ol.js,因为我们已经下载了ol库,所以使用ol的本地路径就行了,如果网络方便,可以直接在从ol网站获取。
1
2
3<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/css/ol.css" type="text/css">
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.4.3/build/ol.js"></script>
<script src="decision/static/js/jquery.min.js"></script>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25// 底图 高德地图 ol.layer.Tile 提供被切分为切片的图片地图数据
var gaodeMapLayer = new ol.layer.Tile({
source: new ol.source.XYZ({
url: 'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}'
})
});
this.map = new ol.Map({
target: "map",
//图层 可以添加多个地图地图
layers: [gaodeMapLayer],
controls:[scaleLineControl],//也可以this.map.addControl
view: new ol.View({
center: [117.814635,36.402033],
projection: 'EPSG:4326',
zoom: 8,//地图缩放级别
minZoom:5,
maxZoom:12
})
});
// 实例化比例尺控件
var scaleLineControl = new ol.control.ScaleLine({
// 设置比例尺单位为degrees、imperial、us、nautical或metric(度量单位)
units: "metric"
});
this.map.addControl(scaleLineControl); - 这段代码的作用是在网页是显示一个地图;
- 和leaflet一样,地图必须显示在一个div中,因此首先创建一个div;
- target:’map’ 指定了地图要显示在id为map的div中;
- new ol.layer.Tile({ source: new ol.source.OSM() }) 定义了一个图层,数据来源是OpenStreetMap提供的切片数据;
- new ol.View({ center: ol.proj.fromLonLat([37.41, 8.82]), zoom: 4 }) 定义了地图的中心位置,范围和层级。
- ol.proj.fromLonLat([37.41, 8.82]) 是将一个经纬度坐标转换成当前地图投影的坐标;
openlayers自定义图层
- 所有的数据都是不同的图层 可定义多个多层
1
2
3
4
5
6
7
8
9//矢量标注的数据源 this.nodeSource.addFeature 添加标点 var nodeLayer 只是在地图上添加该图层
this.nodeSource = new ol.source.Vector({
features: []
});
// 矢量标注图层 也可以nodeLayer.addFeatures
var nodeLayer = new ol.layer.Vector({
source: this.nodeSource,
});
this.map.addLayer(nodeLayer);获取自定义图层中的所有数据
- this.nodeSource.getFeatureById(id) 获取指定id的图层
1
2
3
4
5
6
7var allNodeMarker = this.nodeSource.getFeatures();
//获取图层对应自定义名称的features删除掉
for (let i = 0; i < allStartMarker.length-1; i++) {
if(allNodeMarker[i].values_.layerType == markerLayerName){
this.nodeSource.removeFeature(allStartMarker[i]);
}
}创建图标
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30createNodeMarker(item, txt){
var newFeature = new ol.Feature({
geometry: new ol.geom.Point([item.longitude, item.latitude]), //几何信息
data: item,
type: 'event',//设置键值对的集合私有属性 setProperties设置也可以
layerType:'自定义私有属性' //
imgurl:item.img //方便选择操作及其余操作的时候还原最初图片状态
});
//设置id 方便this.nodeSource.getFeatureById()找到当前标注及私有属性
newFeature.setId(item.nodeId);
let data = newFeature.values_.data.eventType;
//设置要素样式 坐标图片
newFeature.setStyle(this.createNodeStyle(imgurl));
//nodeSource数据标点图层添加数据
this.nodeSource.addFeature(newFeature);
}
createNodeStyle(imgurl,size='0.5') {
return new ol.style.Style({
image: new ol.style.Icon({
anchor: [0.5, 60], //锚点
anchorOrigin: "top-right", //锚点源
anchorXUnits: "fraction", //锚点X值单位
anchorYUnits: "pixels", //锚点Y值单位
offsetOrigin: "top-right", //偏移原点
opacity: 1,
scale:size,
src: '/images/sign/'+imgurl+'.png'
}),
})
}创建线
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16var lineData = []
// [ [lng,lat],[lng,lat],[lng,lat],[lng,lat],[lng,lat]]
lineData.push(ol.proj.fromLonLat([points[i].longitude,points[i].latitude]));
var lineFeature = new ol.Feature({
geometry: new ol.geom.LineString(lineData),
layerType:type,
});
var lineStyle = new ol.style.Style({
stroke: new ol.style.Stroke({
color: 'red',
width: 2
})
});
lineFeature.setStyle(lineStyle);
this.startAndEndMarker.addFeature(lineFeature);openlayers添加鼠标右键
- openlayers没有右键操作 需要通过jq监听右键来实现效果
- 右键弹出的dom需要display:none否则会出现在地图上 操作的时候dom在显示出来
- 删除右键图层会造成dom丢失所以取消设置定位为null即可 self.menu_overlay.setPosition(null);
1
2
3
4
5
6
7
8
9<div v-show="menuShow" id="contextmenu_container" class="contextmenu">
<ul>
<div @click="creatNode">设置事件发生地点</div>
<li v-for="(item,index) in this.addForm.pathPoints">
<div @click="setStart(index)">设置起点{{index+1}}</div>
<div @click="setEnd(index)">设置终点{{index+1}}</div>
</li>
</ul>
</div>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18addMenu_over(){
var self = this;
this.menuShow = true;
this.menu_overlay= new ol.Overlay({
element: document.getElementById("contextmenu_container"),
positioning: 'right-top'
});
this.map.addOverlay(self.menu_overlay);
$(self.map.getViewport()).unbind('contextmenu').on("contextmenu", function(event){
event.preventDefault();//屏蔽自带的右键事件
var pixel = [event.clientX,event.clientY];
let feature = self.map.forEachFeatureAtPixel(pixel, (feature, layer) => {
return feature;
});
var coordinate = self.map.getEventCoordinate(event.originalEvent);
self.menu_overlay.setPosition(coordinate);
});
},openlayers中overlay 添加覆盖物
- overlay是覆盖物的意思,主要是放置一些和地图位置相关的元素,
- 如:infowindow、点标记、图片等,而这些覆盖物都是和html中的element等价的,
- 通过overlay的属性element和html元素绑定同时设定坐标参数——达到将html元素放到地图上的位置,在平移缩放的时候html元素也会随着地图的移动而移动。
鼠标悬浮添加提示框
1
2
3
4
5
6
7
8
9
10<div id="popup">
<el-popover
placement="top-start"
title="RSU编号"
width="200"
trigger="manual"
v-model="popoverVisible"
:content="currentRsuSnHoverId">
</el-popover>
</div>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32var container = document.getElementById("popup1");
this.overlay1 = new ol.Overlay({
//设置弹出框的容器
element: container,
//是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
autoPan: true,
positioning: "top-center",
offset: [-20, -120]
});
//地图鼠标悬浮创建不同标注弹出层
this.map.on("pointermove", evt => {
//https://www.zybuluo.com/mgsky1/note/1132768#2geteventpixelevent
//e.coordinate是点击的坐标
//1在悬浮地图时触发getEventPixel函数返回区域- //在悬浮地图时获取像素区域
//2调用forEachFeatureAtPixel进行像素区域扫描,如果发现Feature,则激活弹出框。
var pixel = this.map.getEventPixel(evt.originalEvent);
var feature = this.map.forEachFeatureAtPixel(pixel, (feature, layer) => {
return feature
});
if (feature) {
//setProperties 设置键值对集合私有属性 getProperties获取私有键值对
if (feature.getProperties().type === 'rsu') {
this.popoverVisible = true;
this.overlay2.setPosition(feature.getGeometry().flatCoordinates);
//显示overlay
this.map.addOverlay(this.overlay2);
this.currentRsuSnHoverId = feature.getId();
}
} else {
this.popoverVisible = false;
}
});点击某一图层添加覆盖物操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29<div id="popup" class="ol-popup">
<div id="popup-content">
<el-tooltip
content="编辑点"
effect="dark"
placement="bottom"
>
<el-button
icon="el-icon-edit primary"
size="mini"
circle
@click="editPointSerial()"
/>
</el-tooltip>
<el-tooltip
:content="删除点"
effect="dark"
placement="bottom"
>
<el-button
icon="el-icon-delete"
size="mini"
type="danger"
circle
@click="deletePoint()"
/>
</el-tooltip>
</div>
</div>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42this.pointSource = new ol.source.Vector({
features: []
});
var pointLayer = new ol.layer.Vector({
source: this.pointSource
});
this.map.addLayer(pointLayer);
//添加popup覆盖物
var container = document.getElementById("popup");
this.overlay = new ol.Overlay({
//设置弹出框的容器
element: container,
//是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
autoPan: true,
positioning: "top-center",
offset: [0, -48]
});
let pointSelect = new ol.interaction.Select({
//condition: ol.events.condition.pointerMove,
layers: [pointLayer],//选择哪个图层进行操作
style: feature => {//设置选中样式
return this.stylePointSelect(feature);
},
multi: false //multi设置是否可以多选
});
//图层选中的一些操作
pointSelect.on("select", e => {
if (e.selected.length > 0 && this.addPointWay === "") {
var coodinate = e.selected[0].getGeometry().flatCoordinates;
//设置弹出框内容,可以HTML自定义
// content.innerHTML = "<p>aaaaaAA</p>";
//设置overlay的显示位置
this.selectedPointSerial = e.selected[0].values_.id;
this.overlay.setPosition(coodinate);
//显示overlay
this.map.addOverlay(this.overlay);
} else {
this.map.removeOverlay(this.overlay);
}
});
this.map.addInteraction(pointSelect);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29stylePointSelect(feature) {
var fill = new ol.style.Fill({
color: "#EA5504"
});
var stroke = new ol.style.Stroke({
color: "#EA5504",
width: 1
});
return new ol.style.Style({
image: new ol.style.Circle({
fill: fill,
stroke: stroke,
radius: 12
}),
text: new ol.style.Text({
textAlign: "center", //位置
textBaseline: "middle", //基准线
font: "normal 14px 微软雅黑", //文字样式
text: feature.values_.id + "", //文本内容
fill: new ol.style.Fill({
//文本填充样式(即文字颜色)
color: "#DCDFE6"
}),
stroke: new ol.style.Stroke({
color: "#DCDFE6"
})
})
});
},动态切换瓦片地图
1
2
3
4
5
6
7
8
9
10this.picLayer = new ol.layer.Tile({});
this.map = new ol.Map({
target: "map",
layers: [gaodeMapLayer, this.picLayer],
view: new ol.View({
zoom: 14,
minZoom: 10,
maxZoom: 21
})
}); - 通过setSource动态更换地图切片
1
2
3
4
5
6
7
8
9
10this.picLayer.setSource(
new ol.source.TileWMS({
url: mapUrl + this.currentProject.name + "/wms",
params: {
LAYERS: this.currentProject.name, //此处可以是单个图层名称,也可以是图层组名称,或多个图层名称
TILED: true
},
serverType: "geoserver" //服务器类型
})
);只能在切片地图上操作
- 通过Openlayers中getGetFeatureInfoUrl方法请求WMS服务数据到客户端(Browser)(基于Geoserver服务器)
- 在WMS图像图层上单击如何触发WMS的GetFeatureInfo请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37var view = this.map.getView();
var viewResolution = view.getResolution();
var pixel = this.map.getEventPixel(evt.originalEvent);
var url = this.picLayer.getSource().getFeatureInfoUrl(
evt.coordinate,
viewResolution,
view.getProjection(),
{ INFO_FORMAT: "application/json", FEATURE_COUNT: 50 }
);
if (url) {
$.ajax({
url: url,
type: "get",
dataType: "json",
timeout: 6000,
success: data => {
console.log(data.features);
if (data.features.length === 0) {
this.$message.warning("请将Point打在切片地图上" );
return;
}
for (let i = 0; i < data.features.length; i++) {
if (data.features[i].geometry.type == "Point") {
this.nodeSource.getFeatureById(this.currentNodeId).setGeometry(
new ol.geom.Point(data.features[i].geometry.coordinates)
);
let pos = [
parseFloat(data.features[i].geometry.coordinates[0]),
parseFloat(data.features[i].geometry.coordinates[1])
];
pos = ol.proj.transform(pos,"EPSG:3857","EPSG:4326");
this.nodeSource.changed();
}
}
}
})
}自定义控件
1
2
3
4
5
6
7
8var viewport = map.getViewport();
$(viewport).append('<div id="share" class="share">分享地图</div>');
// 监听按钮点击事件,执行相关操作
document.getElementById('share').onclick = function(){
alert('分享当前地图给别人!');
}openlayers不同坐标转换
1
2
3
4
5
6
7
8
9
10
11
12//****************************坐标点转换为大地坐标系*************************
translateInMap(center) {
return ol.proj.fromLonLat(center);
},
//****************************坐标点转换为wgs84******************************
transFormMap(center) {
let pos = [
parseFloat(center[0]),
parseFloat(center[1])
];
return pos = ol.proj.transform(pos, "EPSG:3857", "EPSG:4326");
},地图平移动画
1
2
3
4this.map.getView().animate({
center: this.translateInMap([longitude,latitude]),
duration: 800
});自动打点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41- startPointSerial 起始点号
- autoAddPointSerial 打点数
finishAddPoint() {
if (this.addPointWay === "auto") {
if (this.startPointSerial >= this.pointData.length) {
this.$message.error("起始位置不合法");
return;
} else {
var newLineFeature = new ol.Feature({
geometry: new ol.geom.LineString([
this.pointSource
.getFeatureById(parseInt(this.startPointSerial))
.getGeometry().flatCoordinates,
this.pointSource
.getFeatureById(parseInt(this.startPointSerial) + 1)
.getGeometry().flatCoordinates
])
});
this.linkSource.addFeature(newLineFeature);
let list = [];
for (let i = 0; i < this.autoAddPointSerial; i++) {
let pos = newLineFeature
.getGeometry()
.getCoordinateAt(
(i + 1) / (parseInt(this.autoAddPointSerial) + 1)
);
list.push(this.translatePosition(pos[0], pos[1]));
}
list.unshift(this.startPointSerial, 0);
Array.prototype.splice.apply(this.pointData, list);
this.linkSource.removeFeature(newLineFeature);
}
}
this.updateLanePoints();
this.addPointWay = "";
if (this.linkSource.getFeatureById("newLane")) {
this.linkSource.removeFeature(
this.linkSource.getFeatureById("newLane")
);
}
},