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
  })
});

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


image

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
})

渲染后的效果如下所示:


image

但是看上去有点问题,叠加上去的图形是正方形的,不是圆形,是因为着色器默认为正方形的,需要自己定义一个片段着色器,将图形设置成圆形的。


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;
      },
      //! [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]
    });
  }
}

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


image

个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容