专栏首页跟牛老师一起学WEBGISOl4网格生成以及优化

Ol4网格生成以及优化

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/GISShiXiSheng/article/details/103050052

概述

先描述一下大致场景:以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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Arcgis for js实现北京地铁的展示

    在chrom中输入地址http://map.baidu.com/subways/index.html?c=beijing

    lzugis
  • mapboxGL之风流图

    前面的文章说到了Openlayers4中风场的实现,本文将讲述如何在mapbox GL实现类似的效果。

    lzugis
  • 将数据压缩到图片并在前端做解析渲染

    在做前后端数据交互的时候,你一定遇到过这样的问题:数据量大,尤其是在气象行业!在本文,讲解一种将数据压缩到图片并在前端实现数据的解析与展示的功能。

    lzugis
  • 批量导出某个简书用户的所有文章列表和文章超链接

    虽然简书提供了批量下载文章的功能,但是下载到本地的文章都是markdown格式的,不包含文章的链接,这不满足我的需求。

    Jerry Wang
  • [前端]使用曲线将多点连成一条平滑的曲线

    之前在写一个项目需要把多点连成平滑的曲线,而且这些点是无法预知的。开始想到用贝塞尔曲线,但是具体贝塞尔曲线的控制点要怎么设定,怎样让多点都落在曲线上而且保持曲线...

    Tuzei
  • 在 Silverlight 5 项目中使用 async/await

    .Net 4.5 提供了 async/await 让异步编程回归同步, 不过, async/await 不是只能在 .Net 4.5 下才能使用, 通过使用 A...

    beginor
  • Nodejs进阶:Express常用中间件body-parser实现解析

    body-parser是非常常用的一个express中间件,作用是对post请求的请求体进行解析。使用非常简单,以下两行代码已经覆盖了大部分的使用场景。

    IMWeb前端团队
  • 文史上最骚的编程语言来了!大四学生发明言文编程语言!秀的我头皮发麻

    到底是什么神仙项目,竟然获得如此高的评价?原来,这是一位卡内基梅隆大学(CMU)的大四学生开发的基于文言文的编程语言。

    Guide哥
  • JDK10的新特性:本地变量类型var

    java以面向对象的特性显著于世并得到了蓬勃的发展。在语言的发展过程中,为了让java语言更加简洁和方便使用,JDK也在不断的进行改进。

    程序那些事
  • Js基础教程之变量及数据类型

    基本类型:字符串(String)、数字(Number)、布尔(Boolean)、对空(Null)、未定义(Undefined)、Symbol。

    老雷PHP全栈开发

扫码关注云+社区

领取腾讯云代金券