Openlayers 案例整理

Openlayers 案例整理

2020-08-31 28

Openlayers加载在线地图,画点、线、面、图片、自定义切图等数据源,大数据下的聚合标注,绘制交互等

参考 https://openlayers.org/en/latest/examples ,官网更详细

1、地图

加载在线地图资源,这里以天地图为例

const baseLayer = new Tile() // 底图
const labelLayer = new Tile() // 标注
map = new ol.Map({
  layers: [baseLayer, labelLayer],
  target: Element, // 绑定的dom元素
  view: new ol.View({
    center: center,  // 中心点坐标
    maxZoom: maxZoom,  // 最大缩放等级
    minZoom: minZoom,  // 最小缩放等级
    zoom: zoom  // 默认缩放等级
  })
})

getTdtSource(lyr) {
  const key = '3d7245b3b701467ef55e80a971c91612' // 当出现418、429状态码,可能是apiKey超出每日调用限制了,换一个或自己注册
  const url = 'http://t{0-7}.tianditu.com/DataServer?T=' + lyr + '&X={x}&Y={y}&L={z}&tk=' + key
  return new XYZ({
    url: url
  })
}
/**
 * 切换地图瓦片材质
 * @param  {string} type 默认矢量图
 * @example ['影像','地形']
 */
changeBaseLayer(type) {
  let baseSource, labelSouce
  switch (type) {
    case '影像':
    {
      baseSource = this.getTdtSource('img_w')
      labelSouce = this.getTdtSource('cia_w')
      break
    }
    case '地形':
    {
      baseSource = this.getTdtSource('ter_w')
      labelSouce = this.getTdtSource('cva_w')
      break
    }
    default: // 矢量图
    {
      baseSource = this.getTdtSource('vec_w')
      labelSouce = this.getTdtSource('cva_w')
      break
    }
  }
  baseLayer.setSource(baseSource)
  labelLayer.setSource(labelSouce)
}

2、加载切片

const osmSource = new ol.source.OSM()
const projectionExtent = fromEPSG4326(projectionExtent)  // 切片范围
const projection = new Projection({
  code: 'EPSG:3857',
  units: 'pixel',
  extent: projectionExtent,
  global: true
})
const tileGrid = new TileGrid({
  tileSize: 256,
  minZoom: 11,
  origin: [-2.00377E7, 3.02411E7],
  extent: projectionExtent,
  resolutions: osmSource.getResolutions()
})
const untiled = new Tile({
  source: new TileImage({
    wrapX: false,
    crossOrigin: 'anonymous',
    tileUrlFunction: function(tileCoord) { // 加载切片瓦片地址
      if (!tileCoord) {
        return ''
      }
      const z = tileCoord[0]
      let x = tileCoord[1]
      // const y = Math.pow(2, z-1) + tileCoord[2];
      const y = Math.pow(2, z) + tileCoord[2] // openlayers 3.x
      // const y = Math.abs(tileCoord[2]);
      // wrap the world on the X axis
      const n = Math.pow(2, z + 1) // 2 tiles at z=0
      x = x % n
      if (x * n < 0) {
        x = x + n
      }

      const path = '/' + z + '/' + x + '/' + y + '.png'
      return path
    }
  }),
  tileGrid: tileGrid,
  projection: projection
})
map.addLayer(untiled)

3、销毁实例

由于OpenLayers中大量用到了闭包,最开始OpenLayers的内存泄露、销毁问题也是蛮严重的,后面差不多每个类中都写了destroy方法,用于释放资源,在单页应用中,在销毁当前组件前应调用下Openlayers用到那些类的destroy方法以释放资源。

/**
 * 销毁openlayers,内存回收
 * @summary 移除UI控件、交互、图层、要素、覆盖物
 */
destroy() {
  const controls = map.getControls().getArray()
  const interactions = =map.getInteractions().getArray()
  const layers = map.getLayers().getArray()
  const overlays = map.getOverlays().getArray()
  for (let i = controls.length - 1; i >= 0; i--) {
    map.removeControl(controls[i])
  }
  for (let i = interactions.length - 1; i >= 0; i--) {
    map.removeInteraction(interactions[i])
  }
  for (let i = layers.length - 1; i >= 0; i--) {
    const sources = layers[i].getSource()
    if (sources && sources.clear) sources.clear()
    map.removeLayer(layers[i])
  }
  for (let i = overlays.length - 1; i >= 0; i--) {
    map.removeOverlay(overlays[i])
  }
}

4、画各种要素、数据源

4.1、点

const feature = new Feature({
  geometry: new Point(coordinates)
})
const pointLayer = new VectorLayer({
  source: new VectorSource({
    features: [feature]
  }),
  style: function(feature) {}
})
this.map.addLayer(pointLayer)

4.2、线

const features = []
for (let i = 0; i < data.length; i++) {
  const feature = new ol.Feature({
    geometry: new ol.geom.LineString(data[i])
  })
  features.push(feature)
}
const lineLayer = new ol.layer.Vector({
  source: new ol.source.Vector({
    features: features
  }),
  style: function(feature) {}
})
map.addLayer(lineLayer)

4.3、面

const extent = [x1, y1, x2, y2]
// 多边形要素
const polygonFeature = new ol.Feature(
  new ol.geom.Polygon(
    [
      [
        [x1, y1], // 原点
        [x1, y2], // 第二个点
        [x2, y2], // 第三个点
        // ……
        [x1, y1] // 回到原点
      ]
    ]
  )
)
const source = new ol.source.Vector({
  features: [polygonFeature]
})
var polygonLayer = new ol.layer.Vector({
  source: source,
  style: function() {}
})
map.addLayer(polygonLayer)

4.4、单张图片

const source = new ol.source.ImageStatic({
  attributions: img.name,  // 图片的名称
  url: img.url,  // 图片的地址
  imageExtent: img.imageExtent  // 图片的展示范围,无参考坐标系可以用图片的尺寸
})
const tl = new ol.layer.Image({
  source: source 
})
map.addLayer(tl)

5、聚合

//此示例创建10000个要素
const count = 10000;
const features = new Array(count);
const e = 4500000;
for(let i = 0; i < count; i++){
  const coordinates = [2*e*Math.random()-e, 2*e*Math.random()-e];
  features[i] = new ol.Feature(
    new ol.geom.Point(coordinates)
  );
}
//矢量要素数据源
const source = new ol.source.Vector({
  features: features
});
//聚合标注数据源
const clusterSource = new ol.source.Cluster({
  distance: 40,               //聚合的距离参数,即当标注间距离小于此值时进行聚合,单位是像素
  source: source              //聚合的数据源,即矢量要素数据源对象
});
//加载聚合标注的矢量图层
const styleCache = {};                    //用于保存特定数量的聚合群的要素样式
const clusters = new ol.layer.Vector({
  source: clusterSource,
  style: function (feature, resolution){
    const size = feature.get('features').length;          //获取该要素所在聚合群的要素数量
    let style = styleCache[size];
    if(!style){
      style = [
        new ol.style.Style({
          image: new ol.style.Circle({
            radius: 10,
            stroke: new ol.style.Stroke({
                color: '#fff'
            }),
            fill: new ol.style.Fill({
                color: '#3399CC'
            })
          }),
          text: new ol.style.Text({
            text: size.toString(),
            fill: new ol.style.Fill({
                color: '#fff'
            })
          })
        })
      ];
      styleCache[size] = style;
    }
    return style;
  }
});
map.addLayer(clusters);

6、覆盖物

/**
 * 添加覆盖要素
 * @param  { HTMLElement | String } 元素id | HTML元素
 * @param { String } positioning 容器基于鼠标点的定位
 * @param { Array } offset 容器的偏移
 */
addOverLayers(name = 'simpleCarBox', positioning, offset = [0, 0]) {
  this.overlay = new ol.Overlay({
    id: name,
    element: document.getElementById(name),
    autoPan: true,
    positioning,
    offset,
    autoPanAnimation: {
      duration: 250
    }
  })
  this.map.addOverlay(this.overlay)
}
/**
 * 更新信息气泡的位置
 * @param {Array} coordinate 新的坐标点
 */
setOverLayer(coordinates) {
  this.overlay.setPosition(coordinates)
}

7、绘制、交互

const drawSource = new ol.source.Vector()
const drawLayer = new ol.layer.Vector({
  source: drawSource,
  style: function() {}
})
const draw = new ol.interaction.Draw({
  source: drawSource,
  type: type
})
const snap = new ol.interaction.Snap({ source: drawSource })
const modify = new ol.interaction.Modify({ source: drawSource })
map.addInteraction(draw)
map.addInteraction(snap)
map.addInteraction(modify)
map.addLayer(drawLayer)

8、导出图片

获取map中的canvas,并导出图片
map.once('postcompose', (event) => {
  const canvas = event.context.canvas
  const imageData = canvas.toDataURL('image/png')
  return imageData
})

评论(0)

还没有评论,快来抢第一吧