openlayers学习(一)

1,249 阅读7分钟

Openlayers

一、介绍

OpenLayers是一个用于开发WebGIS客户端的JavaScript包。OpenLayers 支持的地图来源包括Google Maps、Yahoo、 Map、微软Virtual Earth 等,用户还可以用简单的图片地图作为背景图,与其他的图层在OpenLayers 中进行叠加,在这一方面OpenLayers提供了非常多的选择。除此之外,OpenLayers实现访问地理空间数据的方法都符合行业标准。OpenLayers 支持Open GIS 协会制定的WMS(Web Mapping Service)和WFS(Web Feature Service)等网络服务规范,可以通过远程服务的方式,将以OGC 服务形式发布的地图数据加载到基于浏览器的OpenLayers 客户端中进行显示。

二、基本概念

基本使用:npm install ol下载,全局使用在main.js中import并use,或者局部使用在需要使用的.vue文件中import后可直接使用

注意:这里需要import的原型比较多,记得仔细检查是否漏引

1.map

OpenLayers 的核心组件是地图 ( ol/Map)。它被渲染到一个target容器(例如div网页上包含地图的元素)。所有地图属性都可以在构建时进行配置,也可以使用 setter 方法进行配置,例如setTarget().

下面的标记可用于创建<div>包含您的地图的标记。

<div id="map" style="width: 100%, height: 400px"></div>

下面的脚本使用元素的 id 作为选择器来构造一个在<div>上面渲染的地图。map

import Map from 'ol/Map';
​
var map = new Map({target: 'map'});

2.view

地图不负责地图的中心、缩放级别和投影等事项。相反,这些是ol/View实例的属性。

import View from 'ol/View';
​
map.setView(new View({
  center: [0, 0],
  zoom: 2
}));

一个View有一个projection投影。投影决定了地图分辨率计算的坐标系center和单位。如果未指定(如上面的代码片段),则默认投影为 Spherical Mercator (EPSG:3857),以米为地图单位。

zoom选项是指定地图分辨率的便捷方式。可用缩放级别由maxZoom(默认值:28)、zoomFactor(默认值:2)和maxResolution(默认值以投影的有效范围适合 256x256 像素图块的方式计算)确定。从缩放级别 0 开始,分辨率为maxResolution每像素单位,后续缩放级别通过将先前缩放级别的分辨率除以 来计算zoomFactor,直到maxZoom达到缩放级别。

3.source

为了获取层的远程数据,OpenLayers 使用ol/source/Source子类。这些可用于 OpenStreetMap 或 Bing 等免费和商业地图切片服务、WMS 或 WMTS 等 OGC 源,以及 GeoJSON 或 KML 等格式的矢量数据。

import OSM from 'ol/source/OSM';
​
var osmSource = OSM();

4.layer

layer是来自source,OpenLayers 有四种基本类型的层:

  • ol/layer/Tile- 渲染在按特定分辨率的缩放级别组织的网格中提供平铺图像的源。(瓦片)
  • ol/layer/Image- 渲染以任意范围和分辨率提供地图图像的源。
  • ol/layer/Vector- 在客户端渲染矢量数据。
  • ol/layer/VectorTile- 渲染作为矢量图块提供的数据。
import TileLayer from 'ol/layer/Tile';
​
var osmLayer = new TileLayer({source: osmSource});
map.addLayer(osmLayer);

5.style

var style = new Style({
    //边框样式
    stroke: new ol.style.Stroke({
        color: 'white',
        width: 2,
    }),
    //填充样式
    fill: new ol.style.Fill({
        color: 'rgba(255, 255, 255, 0.7)',
    }),
    image: new ol.style.Circle({
        radius: 5,
        fill: new ol.style.Fill({
            color: 'white',
        })
    })
})

6.feature

步骤:创建要素实例,设置样式,设置id,向source添加要素feature

组合

上面的代码片段可以组合成一个脚本,用一个瓦片层初始化并且渲染一个地图

import Map from 'ol/Map';
import View from 'ol/View';
import OSM from 'ol/source/OSM';
import TileLayer from 'ol/layer/Tile';
​
new Map({
  layers: [ // 图层数组
    new TileLayer( // 地图图层,比如底图、矢量图等
        {source: new OSM()}
    ) 
  ],
  view: new View({
    // 投影,默认为38
    projection: 'EPSG:4326',
    // 中心坐标
    center: [114.064839, 22.548857],
    // 地图最小缩放比例
    minZoom: 10,
    // 地图最大缩放比例
    maxZoom: 19,
    // 地图缩放级别(打开页面时默认级别)
    zoom: 12
    // 旋转
    rotation: 1,
  }),
  target: 'map' // 指定容器id
});

例子:(高德地图)

//加载高德地图的数据源
var gaodeMapLayer=new ol.layer.Tile({
    title:"高德地图",
    source:new ol.source.XYZ({
        //指定url瓦片
        url:'http://wprd0{1-4}.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
        wrapX:true//x方向平铺,也可以选择false
    })
});
//创建地图容器
var map=new ol.Map({
    layers:[gaodeMapLayer],
    //加载瓦片图层数据
    view:new ol.View({
        //中心点坐标
        center:[12156971,3891618],
        projection:'EPSG:3857',
        zoom:8,
        minZoom:3
    }),
    target:'map'
    //目标加载到map中
})

实现了地图的显示功能之后可以加载常用的控件,比如常用的导航控件,导航条放大缩小等 加载地图导航条:

//加载地图导航条实现放大缩小
var zoomslider=new ol.control.ZoomSlider();
map.addControl(zoomslider);
var zoomToExtent=new ol.control.ZoomToExtent({
	//地图缩放的范围,当前地图缩放至此范围,视图域将显示此范围内的地图
	extent:[13100000,4290000,13200000,5210000]
});
//加载到map容器中
map.addControl(zoomToExtent);

导航条就是滑动形式放大缩小,可以通过编写css代码修改样式

#map .ol-zoom .ol-zoom-out{
	margin-top: 204px;
}
#map .ol-zoomslider{
	background-color: transparent;
	top: 2.3em;
}
#map .ol-touch.ol-zoom .ol-zoom-out{
	margin-top: 212px;
}
#map .ol-touch .ol-zoomslider{
	top: 2.75em;
}
#map .ol-zoom-in .ol-has-tooltip:hover[	role=tooltip;],
#map .ol-zoom-in .ol-has-tooltip:focus[role=tooltip]{
	top:3px;
}
#map .ol-zoom-out .ol-has-tooltip:hover[	role=tooltip],
#map .ol-zoom-out .ol-has-tooltip:focus[role=tooltip]{
	top:232px;
}
#map .ol-zoom-extent{
	top:280px;
}

注意: 这些操作主要有几点注意,加载瓦片图层数据时需要设置参数XYZ, 旋转角度的设置,地图旋转是通过旋转控件(ol.control.Rotation)实现的,此控件已默认添加到地图中,ol.control.Rotate控件的autohHide参数默认为true,在旋转角度为0°时将自动隐藏旋转按钮 tooltip时设置悬浮的提示框 修改css样式时,c比如修改lass下得id对应样式,.class和#id之间需要空格 wrapX:true, //x方向平铺,false就是不平铺

自定义地图

注意:feature中不能直接getSource(),layer才可以直接getSource()。但是可以通过自己封装函数来实现通过feature获取layer。feature可以直接getGeometry()

通过target指定id为map的div容器,如果地图未正确显示,可以检查地图容器宽高的设置

方法1:初始化map实例后,向某一指定图层添加点/线/面元素(feature)
//初始化红绿灯数据
initLightData(){
  this.lightLayer.getSource().clear(); // 清空图层
  this.lightData.forEach((item, index) => {
      var feature = new Feature({
          geometry: new Point([Number(item.x), Number(item.y)]),
      });
      let url = "images/light.png";
      const zoom = this.map.getView().getZoom();
      let style = new Style({
              image: new Icon({
                  scale: 0.15 * (zoom -13) ,
                  src: url,
                  anchor: [0.48, 0.52],
              }),
          });
      feature.setStyle(style);
      this.lightLayer.getSource().addFeature(feature);
  });
},
import { Image as ImageLayer, Vector as VectorLayer, Tile as TileLayer, } from "ol/layer";
import { Circle as CircleStyle, Fill, Icon, Stroke, Style, Text, } from "ol/style";
// 候车室点位
drawWaitingPoint() {
    this.wrnameData.forEach((item, index) => {
        var feature = new Feature({
            geometry: new Point([item.x, item.y]),
        });
        feature.setId(`${item.wrname}`);

        let style = new Style({
            text: new Text({
                font: "normal 10px 黑体",
                // // 对其方式
                textAlign: "center",
                // 基准线
                textBaseline: "middle",
                offsetY: 0,
                offsetX: 0,
                // 文本填充样式
                fill: new Fill({
                    color: "rgba(236,218,20,1)",
                }),
                padding: [5, 5, 5, 5],
                text: `${item.wrname}`,
            }),
        });
        feature.setStyle(style); // 为元素设置样式
        this.roomLayer.getSource().addFeature(feature);
    });
},
方法2:添加点/线/面图层
import { Feature } from "ol";
import { Point, LineString, Polygon } from "ol/geom";
addLayer() {
  this.vectorLayer = new VectorLayer({
    source: new VectorSource(),
  });
  this.vectorLayer.getSource().addFeature(
    //添加点图层
    new Feature({
      geometry: new Point([104.2979180563, 30.528298024]),
    })
    //添加线图层
    // new Feature({
    //   geometry: new LineString([
    //     [104.2979180563, 30.528298024],
    //     [104.2987389704, 30.527798338],
    //   ]),
    // })
    //添加面图层
    // new Feature({
    //   geometry: new Polygon([
    //     [
    //       [104.2979180563, 30.528298024],
    //       [104.2987389704, 30.527798338],
    //       [104.2974397847, 30.5265062907],
    //       [104.2979180563, 30.528298024],
    //     ],
    //   ]),
    // })
  );
}

三、自定义点线面图层

创建点要素Point

let feature = new Feature({
  geometry: new Point([104.2979180563, 30.528298024]),
});

创建线要素LineString

let feature = new Feature({
  geometry: new LineString([
    [104.2979180563, 30.528298024],
    [104.2987389704, 30.527798338],
  ]),
});

创建面要素Polygon

let feature = new Feature({
  geometry: new Polygon([
    [
      [106, 33],
      [108.03955078125, 32.2313896627376],
      [108.25927734375, 33.15594830078649],
      [106, 33],
    ],
  ]),
});

动态添加坐标

let geometry = new LineString(); //LineString 线,Point 点,Polygon 面
 
let coordinate = [
        [105.6005859375, 30.65681556429287],
        [107.95166015624999, 31.98944183792288],
    ];
 
function addPonitToGeometry(arr) {
    for (let i = 0; i < arr.length; i++) {
        geometry.appendCoordinate(arr[i]);
    }
}
addPonitToGeometry(coordinate);
 
let LineStringFeature = new Feature(geometry); 

给feature设置id

feature.setId(xxx)

获取feature的id

feature.getId()

通过feature的id获取feature

source.getFeatureById(xxx)

添加feature

source.addFeature(xxx)

移除feature

source.removeFeature(xxx)

数据源source中遍历所有要素feature

source.forEachFeature(feature=>{})

数据源source中获取features数组

source.getFeatures()

geojson中获取features数组

import GeoJSON from "ol/format/GeoJSON";
geojsonData: {
    type: "FeatureCollection",
    features: [
      {
        type: "Feature",
        geometry: {
          type: "Point",
          coordinates: [0, 0],
        },
      },
    ],
 },
 let features = new GeoJSON().readFeatures(this.geojsonData)

给feature动态设置文本text

change() {
	this.feature
		.getStyle()
		// .getText()
		// .setText("哈哈哈");
  	this.feature.changed();
}

给feature设置样式style

feature.setStyle(new Style(xxx))

根据feature获取geometry

feature.getGeometry()

将feature置于视图中心-fly飞行

this.map.getView().fit(feature.getGeometry(), {
   duration: 1000,
   padding: [100, 100, 100, 100],
 });

根据feature获取geometry类型

feature.getGeometry().getType()
如:Point、LineString、Polygon等 

给feature设置指定属性

feature.set("xx",xx)

给feature设置多个属性

feature.setProperties(Object)

获取feature中的指定属性

获取feature要素后,可以直接通过feature.get('属性名') 来获取geojson中该feature的属性值

feature.get('属性名')

获取feature中的所有属性

或者通过feature.getProperties() 来获取geojson中该feature的所有的属性值,返回包含属性值的一个对象

通过feature获取layer

适用于点要素和面要素,而线要素还有待研究。

import {Vector as VectorSource } from "ol/source";
 
// 根据feature获取layer
getLayer(feature = {}, map = {}) {
  let layers = map.getLayers().getArray();
  for (let i in layers) {
    let source = layers[i].getSource();
    if (source instanceof VectorSource) {
      let features = source.getFeatures();
      if (features.length > 0) {
        for (let j in features) {
          if (features[j] === feature) {
            return layers[i];
          }
        }
      }
    }
  }
  return {};
},