OpenLayers 3 之 使用矢量图层(Vector)

更新 – 2018-05-25

由于openlayers的版本升级迭代,本文程序已经不可运行,最新代码可到这里查看: https://github.com/QingyaFan/openlayers-examples/blob/master/vector.html 。


摘要

        矢量图层:矢量图层是用来渲染矢量数据的图层类型,在OpenLayers里,它是可以定制的,可以控制它的透明度,颜色,以及加载在上面的要素形状等。

        常用于从数据库中请求数据,接受数据,并将接收的数据解析成图层上的信息。如将鼠标移动到中国,相应的区域会以红色高亮显示出来,高亮便是矢量图层的行为。

主要内容

1、 HTML文件的进化

        这次添加矢量图层,如果再独自写一个JS文件,就得在引用一个外部JS文件,如果后续再加一个功能,那么就会越来越多的JS文件,不免造成JS文件之间造成干扰,比如说命名冲突等,所以就直接将功能写在以前的JS文件中(popup.js),并将其更名为“map_utils.js”,意为地图工具集!

        首先我们在HTML中原来存留的JavaScript移动到map_utils.js文件中,因为做到表观层和逻辑层分离,是一个很重要的事情,便于后期的管理。之所以之前没有一步就那么做,是为了让大家意识到 — 过早优化没有必要,怎么实现方便,就先做,避免过度考虑。有一句话说的好:“一个思想过度的人,行动非常软弱!”。

        同时,我们将CSS也分离到一个单独的文件中 – map_style.css,这样,现阶段,就比较容易维护了,别忘了添加引用CSS的语句哦。

        我们并不用对HTML页做其它的修改了,因为矢量图层是一个图层,是从属于Map对象的(注:一个map可以包含很多layer,layer包含底图和一般图层)。

        修改后的HTML页面如下:

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <link rel="stylesheet" href="http://openlayers.org/en/v3.3.0/css/ol.css" type="text/css">
    <link rel="stylesheet" href="map_style.css" type="text/css">
    <title>OpenLayers 3</title>
  </head>
  <body>
    <h2>My Map</h2>
    <div id="map" class="map">
        <div id="popup" class="ol-popup">
            <a href="#" id="popup-closer" class="ol-popup-closer"></a>
            <div id="popup-content" style="width:300px; height:120px;"></div>
        </div>
    </div>
    <script src="http://openlayers.org/en/v3.3.0/build/ol.js" type="text/javascript"></script>
    <script src="map_utils.js" type="text/javascript"></script>
  </body>
</html>

2、 JavaScript文件的修改

        接下来,我们就给我们的“map_utils.js”做点手术。

       首先我们定义需要全局都能访问到的变量:map ,vectorLayer等等:

/**
 * 定义一些全局变量
 */
var map, vectorLayer;
var highlightStyleCache = {}, highlight;
//弹出框需要的部件
var container = document.getElementById('popup');
var content = document.getElementById('popup-content');
var closer = document.getElementById('popup-closer');

     我们原来定义的map,还是可以拿来直接用,但是需要添加一个vector图层,所以这个图层要提前定义,首先我们定义矢量图层的样式,实例化一个style对象:

/**
 * 定义矢量图层
 * 其中style是矢量图层的显示样式 
 */
var style = new ol.style.Style({
  fill: new ol.style.Fill({ //矢量图层填充颜色,以及透明度
    color: 'rgba(255, 255, 255, 0.6)'
  }),
  stroke: new ol.style.Stroke({ //边界样式
    color: '#319FD3',
    width: 1
  }),
  text: new ol.style.Text({ //文本样式
    font: '12px Calibri,sans-serif',
    fill: new ol.style.Fill({
      color: '#000'
    }),
    stroke: new ol.style.Stroke({
      color: '#fff',
      width: 3
    })
  })
});

然后将style用于初始化矢量图层:

vectorLayer = new ol.layer.Vector({ //初始化矢量图层
  source: new ol.source.GeoJSON({
    projection: 'EPSG:3857',
    url: 'data/geojson/countries.geojson'   //从文件加载边界等地理信息
  }),
  style: function(feature, resolution) {
    style.getText().setText(resolution < 5000 ? feature.get('name') : '');  //当放大到1:5000分辨率时,显示国家名字
    return [style];
  }
});

接下来就是实例化map,还是原来的样子,出了layers加了一个适量图层vectorLayer:

map = new ol.Map({  //初始化map
    target: 'map',
    layers: [
      new ol.layer.Tile({
        source: new ol.source.MapQuest({layer: 'sat'})
      }),
      vectorLayer
    ],
    view: new ol.View({
      center: ol.proj.transform([37.41, 8.82], 'EPSG:4326', 'EPSG:3857'),
      zoom: 4
    })
});

接下来,当鼠标在地图上移动时,我们要让矢量图层做出点反应,对,我们就让它高亮吧。

/**
 * 当鼠标移动时,高亮相应的区域的函数
 */
var featureOverlay = new ol.FeatureOverlay({
  map: map,
  style: function(feature, resolution) {
    var text = resolution < 5000 ? feature.get('name') : '';
    if (!highlightStyleCache[text]) {
      highlightStyleCache[text] = [new ol.style.Style({
        stroke: new ol.style.Stroke({
          color: '#f00',
          width: 1
        }),
        fill: new ol.style.Fill({
          color: 'rgba(255,0,0,0.1)'
        }),
        text: new ol.style.Text({
          font: '12px Calibri,sans-serif',
          text: text,
          fill: new ol.style.Fill({
            color: '#000'
          }),
          stroke: new ol.style.Stroke({
            color: '#f00',
            width: 3
          })
        })
      })];
    }
    return highlightStyleCache[text];
  }
});

var displayFeatureInfo = function(pixel) {
  var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
    return feature;
  });

  if (feature !== highlight) {
    if (highlight) {
      featureOverlay.removeFeature(highlight);
    }
    if (feature) {
      featureOverlay.addFeature(feature);
    }
    highlight = feature;
  }

};

以上是当鼠标移动时的反应,我们要将它绑定到地图的鼠标移动事件中:

/**
 * 鼠标移动的事件 
 */
map.on('pointermove', function(evt) {
  if (evt.dragging) {   //如果是拖动地图造成的鼠标移动,则不作处理
    return;
  }
  var pixel = map.getEventPixel(evt.originalEvent);
  displayFeatureInfo(pixel);
});

就是这样的效果:

当点击鼠标的时候,你并不想没有反应吧!?所以我们再添加一个鼠标点击事件,效果是弹出我们上一节引入的弹出框框。

/**
 * 鼠标点击的事件 
 */
map.on('click', function(evt) {
  var pixel = map.getEventPixel(evt.originalEvent);
  var feature = map.forEachFeatureAtPixel(pixel, function(feature, layer) {
    return feature;
  });
  var coordinate = evt.coordinate;
  var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
      coordinate, 'EPSG:3857', 'EPSG:4326'));
  if(feature!==undefined){
      content.innerHTML = '<p>你点击的坐标是:</p><code>' + hdms + '</code><p>这里属于:'+ feature.get('name') + '</p>';
  }
  else{
      content.innerHTML = '<p>你点击的坐标是:</p><code>' + hdms + '</code><p>这里是大海!</p>';
  }
  overlay.setPosition(coordinate);
  map.addOverlay(overlay);
});

/**
 * 隐藏弹出框的函数
 */
closer.onclick = function() {
  overlay.setPosition(undefined);
  closer.blur();
  return false;
};

这样,就搞定了。我们看一下运行效果:

总结

        这次,我们不仅添加了新功能 — 矢量图层,而且整理了HTML、JavaScript和CSS的结构,不过矢量图层的数据是来自本地文件的,这种情况在真正的应用中很少见,一般都是直接来自后端数据库的,而且对于网络地图这种需要传输大量数据的应用来说,减少重新加载的机会和选用一种轻量的传输格式至关重要!

        这是下一次我们将要涉及的内容,服务器与客户端的通信手段:AJAX通信,以及传输数据格式:GeoJSON格式!

转载自:https://blog.csdn.net/qingyafan/article/details/44676665

You may also like...