OpenLayers之多源数据加载七:矢量地图

一、矢量地图介绍

    矢量地图的图形的元素是一些点、线、矩形、多边形、圆和弧线等等,它们都是通过数学公式计算获得的。由于矢量图形可通过公式计算获得,所以矢量图形文件体积一般较小。

    矢量图形最大的优点是无论放大、缩小或旋转等图形都不会失真。矢量地图在地图项目中存在着大量的应用,是地图数据中非常重要的组成部分。

    为了便于存储、传递、使用,矢量地图会按照一定的格式来表达,比如常见的GeoJSON、TopoJSON、GML、KML、shapefile等等。除了最后一个shapefile,其他几个格式的矢量地图OpenLayers都支持,使用起来也非常的简单,下面这个地图就加载了GeoJson格式的矢量地图。

    代码非常简单:

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

    <script>
        //创建地图
        var map = new ol.Map({
            layers: [
                //底图用Open Street Map地图
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
                //再加载一个geojson的矢量地图
                new ol.layer.Vector({
                    source: new ol.source.Vector({
                        url: 'data/geojson/line-samples.geojson',     // 矢量地图来源
                        format: new ol.format.GeoJSON()                  //解析矢量地图的格式化类
                    })
                })
            ],
            view: new ol.View({
                center: [-72.980624870461128, 48.161307640513321],
                zoom: 8,
                projection: 'EPSG:4326'
            }),
            target: 'map'
        });
    </script>

    注释对代码进行了很好的说明,但有两点需要进一步说明:

        加载矢量图使用的source是ol.source.Vector,layer是ol.layer.Vector,不要错误的使用。

        加载代码之所以这么简单,是因为OpenLayer内置了对应矢量地图格式的解析类,比如ol.format.GeoJSON。它们都位于包ol.format下面,可以在API官方文档中查询得到。如果是shapefile这种不支持的,则需要自己解析。解析后,矢量地图都会转换为对应于OpenLayers中的Feature。所以,当加载完成后,可以通过source的getFeatures()方法来获取所有的矢量图形。

        需要注意坐标系,因为.geojson文档里用的是和当前地图用的不一样的坐标系。

    对于不同格式的矢量地图,会有相应的一些不同用法,下面就针对一些大家经常会遇到的问题,给出相应的实例,用以说明。

二、获取加载后的所有feature

    这是一个很多人会遇到的问题,因为在加载矢量地图后,需要对矢量地图做一些简单的查询,分析等。但是经常会遇到获取不到加载后的feature的问题。原因就在于获取的时机不对,因为矢量地图是异步加载的。

    下面就看一下正确的获取所有feature的做法是什么:

    从图上可以看到,共有9个feature,在地图下方的统计数据也是9。下面看看代码是如何实现的:

<div id="map" style="width: 100%"></div>
<div>矢量地图Feature总数: <span id="count"></span></div>
<script type="text/javascript">

    //创建地图
    var map = new ol.Map({
        layers: [
            new ol.layer.Tile({
                source: new ol.source.OSM()
            })
        ],
        view: new ol.View({ 
            center: [-72.980624870461128, 48.161307640513321],
            zoom: 8,
            projection: 'EPSG:4326'
        }),
        target: 'map'
    });

    var vectorLayer = new ol.layer.Vector({
        source: new ol.source.Vector({
            url: '../data/geojson/line-samples.geojson', 
            format: new ol.format.GeoJSON()
        })
    });

    // 因为是异步加载,所以要采用事件监听的方式来判定是否加载完成
    var listenerKey = vectorLayer.getSource().on('change', function(){
        if (vectorLayer.getSource().getState() === 'ready') {    // 判定是否加载完成
            document.getElementById('count').innerHTML = vectorLayer.getSource().getFeatures().length;
            vectorLayer.getSource().unByKey(listenerKey); // 注销监听器
        }
    });

    map.addLayer(vectorLayer);
    // 如果在此处调用vectorLayer.getSource().getFeatures()是完全有可能获取不到任何Feature的,这是常犯错误
</script>

    对于其他格式的矢量地图加载也需要这样编写代码,才能正确获取到加载完成的所有feature。

三、坐标转换

    坐标转换也是矢量地图经常会遇到的问题,比如当前地图用的是EPSG:3857,但是矢量地图用的是EPSG:4326,这样就需要进行坐标转换。由于OpenLayers为我们内置了地图格式解析器,那么自然只能依靠它来处理。

    上一节中使用的.geojson文件内的坐标使用是wgs84坐标,那么如果我们地图使用EPSG:3857,该怎么来加载?

    详细实现参见代码:

<div id="map" style="width: 100%"></div>
<script type="text/javascript">

    //创建地图
    var map = new ol.Map({
        layers: [
            new ol.layer.Tile({
                source: new ol.source.OSM()
            }),

        ],
        view: new ol.View({ 
            center: ol.proj.fromLonLat([-72.980624870461128, 48.161307640513321]),
            zoom: 8
        }), 
        target: 'map'
    });

    // 加载矢量地图
    function addGeoJSON(src) {
        var layer = new ol.layer.Vector({
            source: new ol.source.Vector({
                features: (new ol.format.GeoJSON()).readFeatures(src, {     // 用readFeatures方法可以自定义坐标系
                    dataProjection: 'EPSG:4326',    // 设定JSON数据使用的坐标系
                    featureProjection: 'EPSG:3857' // 设定当前地图使用的feature的坐标系
                })
            })
        });
        map.addLayer(layer);
    }

    // 使用ajax获取矢量地图数据
    $.ajax({
        url: '../data/geojson/line-samples.geojson',
        success: function(data, status) {
            // 成功获取到数据内容后,调用方法添加到地图
            addGeoJSON(data);
        }
    });
</script>

    代码稍微麻烦了一点,是因为目前ol.format.GeoJSON的构造参数不支持设定创建feature的坐标系(openlayers5已经支持),如果要支持也并不麻烦,期望后续官网能够改进。

    注意,该方法可以适用于其他几种矢量地图。readFeatures()这个方法在内置的几个解析类中都有。

四、样式设置

    对矢量元素进行样式设置,OpenLayers支持两种方式,一种是直接给feature设置样式,一种是给layer设置样式。系统默认优先考虑feature的样式,如果没有,则使用layer的样式,还有一种情况是layer也没有设置样式,则会采用系统默认的样式。

    对于矢量地图而言,要想修改样式也只有这两种途径可选。比如之前例子中使用GeoJSON,如果要改变线条的颜色成下面这样,可以考虑在layer上设置样式:

    代码很简单:

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

    <script>
        //创建地图
        var map = new ol.Map({
            layers: [
                //底图用Open Street Map地图
                new ol.layer.Tile({
                    source: new ol.source.OSM()
                }),
            ],
            view: new ol.View({
                center: ol.proj.fromLonLat([-72.980624870461128, 48.161307640513321]),
                zoom: 8,
            }),
            target: 'map'
        });
        
        var vectorLayer = new ol.layer.Vector({
            source: new ol.source.Vector({
                url: "http://localhost:8080/openLayers/data/geojson/line-samples.geojson",
                format: new ol.format.GeoJSON({
                    dataProjection: 'EPSG:4326',
                    featureProjection: 'EPSG:3857'
                })
            }),
            //设置样式,颜色为红色,线条粗细为1个像素
            style: new ol.style.Style({
                stroke: new ol.style.Stroke({
                    color: 'black',
                    width: 1
                })
            })
        });

        map.addLayer(vectorLayer);
    </script>

    如果要在feature上设置样式,就必须先获取到所有加载的feature,然后依次设置,显然直接设置layer的样式,会在代码编写上更容易一些。

    自带样式的矢量地图修改样式

    有些矢量地图数据自带样式,比如KML格式的矢量地图,如果要修改样式,则相对比较麻烦。得分情况考虑:

        一种是所有矢量地图都不使用自带的样式:

        一种是部分矢量地图不使用自带的样式。

    对于第一种情况,则相对比较简单一点,只需要把ol.format.KML的构造参数extractStyles设置为false即可,然后为layer设定自定义的样式。

    对于第二种情况,则相对麻烦一些,必须要读取加载的所有feature,并进行过滤,对符合条件的feature重新设置样式。

转载自:https://blog.csdn.net/qq_35732147/article/details/81391738

You may also like...