OpenLayers 学习笔记一

关注我,带你一起学GIS ^

注:当前使用的是 ol [9.2.4] 版本,天地图使用的key请到天地图官网申请,并替换为自己的key

1. 一些关系

1.1. Map对象

MapOpenLayers的核心组件,由目标容器、视图和图层等组成。在Map对象中管理图层组以及控件,凡是涉及到图层(layers)、控件(controls)以及叠加层(overlay)的操作都由Map对象完成。

1.2. View对象

View用于控制视图,如修改地图中心点、缩放级别、地图投影以及视图动画等。

1.3. Map和View的关系

Map对象用来装载地图,View对象用来显示地图,而且View对象是Map对象的属性。OpenLayers和ArcGIS API for JS一样,将地图划分为Map和View两个顶级对象。

1.4. 图层对象

OpenLayers中图层对象很多,图层还可以形成图层组,添加到地图上的对象具有层级特点,即最近添加的图层离用户最近,即图层添加越晚,显示层级越高,与CSS属性z-index类似。大体上可以分为矢量图层、切片图层、影像图层等几大类。详见OpenLayers 框架体系在OpenLayers中矢量图层的大致组成关系如下

几何对象->要素(要素集)->数据源->数据集geometry->features->source->layer

2. 一些属性

2.1. View对象属性

multiWord:是否启用多地图投影坐标系,默认为 false。当设置为 true 时,可以在同一个地图中使用多个不同的投影,适用于跨越多个地区和国家的地图。

2.2. Source 对象属性

wrapX:是否启用图层横向重复,默认为 false。当设置为 true,地图沿水平方向循环出现。

3. 一些方法

3.1. 获取图层方法

可以使用getAllLayers、getLayers方法获取加载到地图中的所有图层。

// 返回从所有图层组中获取到的所有图层
map.getAllLayers()
// 返回与地图关联的图层集合(Collection)
map.getLayers()

使用getLayers()方法获取到图层是一个集合对象,可以通过getArray()方法将其转换为一个数组对象。

3.2. 添加图标方法

  1. 通过 `Overlay` 类添加图标
    
const marker = new ol.Overlay({
  element: document.getElementById('markerId'),
  positioning: 'center-center',
  position: [4000, -3000]
});
map.addOverlay(marker);
  1. 通过 `Feature` 要素样式添加图标
    
const markerStyle = new ol.style.Style({
  image: new ol.style.Icon(({
    src: '../image/markre.png',
    size: [20, 20]
  }))
});
const markerSource = new ol.source.Vector({
  features: [feature]
});
const markerLayer = new ol.layer.Vector({
  source: markerSource,
  style: markerStyle
});
map.addLayer(markerLayer);

3.3. 添加GeoJSON方法

方式一:使用urlformat组合。

const JSON_URL = ""
const vectorSource = new ol.source.Vector({
    url: JSON_URL,
    format: new ol.format.GeoJSON()
})
const layer = new ol.layer.Vector({
    source: vectorSource
})

方式二:使用GeoJSON属性readFeatures方法读取JSON数据,然后赋值给数据源features属性,features属性类型为数组对象。

const layer = new ol.layer.Vector({
    source: new ol.source.Vector({
        features: (new ol.format.GeoJSON()).readFeatures(result)
    })
})

注意:OpenLayers中加载一些非标准GeoJSON 几何对象时,需要将数据格式转换为标准GeoJSON 格式。如要添加feature或者FeatureCollection 时,数据对象缺少type属性,则会报错,需要将每一个要素(feature)重新设置type属性,不然readFeatures方法会报错。

features.forEach(feature => {
  feature.type = "Feature"
})

const featureCollection = {
  "type""FeatureCollection",
  "features": features
}
// 添加GeoJSON数据
const featureSet = new GeoJSON().readFeatures(featureCollection)
addGeoJSON2Map(featureCollection)

3.4. 添加Popup方法

信息弹窗用于显示要素信息,在OpenLayers中并没有直接提供一个Popup类供用户使用,但是可以使用Overlay类来实现Popup弹窗效果。

/**
 * 设置 Popup 信息弹窗
 * @param property:要素属性
 * @param popupColumns:信息弹窗字段
 * @param polygon:信息弹窗几何对象
 * @param map:信息弹窗显示地图
 */
export function setPopup(property, popupColumns, polygon, map) {
  removeOverlayByName('overLay',map)
  //  自定义popup容器
  const popupDiv = document.createElement('div')
  popupDiv.setAttribute('class''custom-popup')
  // 自定义popup头部
  const headerDiv = document.createElement('div')
  headerDiv.setAttribute('class''custom-popup-header')
  const titleSpan = document.createElement('span')
  titleSpan.setAttribute('class''custom-popup-title')
  titleSpan.textContent = "属性信息"
  const closeSpan = document.createElement('span')
  closeSpan.setAttribute('class''custom-popup-close')
  closeSpan.textContent = "X"
  headerDiv.appendChild(titleSpan)
  headerDiv.appendChild(closeSpan)
  // 自定义头部定位角标
  const headerAngleIcon = document.createElement('span')
  headerAngleIcon.setAttribute('class''custom-header-angle')
  // 自定义popup表格
  const tableEle = document.createElement('table')
  tableEle.className = "popup-table"
  tableEle.setAttribute('border','1')
  tableEle.setAttribute('cellpadding','0')
  tableEle.setAttribute('cellspacing','0')

  Object.values(popupColumns).forEach((prop,index) => {
    if (prop["name"] === 'id' || prop["name"] === 'import_oid'return
    const trEle = document.createElement('tr')
    trEle.className = 'table-tr'
    const firstTdEle = document.createElement('td')
    const secondTdEle = document.createElement('td')
    firstTdEle.innerText = popupColumns[index].name //popupColumns[index].comment
    secondTdEle.innerText = property[popupColumns[index].name] || '暂无'

    trEle.appendChild(firstTdEle)
    trEle.appendChild(secondTdEle)
    tableEle.appendChild(trEle)
  })
  popupDiv.appendChild(headerAngleIcon)
  popupDiv.appendChild(headerDiv)
  popupDiv.appendChild(tableEle)
  const extent = polygon.getExtent()
  const center = getCenter(extent)

  // 创建Overlay popup
  const overlay = new Overlay({
    id: "temp-",
    position: center,
    element: popupDiv,
    offset: [0,20],
    autoPan: false,
    autoPanMargin: 1.25,
    positioning: 'top-center'
  })
  overlay.setProperties({ layerName: "overLay" })
  map.addOverlay(overlay)

  // 监听popup移除事件
  closeSpan.addEventListener('click',evt => {
    removeOverlayByName('overLay',map)
  })
}

4. 清除所有图层时的bug

对于自己封装的清除所有图层方法在使用过程中遇到了一个问题,通过遍历所有图层来移除图层对象的方式并不能起到很好的效果,不能一次性清除目标图层。

// 清除图层
const layers = map.getLayers().getArray()
layers.forEach(layer => {
  const props = layer.getProperties()
  if (!props.isBaseMap){
    map.removeLayer(layer)
  }
})

使用以下方式可以达到清除目标图层组的操作,但是不太满意。通过过滤目标图层组,然后再对目标图层组执行清除命令。

const tarLayers = layers.filter(layer => {
  const props = layer.getProperties()
  if (!props.isBaseMap){
    return layer
  }
})
tarLayers.forEach(tar => {
  map.removeLayer(tar)
})
/**
 * @description:清除除了底图的所有图层
 * @param map:地图对象,默认为全局地图对象
 */
export function removeAllLayer(map = window._map){
  // 清除图层
  const layers = map.getLayers().getArray()
  // layers.forEach(layer => {
  //   const props = layer.getProperties()
  //   if (!props.isBaseMap){
  //     map.removeLayer(layer)
  //   }
  // })

  // 为什么要下面这种才能一次性清除呢?很奇怪
  const tarLayers = layers.filter(layer => {
    const props = layer.getProperties()
    if (!props.isBaseMap){
      return layer
    }
  })
  tarLayers.forEach(tar => {
    map.removeLayer(tar)
  })
  console.log(tarLayers);

  // 清除Overlay
  const overLayers = map.getOverlays().getArray()
  overLayers.forEach(overLayer => map.removeOverlay(overLayer))
}

使用getAllLayers方法获取到图层对象进行移除可以方便解决这个问题。

const layers = map.getAllLayers()
layers.forEach(layer => map.removeLayer(layer))

5. StyleFunction 函数

样式函数具有一个feature参数,使用样式函数可以方便处理图层标注的问题,只需要在最后返回目标央视对象即可。

style: (feature)=>{
  style.setText(new Text({
    font:'16px sans-serif',
    text: feature.getProperties().projectName,
    fill: new Fill({
      color: 'rgba(0, 0, 0, 1)'
    }),
    // backgroundFill: new Fill({
    //   color: 'rgba(255, 255, 255, 1)'
    // }),
    stroke:new Stroke({
      color:'rgba(255, 255, 255, 1)',
      width:2
    })
  }))
  return style
}

OpenLayers示例数据下载,请在公众号后台回复:ol数据

全国信息化工程师-GIS 应用水平考试资料,请在公众号后台回复:GIS考试

GIS之路公众号已经接入了智能助手,欢迎大家前来提问。

欢迎访问我的博客网站-长谈GIShttp://shanhaitalk.com

都看到这了,不要忘记点赞、收藏+关注 

本号不定时更新有关 GIS开发  相关内容,欢迎关注 

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部