OpenLayers 5 使用turf.js渲染克里金插值计算的等值面

之前Trojx同学实现了一个克里金插值渲染等值面的例子,使用的是kriging.js内置的绘图函数,然后在openlayer中利用ImageCanvas渲染。

这个方法比较简便,但是有一些性能上的问题:

  • 网格切分比较小的时候,总体的网格数增加,每次重新渲染都要将整个网格数组遍历一次,交互体验不是很好;
  • 网格是以方块的形式呈现的,视觉效果不如曲线和多边形。

我使用了turf.js来处理网格数据,生成等值面,提升了交互性能,效果也更好看一点:

下面是源码:

<!DOCTYPE html>
<html>

<head>
    <title></title>
    <link rel="stylesheet" href="./include/ol.css" type="text/css" />
    <script src="./include/ol.js"></script>
    <script src="./include/kriging.js"></script>
    <script src='./include/turf.js'></script>
</head>
<style>
</style>

<body>
    <div id="map" class="map"></div>
    <script>
        let params = {
            mapCenter: [121.483101, 31.227036],
            maxValue: 100,
            krigingModel: 'spherical',//model还可选'gaussian','spherical',exponential
            krigingSigma2: 0,
            krigingAlpha: 100,
            canvasAlpha: 0.75,//canvas图层透明度
            colors: ["#006837", "#1a9850", "#66bd63", "#a6d96a", "#d9ef8b", "#ffffbf",
                "#fee08b", "#fdae61", "#f46d43", "#d73027", "#a50026"],
        };
        let baseLayer = new ol.layer.Tile({
            title: "base",
            source: new ol.source.OSM()
        });
        let map = new ol.Map({
            target: 'map',
            layers: [baseLayer],
            view: new ol.View({
                center: params.mapCenter,
                projection: 'EPSG:4326',
                zoom: 16
            })
        });
        let WFSVectorSource = new ol.source.Vector();
        let WFSVectorLayer = new ol.layer.Vector(
            {
                source: WFSVectorSource,
            });
        map.addLayer(WFSVectorLayer);
        
        //添加选择和框选控件,按住Ctr键,使用鼠标框选采样点
        let select = new ol.interaction.Select();
        map.addInteraction(select);
        let dragBox = new ol.interaction.DragBox({
            condition: ol.events.condition.platformModifierKeyOnly
        });
        map.addInteraction(dragBox);


        //创建15个位置随机、属性值随机的特征点
        for (let i = 0; i < 15; i++) {
            let feature = new ol.Feature({
                geometry: new ol.geom.Point(
                    [
                        params.mapCenter[0] + Math.random() * 0.01 - .005,
                        params.mapCenter[1] + Math.random() * 0.01 - .005
                    ]
                ),
                value: Math.round(Math.random() * params.maxValue)
            });
            feature.setStyle(new ol.style.Style({
                image: new ol.style.Circle({
                    radius: 6,
                    fill: new ol.style.Fill({ color: "#00F" })
                })
            }));
            WFSVectorSource.addFeature(feature);
        }

   
        //设置框选事件
        let selectedFeatures = select.getFeatures();
        dragBox.on('boxend', () => {
            let extent = dragBox.getGeometry().getExtent();
            WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
                selectedFeatures.push(feature);
            });
            drawKriging(extent);
        });
        dragBox.on('boxstart', () => {
            selectedFeatures.clear();
        });

        //利用网格计算点集
        const gridFeatureCollection = function (grid, xlim, ylim) {
            var range =grid.zlim[1] - grid.zlim[0];
            var i, j, x, y, z;
            var n = grid.length;//列数
            var m = grid[0].length;//行数
            var pointArray = [];
            for (i = 0; i < n ; i++)
                for (j = 0; j < m ; j++) {
                    x = (i) * grid.width + grid.xlim[0];
                    y = (j) * grid.width + grid.ylim[0];
                    z = (grid[i][j] - grid.zlim[0]) / range;
                    if (z < 0.0) z = 0.0;
                    if (z > 1.0) z = 1.0;
                    pointArray.push(turf.point([x, y], { value: z }));
                }
            return pointArray;
        }
        //绘制kriging插值图
        let vectorLayer = null;
        const drawKriging = (extent) => {
            let values = [], lngs = [], lats = [];
            selectedFeatures.forEach(feature => {
                values.push(feature.values_.value);
                lngs.push(feature.values_.geometry.flatCoordinates[0]);
                lats.push(feature.values_.geometry.flatCoordinates[1]);
            });
            if (values.length > 3) {
                let variogram = kriging.train(
                    values,
                    lngs,
                    lats,
                    params.krigingModel,
                    params.krigingSigma2,
                    params.krigingAlpha
                );
                let polygons = [];
                polygons.push([
                    [extent[0], extent[1]], [extent[0], extent[3]],
                    [extent[2], extent[3]], [extent[2], extent[1]]
                ]);
                let grid = kriging.grid(polygons, variogram, (extent[2] - extent[0]) / 500);
                let dragboxExtent = extent;

                if (vectorLayer !== null) {
                    map.removeLayer(vectorLayer);
                }
                var vectorSource = new ol.source.Vector();
                vectorLayer = new ol.layer.Vector(
                    {
                        source: vectorSource,
                        opacity: 0.7,
                        style: function (feature) {
                            
                            var style = new ol.style.Style({
                                fill: new ol.style.Fill({
                                    color: params.colors[parseFloat(feature.get('value').split('-')[1]) * 10]
                                })
                            })
                            return style;
                        }
                    }
                )
                //使用turf渲染等值面/线
                let fc = gridFeatureCollection(grid,
                    [extent[0], extent[2]], [extent[1], extent[3]]);
                var collection = turf.featureCollection(fc);
                var breaks = [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0];
                var isobands = turf.isobands(collection, breaks, { zProperty: 'value' });
                function sortArea(a,b)
                {
                    return turf.area(b)-turf.area(a);
                }
                //按照面积对图层进行排序,规避turf的一个bug
                isobands.features.sort(sortArea)
                var polyFeatures = new ol.format.GeoJSON().readFeatures(isobands, {
                    featureProjection: 'EPSG:4326'
                })
                vectorSource.addFeatures(polyFeatures);

                map.addLayer(vectorLayer);
            } else {
                alert("有效样点个数不足,无法插值");
            }
        }

        let extent = [params.mapCenter[0] - .005, params.mapCenter[1] - .005, params.mapCenter[0] + .005, params.mapCenter[1] + .005];
        WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
            selectedFeatures.push(feature);
        });
        drawKriging(extent);
    </script>
</body>

</html>

再次对

Trojx

表示敬意,感谢他之前创造性的工作。

  • 18
    点赞
  • 49
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 30
    评论
评论 30
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

战斗中的老胡

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值