Openlayers指南-WebGL

在叠加海量数据量,使用 WebGL 可以提升性能,因为 WebGL 是基于 GPU 来渲染的。这里主要介绍将 CSV 中的数据叠加到地图上来,首先使用的是用普通的 canvas 来叠加二维数据,然后再使用 WebGL 来叠加数据。

1.Canvas 2D渲染

Openlayers 6 中,地图的每个图层都是单独进行渲染的。之前所有图层都是在一个单独的渲染器上完成的。所以在 Openlayers 6 之前,只能选择 Canvas 2D 或者 WebGL 渲染所有图层,但在 Openlayers 6 可以为不同的图层选择不同的渲染策略,也就是说有些图层可用 Canvas 2D 渲染,有些图层可以用 WebGL 渲染。 ol/layer/Vector 可以用 Canvas 2D 来渲染点、线、面,这个图层具有丰富的渲染可能,可以渲染不同的样式。但是对于海量的数据来说, WebGL 是最佳的选择。下面使用 Canvas 2D 来加载 *45,000 **个点。

加载CSV

这里主要使用 csv 文件来加载数据,文件中的数据格式为如下所示:

name,mass,year,reclat,reclong
Aachen,21,1880,50.775000,6.083330

修改main.js后的代码如下所示:

import 'ol/ol.css';
import {fromLonLat} from 'ol/proj';
import {Map, View} from 'ol';
import {Vector as VectorLayer, Tile as TileLayer} from 'ol/layer';
import {Vector as VectorSource, Stamen} from 'ol/source';
import Feature from 'ol/Feature';
import Point from 'ol/geom/Point';
const source = new VectorSource();
const client = new XMLHttpRequest();
client.open('GET', 'data/meteorites.csv');
client.onload = function() {
  const csv = client.responseText;
  const features = [];
  let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
  let curIndex;
  while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
    const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
    prevIndex = curIndex + 1;
    const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
    if (isNaN(coords[0]) || isNaN(coords[1])) {
      // guard against bad data
      continue;
    features.push(new Feature({
      mass: parseFloat(line[1]) || 0,
      year: parseInt(line[2]) || 0,
      geometry: new Point(coords)
  source.addFeatures(features);
client.send();
new Map({
  target: 'map-container',
  layers: [
    new TileLayer({
      source: new Stamen({
        layer: 'toner'
    new VectorLayer({
      source: source
  view: new View({
    center: [0, 0],
    zoom: 2

全部叠加后的数据如下所示:

2.WebGL渲染

前面使用的是用Canvas 2D来渲染的,这里主要介绍一下WebGL怎么渲染要矢量图层。使用的是静态样式,如果使用动态样式来渲染,WebGL是最好的选择。在Openlayers中可以使用一起工具来使用WebGL渲染数据。步骤如下所示:

2.1引入相关工具

这里渲染的是点坐标,需要引入PointsLayer和一个数学函数工具。

import Renderer from 'ol/renderer/webgl/PointsLayer';
import {clamp} from 'ol/math';

2.2创建自定义图层

继承VectorLayer创建一个子类,重写createRenderer方法,并返回新的Renderer对象,在构造函数中设置colorCallbacksizeCallback,分别用于设置颜色和尺寸。

const color = [1, 0, 0, 0.5];
class CustomLayer extends VectorLayer {
  createRenderer() {
    return new Renderer(this, {
      colorCallback: function(feature, vertex, component) {
        return color[component];
      sizeCallback: function(feature) {
        return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;

创建好自定义图层后,然后再进行实例化,并指定source,如下所示:

new CustomLayer({
  source: source

渲染后的效果如下所示:

createRenderer() { return new Renderer(this, { colorCallback: function(feature, vertex, component) { return color[component]; sizeCallback: function(feature) { return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8; //! [fragment] fragmentShader: ` precision mediump float; varying vec2 v_texCoord; varying vec4 v_color; void main(void) { vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0); float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y; float value = 2.0 * (1.0 - sqRadius); float alpha = smoothstep(0.0, 1.0, value); gl_FragColor = v_color; gl_FragColor.a *= alpha; //! [fragment]

使用片段着色器处理后,将看到圆形了,如下所示: