OpenLayers Workshop(六)Raster Operations

Render sea level 渲染海平面

在之前的步骤中,我们直接在地图上渲染了Terrain-RGB的瓦片。然而我们想要做的是在地图上渲染海平面。并且我们想要我们的用户能够调整在海平面上的高度,查看跳帧高度后在地图上的渲染效果。我们将使用一个栅格的数据源去直接使用高程数据,并获取用户通过滑条输入的数据。

首先增加一些组件。在index.html中添加label和input标签:

<label id="slider">
  Sea level
  <input id="level" type="range" min="0" max="100" value="1"/>
  +<span id="output"></span> m
</label>

现在为组件增加样式:

#slider {
  position: absolute;
  bottom: 1rem;
  width: 100%;
  text-align: center;
  text-shadow: 0px 0px 4px rgba(255, 255, 255, 1);
}

与上次直接渲染Terrain-RGB图层的RGBA值不同,这次我们将要在渲染前操作像素值。栅格数据源允许我们接收任意数量的输入和一个操作来实现这个东西。这个操作是一个可以被所有输入源像素所调用的函数。我们只有一个输入源(高程),所以它将被一个数组的像素点调用,其中每一个像素点都是一个[red, green, blue, alpha]的数组。这个操作也会被data对象调用。我们将使用data对象去传递滑动条输入的值。

首先引入RasterSourceImageLayer

import ImageLayer from 'ol/layer/Image';
import RasterSource from 'ol/source/Raster';

在main.js中添加下面的方法。这个方法会对输入的高程数据进行解码:将RGB值转换成一个单独的高程测量值。对于等于或低于用户选择值的高程值,该函数将返回一个部分透明的蓝色像素,对于高于用户选择值的高程值,函数讲返回一个透明的像素:

function flood(pixels, data) {
  const pixel = pixels[0];
  if (pixel[3]) {
    // decode R, G, B values as elevation
    const height = -10000 + ((pixel[0] * 256 * 256 + pixel[1] * 256 + pixel[2]) * 0.1);
    if (height <= data.level) {
      // sea blue
      pixel[0] = 145; // red
      pixel[1] = 175; // green
      pixel[2] = 186; // blue
      pixel[3] = 255; // alpha
    } else {
      // transparent
      pixel[3] = 0;
    }
  }
  return pixel;
}

使用单个数据源(高程数据)创建一个栅格源,并使用flood函数对其进行配置:

const raster = new RasterSource({
  sources: [elevation],
  operation: flood
});

监听滑动条的输入值变化,并且在用户调整这个值的时候重新运行栅格操作:

const control = document.getElementById('level');
const output = document.getElementById('output');
control.addEventListener('input', function() {
  output.innerText = control.value;
  raster.changed();
});
output.innerText = control.value;

beforeoperations 事件会在栅格源的像素操作被执行前被启动。这是我们为这个操作提供额外数据的时机。在中国样例中,我们想要提供范围输入值(海拔米)。

raster.on('beforeoperations', function(event) {
  event.data.level = control.value;
});

最后,通过将源添加到图像层来渲染光栅操作的输出。 将瓦片图层替换为使用我们的栅格源的图像图层(修改map的layers数组):

new ImageLayer({
  opacity: 0.8,
  source: raster
})

现在可以通过控制滑动条的输入值来改变海平面的高度了。

发表评论