Wechat: yu389741| Email: gisdqy@163.com

Shop:https://www.giserdqy.com/shop

利用OpenLayers3在地图上显示标记并点击标记后显示弹出框



前言

在上一篇《利用全能电子地图下载器+GeoWebCache发布Arcgis Server缓存瓦片过程全记录》中,我们利用GeoWebCache作为瓦片地图服务器发布了瓦片地图。虽然在其中可以直接浏览,但是在GeoWebCache1.10.0中,官方内置的是OpenLayers2的版本,这个版本比较老旧,不能很好的适应诸如触屏设备等应用环境。所以,我想利用OpenLayers2的升级版OpenLayers3来进行地图显示,并增加显示地图标记点击标记后显示弹出框的功能,这两个也是比较常用的。
这篇文章可能会比较,我会对在标题中提到的总目标(在地图上显示标记并点击标记后显示弹出框)进行模块分解,并配上所用的API解析,化整为零嘛~各位也可以各取所需~
模块分解如下:
1、显示瓦片地图
2、在地图上显示标记
3、在点击标记后显示弹出框
Let’s Start~

环境

Part I 显示瓦片地图

效果

思路

GeoWebCache本身就是一个WMS服务,所以只需要利用OpenLayers3与这个WMS服务对接即可。

实现步骤

Step1:建立HTML文件,并引入OpenLayers的相关js与css文件

<link rel="stylesheet" type="text/css" href="../ol.css" />
<script src="../ol.js"></script>
<script src="https://code.jquery.com/jquery-3.3.1.js"></script>

Step2:建立一个div,只需要一个ID属性

<div id="map"></div>

需要记住这个id值,后面的脚本会用到

Step3:获取投影坐标系,建立map对象

   //获取投影坐标系
   var pos = ol.proj.get('EPSG:3857');
    var map = new ol.Map({
        //地图容器div的ID
        target: 'map',
        //地图容器中加载的图层
        layers: [],
        view: new ol.View({
            //设置地图投影坐标系
            projection: pos,
            //设置地图加载时的初始中心点
            center: [13276805.940731, 3008561.497087],
            //缩放级别
            zoom: 19
        }),
    });

相关API:
1、new ol.Map
2、new ol.View
关于View构造参数的说明:
1、center参数的获取方式:
  a、在GeoWebCache中进入地图浏览模式,利用浏览器的开发者工具(这里以Google Chrome为例)打开NetWork选项卡

  b、随机点击Type值为png的连接,在Preview选项卡中,要是有瓦片地图的状态,而不是网格的状态,并记下URL,后续步骤要使用
  这我们想要的效果:

  这不是我们想要的效果:

  c、找到URL中的BBOX参数
  BBOX=13280473.174523,3009173.884415,13281084.670715,3009785.380607
  d、将前两个值,这里是13280473.1745233009173.884415填入center属性即可。
2、zoom参数:为下载瓦片地图时选择的地图级别。
注意二者要对应起来,zoom信息可以在Header(如果是Chrome浏览器的调试窗口)中找到

Step4:建立瓦片地图层

 var mlayer = new ol.layer.Tile({
        source: new ol.source.TileWMS({
            url: 'http://XXX.xxx.com/geowebcache/service/wms',
            params: {
                'LAYERS': 'fzgl',
                'FORMAT': 'image/png',
                'SRS': 'EPSG:3857'
            },
            tileGrid: new ol.tilegrid.TileGrid({
                resolutions: [156543.0339, 78271.51696, 39135.75848, 19567.87924, 9783.939621, 4891.96981, 2445.984905, 1222.992453, 611.496226, 305.748113, 152.874057, 76.437028, 38.218514, 19.109257, 9.554629, 4.777314, 2.388657, 1.194329, 0.597164, 0.298582],
                origin: [-20037508.3427892, 20037508.3430388]
            })
        })
    })

相关API:
1、new ol.layer.Tile
2、new ol.source.TileWMS
3、new ol.tilegrid.TileGrid
关于Tile对象的构造参数的说明:
1、url参数:如果你的Web Server(eg.Tomcat)没有经过特殊配置的话,直接替换XXX.xxx.com为你的地址即可
2、params参数、FORMAT参数、SRS参数,都可以从Step3中记下的URL里的对应参数位置找到
3、resolutions 参数:可以从geowebcache对应的地图预览的网页源代码找到

4、origin 参数:可以从Arcgis瓦片的conf.xml中找到

4、这几个参数是最基本的,如果有缺失或填写错误,地图将无法正常渲染

Step5:将创建好的瓦片地图层添加进Map中

map.addLayer(mlayer)

相关API
1、map.addLayer

Done!
实例演示,点这里

Part II 在地图上显示标记

效果

这里写图片描述

思路

在地图上显示标记,相当于在原来的瓦片地图层上由新叠加了一层,在OpenLayers中称为矢量层。可以把这种叠加的原理理解为PS中的图层,通过各种图层的叠加,达到我们想要的效果。这些地图上的图标,就存在与矢量层上。所以,我们只需要创建矢量层,并添加进map中即可。

实现步骤

Step1:创建空的矢量容器

注:在OpenLayers中,每一个地图上的图标,称做一个Feature,这个矢量容器就是用来装Feature的

var vectorSource = new ol.source.Vector({});

相关API:
1、new ol.source.Vector

Step2:创建Feature,并添加进矢量容器中

        //创建图标特性
        var iconFeature = new ol.Feature({
            geometry: new ol.geom.Point([t1, t2], "XY"),
            name: "my Icon",
        });
        //将图标特性添加进矢量中
        vectorSource.addFeature(iconFeature);

相关API:
1、new ol.Feature
2、new ol.geom.Point
3、vectorSource.addFeature
几点说明:
1、上面代码中的t1、t2即要显示标记的位置,填入你想让标记出现的经纬度即可。

Step3:创建标记的样式

  //创建图标样式
    var iconStyle = new ol.style.Style({
        image: new ol.style.Icon({
            opacity: 0.75,
            src: "http://openlayers.org/en/v3.9.0/examples/data/icon.png"
        }),
    });

相关API:
1、new ol.style.Style
2、new ol.style.Icon

Step4:创建矢量层,并添加进map层

   //创建矢量层
    var vectorLayer = new ol.layer.Vector({
        source: vectorSource,
        style: iconStyle
    });
    //添加进map层
    map.addLayer(vectorLayer);

相关API:
1、new ol.layer.Vector

Done!
示例演示,点这里

Part III 在点击标记后显示弹出框

效果

思路

这个是在这几个案例中最复杂的一个了。
分析:在OpenLayers3中,弹出框是一个Overlay,overlay的中文是覆盖物的意思,弹出框不就是一个覆盖物吗?
这里又牵扯到一个新的知识点,那就是地图的事件监听,在map类中有一个on方法,但这个方法的确能对点击事件进行监听,但是是对整个map的。也就是说,我点击地图上的任何位置,都会触发这个监听事件,效果上并不是我们想要的。我们想要的是在点击标记后才触发监听事件。幸运的是,OpenLayers在map类中为我们提供了一个函数,叫forEachFeatureAtPixe,这个函数的工作原理有点类似物理中的光电门,这个函数会对所给定的像素范围进行扫描,如果发现Feature(标记就是一个Feature),就会触发回掉函数。那么如何给定点击像素呢?OpenLayers又很贴心地给我们准备了getEventPixe函数,这个函数会在事件触发时,返回对应的像素范围。
总结思路: 在点击地图时触发getEventPixel函数返回区域->调用forEachFeatureAtPixel进行像素区域扫描,如果发现Feature,则激活弹出框。

实现步骤

Step1:在HTML中添加一个div,用于显示弹出框

<div id="popup" class="ol-popup">
        <a href="#" id="popup-closer" class="ol-popup-closer"></a>
        <div id="popup-content"></div>
</div>

1、这里所有的id都需要记录
2、这里还需要对弹出框设定样式,例子CSS样式将在文章最后的源码中给出

Step2:在js中获取HTML元素

var container = document.getElementById("popup");
var content = document.getElementById("popup-content");
var popupCloser = document.getElementById("popup-closer");

1、container:最外层包含所有元素的div
2、content:显示弹出框具体内容的div
3、popupCloser:弹出框的关闭按钮,是一个a标签

Step3:创建一个Overlay

 var overlay = new ol.Overlay({
         //设置弹出框的容器
        element: container,
        //是否自动平移,即假如标记在屏幕边缘,弹出时自动平移地图使弹出框完全可见
        autoPan: true
    });

相关API:
1、new ol.Overlay

Step4:在map上绑定点击事件监听

map.on('click',function(e){
        //在点击时获取像素区域
        var pixel = map.getEventPixel(e.originalEvent);
        map.forEachFeatureAtPixel(pixel,function(feature){
            //coodinate存放了点击时的坐标信息
            var coodinate = e.coordinate;
            //设置弹出框内容,可以HTML自定义
            content.innerHTML = "<p>你点击的坐标为:" + coodinate + "</p>";
            //设置overlay的显示位置
            overlay.setPosition(coodinate);
            //显示overlay
            map.addOverlay(overlay);
        });
    });

相关API:
1、map.on
2、map.getEventPixel
3、map.forEachFeatureAtPixel
4、overlay.setPosition
5、map.addOverlay

Done! 至此,在地图上点击标记时,就会有弹出框显示了~
示例演示,点这里

演示与示例代码合集

GitHub
演示合集

本文用到的API合集

Openlayer3.13.1的几个API的部分翻译

参考资料

1、Openlayers3 加载Geowebcache 发布的 ArcGIS 切片地图
2、Openlayer 3 的点击弹出框

写在最后

由于OpenLayers3几乎没有中文的API,于是乎就去翻译了,翻译了两天,部分语句采用了Google Translate的翻译结果。如果出现错误可以在评论区反馈~多谢谅解~~其实翻译一遍在结合代码理解会更清晰一些~

转载自:https://blog.csdn.net/mgsky1/article/details/80191401