Ol4網格生成以及優化

LZU-GIS發表於2020-02-11

概述

先描述一下大致場景:以0.05為單元格大小生成網格,並在地圖上繪製,繪製的時候需要區分海陸。本文以此需求為契機,簡單描述一下該需求的實現以及如何來優化。

效果

優化前
優化後

實現

優化前

  var source = new ol.source.Vector({
    features: []
  });
  var vector = new ol.layer.Vector({
    source: source,
    zIndex: 1,
    opacity: 0.65,
    style: styleFunction
  });
  map.addLayer(vector);

  var landData = format.readFeatures(chinaZone, options);
  landGeom = landData[0].getGeometry();
  
  function styleFunction(feat) {
    var i = feat.get("i"),
      j = feat.get("j"),
      isLand = feat.get("land");
    if(isLand) {
      var val = data[i][j];
      var color;
      if (val > 0.33 && val <= 0.66) {
        color = "orange";
      } else if (val > 0.66 && val <= 1) {
        color = "red";
      } else {
        color = 'yellow';
      }
      return new ol.style.Style({
        fill: new ol.style.Fill({
          color: color,
        })
      })
    }
  }

  function generateGrid() {
    var bound = $("#bound").val(),
      size = Number($("#size").val());
    var bounds = bound.split(",").map(Number);
    console.time('Time Test');
    createGrid(bounds, size);
    console.timeEnd('Time Test')
  }
  
  function isOnLand(coord) {
    var is = false;
    for(var i = 0;i<landData.length;i++){
      var geom = landData[i].getGeometry();
      if (geom.intersectsCoordinate(coord)) {
        is = true;
        break;
      }
    }
    return is;
  }

  function createGrid(bound, size) {
    var gridData = {
      type: "FeatureCollection",
      features: []
    };
    var deltaLon = bound[2] - bound[0],
      deltaLat = bound[3] - bound[1];
    var numLon, numLat;
    numLon = Math.ceil(deltaLon / size);
    numLat = Math.ceil(deltaLat/ size);
    var minLon = bound[0],
      maxLat = bound[3];
    for(var i = 0; i < numLat; i++) {
      var lat1 = maxLat - i * size,
        lat2 = maxLat - (i + 1) * size;
      var latC = (lat1 + lat2) / 2;
      data[i] = [];
      for(var j = 0; j < numLon; j++) {
        data[i][j] = Math.random();
        var lon1 = minLon + j * size,
          lon2 = minLon + (j + 1) * size;
        var lonC = (lon1 + lon2) / 2;
        var coord = ol.proj.fromLonLat([lonC, latC]);
        var prop = {
          i: i,
          j: j,
          land: isOnLand(coord)
        };
        // 網格面
        var featG = {
          "type":"Feature",
          "properties": prop,
          "geometry":{
            "type":"Polygon",
            "coordinates":[[
              [lon1, lat1],
              [lon2, lat1],
              [lon2, lat2],
              [lon1, lat2],
              [lon1, lat1]
            ]]
          }
        };
        gridData.features.push(featG);
      }
    }
    var gridFeatures = format.readFeatures(gridData, options);
    source.addFeatures(gridFeatures);
  }

優化後

  var source = new ol.source.Vector({
    features: []
  });
  var vector = new ol.layer.Vector({
    source: source,
    zIndex: 1,
    opacity: 0.65,
    style: styleFunction,
    renderMode: 'image'
  });
  map.addLayer(vector);

  var landData = format.readFeatures(chinaZone, options);
  landGeom = landData[0].getGeometry();

  function styleFunction(feat) {
    // i為lat,j為lon
    var i = feat.get("i"),
      j = feat.get("j"),
      land = feat.get("land");
    if(land) {
      var val = data[i][j];
      var color;
      if (val > 0.33 && val <= 0.66) {
        color = "orange";
      } else if (val > 0.66 && val <= 1) {
        color = "red";
      } else {
        color = 'yellow';
      }
      return new ol.style.Style({
        // stroke: new ol.style.Stroke({
        //   color: 'grey',
        //   width: 1
        // }),
        fill: new ol.style.Fill({
          color: color,
        })
      })
    }
  }

  function generateGrid() {
    var bound = $("#bound").val(),
      size = Number($("#size").val());
    var bounds = bound.split(",").map(Number);
    console.time('Time Test');
    createGrid(bounds, size);
    console.timeEnd('Time Test')
  }

  function isOnLand(coord) {
    return landGeom.intersectsCoordinate(coord);
  }

  /**
   * 建立網格
   * @param bound
   * @param size
   * @returns {{grid: {features: Array, type: string}, center: {features: Array, type: string}}}
   */
  function createGrid(bound, size) {
    var deltaLon = bound[2] - bound[0],
      deltaLat = bound[3] - bound[1];
    var numLat;
    numLat = Math.ceil(deltaLat / size);
    for (var i = 0; i < numLat; i++) {
      data[i] = [];
      getFeatures(bound, i, deltaLon, size)
        .then(res => {
          var json = {
            "type": "FeatureCollection",
            features: res
          };
          var features = format.readFeatures(json, options);
          source.addFeatures(features);
        })
    }
  }

  function getFeatures(bound, i, deltaLon, size) {
    var promise = new Promise(function(resolve, reject) {
      window.setTimeout(function() {
        var features = [];
        var minLon = bound[0],
          maxLat = bound[3],
          numLon = Math.ceil(deltaLon / size);

        var lat1 = maxLat - i * size,
          lat2 = maxLat - (i + 1) * size;
        var latC = (lat1 + lat2) / 2;
        for(var j = 0; j < numLon; j++) {
          var lon1 = minLon + j * size,
            lon2 = minLon + (j + 1) * size;
          var lonC = (lon1 + lon2) / 2;
          var coord = ol.proj.fromLonLat([lonC, latC]);
          var prop = {
            i: i,
            j: j,
            land: isOnLand(coord)
          };
          data[i][j] = Math.random();
          // 網格面
          var featG = {
            "type":"Feature",
            "properties": prop,
            "geometry":{
              "type":"Polygon",
              "coordinates":[[
                [lon1, lat1],
                [lon2, lat1],
                [lon2, lat2],
                [lon1, lat2],
                [lon1, lat1]
              ]]
            }
          };
          features.push(featG);
        }
        resolve(features);
      });
    });
    return promise;
  }

思路分析

通過前面的兩張圖可以明顯看出,優化前後效率上有了質的變化,這說明我們的優化思路是正確的。下面說一下我在做這部分優化的時候的思路:

1.找到原因

從本案例來看,能影響效率的有可能有兩點:1、js的for迴圈比較慢;2、渲染到地圖上的時候比較慢。於是就做了一下測試,發現原因其實是1,而不是2.

2.思考解決

既然找到了是1影響了效率,那就考慮如何優化1。在本案例中,第一層迴圈有200,第二層迴圈有140,由於js的執行是單執行緒順序執行的,所以我思考把這個迴圈拆開,拆成若干個迴圈,非同步執行,這樣就能避免同步執行慢的問題。因此,在優化的時候用了setTimeoutpromise來實現迴圈的非同步執行。

3. 其他

此外,在建立vectorLayer的時候,加入了renderMode: 'image'引數,提高渲染層面的效率。

思考優化

本案例其實還可以做進一步的優化,優化主要在渲染上,優化思路類似於地圖切片,將展示資料建立索引,並將展示結果進行分塊,以達到優化展示。


技術部落格
CSDN:http://blog.csdn.NET/gisshixisheng
線上教程
https://edu.csdn.net/course/detail/799
https://edu.csdn.net/course/detail/7471
聯絡方式

型別 內容
qq 1004740957
公眾號 lzugis15
e-mail niujp08@qq.com
webgis群 452117357
Android群 337469080
GIS資料視覺化群 458292378

LZUGIS

相關文章