Bootstrap

openlayers WebGLPoints图层应用(光环、光晕扩散收缩)

本篇介绍一下使用 openlayers WebGLPoints图层应用(光环、光晕扩散收缩)

1 需求

  • WebGL渲染的光环、光晕扩散收缩

2 分析

  • WebGLPoints图层应用
  • ol/expr/expression 的简单使用官网解释

WebGLPoints 的 style 属性比较多(基本都是图标、填充色、描边宽度及颜色之类的)具体参见源码v9.2.4(src/ol/style/webgl.js) github地址

3 实现

3.1 光晕扩散

在这里插入图片描述

<template>
  <div id="map" class="map"></div>
  <div class="toolbar">
      <div>
        <span>日期范围</span>
        <el-slider
          v-model="date"
          :min="2000"
          :max="2024"
          range
          show-stops
          @input="handleInput"
        ></el-slider>
      </div>
  </div>
</template>

<script setup lang="ts">
import { Feature, Map, View } from 'ol';
import { WebGLTile as WebGLTileLayer } from 'ol/layer';
import { get } from 'ol/proj';
import { XYZ } from 'ol/source';
import { Vector as VectorSource } from 'ol/source.js';
import { Point } from 'ol/geom';
import WebGLPointsLayer from 'ol/layer/WebGLPoints';

const projection = get('EPSG:4326');
const key = '替换为天地图key';
const layerTypeMap = {
  vector: ['vec', 'cva'], // [矢量底图, 矢量注记]
  image: ['img', 'cia'], // [影像底图, 影像注记]
  terrain: ['ter', 'cta'] // [地形晕渲, 地形注记]
};
const startColor = 'rgba(255, 242, 0,0.7)';
const endColor = '#ff7f00';
const period = 10;
const date = ref([2000, 2024]);
let map = null;

const rate = [
  '/',
  [
    '%',
    ['+', ['time'], ['interpolate', ['linear'], ['get', 'date'], 2000, 0, 2024, period]],
    period
  ],
  period
];

const variables = computed(() => {
  return {
    min: date.value[0],
    max: date.value[1]
  };
});

const source = new VectorSource();

const pointerLayer = new WebGLPointsLayer({
  source: source,
  style: {
    variables: variables.value,
    filter: ['between', ['get', 'date'], ['var', 'min'], ['var', 'max']],
    'circle-radius': [
      '*',
      ['interpolate', ['linear'], ['get', 'count'], 0, 5, 100000, 15],
      ['+', 1.5, ['*', rate, 0.8]]
    ],
    'circle-fill-color': ['interpolate', ['linear'], rate, 0, startColor, 1, endColor],
    'circle-opacity': ['-', 1.0,  rate]
  }
});

onMounted(() => {
  initMap('image');
  initPoints();
});

const initMap = (layerType = 'image') => {
  // c: 经纬度 w: 墨卡托
  const matrixSet = 'c';
  map = new Map({
    target: 'map',
    view: new View({
      center: [116.406393, 39.909006],
      projection: projection,
      zoom: 5,
      maxZoom: 17,
      minZoom: 1
    }),
    layers: [
      // 底图
      new WebGLTileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][0]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      // 注记
      new WebGLTileLayer({
        source: new XYZ({
          url: `https://t{0-7}.tianditu.gov.cn/DataServer?T=${layerTypeMap[layerType][1]}_${matrixSet}&tk=${key}&x={x}&y={y}&l={z}`,
          projection
        })
      }),
      pointerLayer
    ]
  });

  pointerLayer.on('postrender', function (event) {
    map.render();
  });
};

const initPoints = () => {
  const points = [
    {
      count: 50000,
      date: 2000,
      coordinates: [123, 29]
    },
    {
      count: 20000,
      date: 2001,
      coordinates: [120, 31]
    },
    {
      count: 6000,
      date: 2002,
      coordinates: [117, 29]
    },
    {
      count: 17900,
      date: 2003,
      coordinates: [121, 37]
    },
    {
      count: 500,
      date: 2005,
      coordinates: [121, 29]
    },
    {
      count: 1500,
      date: 2006,
      coordinates: [122, 22]
    },
    {
      count: 6500,
      date: 2007,
      coordinates: [125, 21]
    },
    {
      count: 70500,
      date: 2008,
      coordinates: [120, 24]
    },
    {
      count: 66500,
      date: 2009,
      coordinates: [127, 26]
    },
    {
      count: 30000,
      date: 2001,
      coordinates: [113, 29]
    },
    {
      count: 10000,
      date: 2002,
      coordinates: [110, 31]
    },
    {
      count: 16000,
      date: 2003,
      coordinates: [114, 29]
    },
    {
      count: 27900,
      date: 2004,
      coordinates: [111, 30]
    },
    {
      count: 15000,
      date: 2005,
      coordinates: [113, 26]
    },
    {
      count: 2500,
      date: 2006,
      coordinates: [111, 26]
    },
    {
      count: 3500,
      date: 2007,
      coordinates: [112, 23]
    },
    {
      count: 9500,
      date: 2007,
      coordinates: [115, 22]
    },
    {
      count: 10500,
      date: 2008,
      coordinates: [110, 25]
    },
    {
      count: 26500,
      date: 2009,
      coordinates: [120, 26]
    }
  ];
  points.forEach(p => {});
  source.addFeatures(
    points.map(
      p =>
        new Feature({
          count: p.count,
          date: p.date,
          geometry: new Point(p.coordinates)
        })
    )
  );
};

const handleInput = () => {
  pointerLayer.updateStyleVariables(variables.value);
};
</script>
<style scoped lang="scss">
.map {
  width: 100%;
  height: 100%;
}
.toolbar {
  position: absolute;
  top: 20px;
  left: 100px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #fff;
  .el-slider {
    margin-right: 10px;
    margin-left: 10px;
  }
  div {
    width: 300px;
    height: 40px;
    display: flex;
    justify-content: center;
    align-items: center;
    span {
      width: 120px;
      margin-left: 10px;
    }
  }
}
</style>


3.2 光晕收缩

只需要将下面代码:

['+', 1.5, ['*', rate, 0.8]]

修改为:

['-', 1.5, ['*', rate, 0.8]]

在这里插入图片描述

3.3 光环扩散和收缩

只需要将下面代码:

'circle-fill-color': ['interpolate', ['linear'], rate, 0, startColor, 1, endColor],

修改为:

'circle-stroke-width':2,
'circle-stroke-color': ['interpolate', ['linear'], rate, 0, startColor, 1, endColor],

在这里插入图片描述

;