返回介绍

使用 WebGL 过滤图形要素

发布于 2022-11-30 23:36:03 字数 6912 浏览 0 评论 0 收藏 0

使用 WebGL 过滤大量图形要素

这个例子展示了如何使用ol/layer/WebGLPoints的文字样式来动态地过滤大量的几何点。上面的地图是基于美国国家航空航天局的数据集,包含45k记录的陨石着陆点。每颗陨石在地图上都有一个圆圈标记(圆圈越大,物体越重)。增加了一个脉冲效应,它被影响的年份略微抵消了。 本示例演示使用 ol/layer/WebGLPoints 的文字样式动态的过滤大量的点图形。上边的地图渲染了 NASA 的数据集,包含45k记录的陨石着陆点。每颗陨石在地图上都有一个圆圈标记(圆圈越大,物体越重)。增加了一个脉冲效应,它被影响的年份略微抵消了。 每个陨石在地图上以圆圈来标记显示(圆圈越大,陨石越重)。并且添加了脉冲效应,这个脉冲效应被影响的年份略微抵消了(没太明白啥意思)。

调整滑块会导致日期范围之外的对象被过滤出地图。通过调整滑块,可以改变日期范围,并且将日期之外的图形对象过滤到地图之外。此功能是通过改变提供给WebGL层的样式( style )对象中的变量来实现的。除此之外,还要注意的是,为了确保地图每一帧都刷新,最后一段代码是必须的。

main.js

import 'ol/ol.css';
import Feature from 'ol/Feature';
import Map from 'ol/Map';
import Point from 'ol/geom/Point';
import Stamen from 'ol/source/Stamen';
import TileLayer from 'ol/layer/Tile';
import View from 'ol/View';
import WebGLPointsLayer from 'ol/layer/WebGLPoints';
import {Vector} from 'ol/source';
import {fromLonLat} from 'ol/proj';

const vectorSource = new Vector({
  attributions: 'NASA',
});

const oldColor = 'rgba(242,56,22,0.61)';
const newColor = '#ffe52c';
const period = 12; // animation period in seconds
const animRatio = [
  '^',
  [
    '/',
    [
      '%',
      [
        '+',
        ['time'],
        ['interpolate', ['linear'], ['get', 'year'], 1850, 0, 2015, period],
      ],
      period,
    ],
    period,
  ],
  0.5,
];

const style = {
  variables: {
    minYear: 1850,
    maxYear: 2015,
  },
  filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']],
  symbol: {
    symbolType: 'circle',
    size: [
      '*',
      ['interpolate', ['linear'], ['get', 'mass'], 0, 8, 200000, 26],
      ['-', 1.75, ['*', animRatio, 0.75]],
    ],
    color: ['interpolate', ['linear'], animRatio, 0, newColor, 1, oldColor],
    opacity: ['-', 1.0, ['*', animRatio, 0.75]],
  },
};

// handle input values & events
const minYearInput = document.getElementById('min-year');
const maxYearInput = document.getElementById('max-year');

function updateMinYear() {
  style.variables.minYear = parseInt(minYearInput.value);
  updateStatusText();
}
function updateMaxYear() {
  style.variables.maxYear = parseInt(maxYearInput.value);
  updateStatusText();
}
function updateStatusText() {
  const div = document.getElementById('status');
  div.querySelector('span.min-year').textContent = minYearInput.value;
  div.querySelector('span.max-year').textContent = maxYearInput.value;
}

minYearInput.addEventListener('input', updateMinYear);
minYearInput.addEventListener('change', updateMinYear);
maxYearInput.addEventListener('input', updateMaxYear);
maxYearInput.addEventListener('change', updateMaxYear);
updateStatusText();

// load data
const client = new XMLHttpRequest();
client.open('GET', 'data/csv/meteorite_landings.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),
      })
    );
  }

  vectorSource.addFeatures(features);
};
client.send();

const map = new Map({
  layers: [
    new TileLayer({
      source: new Stamen({
        layer: 'toner',
      }),
    }),
    new WebGLPointsLayer({
      style: style,
      source: vectorSource,
      disableHitDetection: true,
    }),
  ],
  target: document.getElementById('map'),
  view: new View({
    center: [0, 0],
    zoom: 2,
  }),
});

// animate the map
function animate() {
  map.render();
  window.requestAnimationFrame(animate);
}
animate();

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Filtering features with WebGL</title>
    <!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
    <script src="https://unpkg.com/elm-pep"></script>
    <!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
    <script src="./resources/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder,Number.isInteger"></script>
    <style>
      .map {
        width: 100%;
        height:400px;
      }
    </style>
  </head>
  <body>
    <div id="map" class="map"></div>
    <form>
      <div id="status">Show impacts between <span class="min-year"></span> and <span class="max-year"></span></div>

      <label for="min-year">Minimum year:</label>
      <input id="min-year" type="range" min="1850" max="2015" step="1" value="1850"/>
      <label for="max-year">Maximum year:</label>
      <input id="max-year" type="range" min="1850" max="2015" step="1" value="2015"/>
    </form>
    <script src="main.js"></script>
  </body>
</html>

package.json

{
  "name": "filter-points-webgl",
  "dependencies": {
    "ol": "7.1.0"
  },
  "devDependencies": {
    "parcel": "^2.0.0-beta.1"
  },
  "scripts": {
    "start": "parcel index.html",
    "build": "parcel build --public-url . index.html"
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文