zoukankan      html  css  js  c++  java
  • 使用 Cesium 动态加载 GeoJSON 数据

    前言

    需求是这样的,我需要在地图中显示 08 年到现在的地震情况,地震都是发生在具体的时间点的,那么问题就来了,如何实现地震情况按照时间动态渲染而不是一次全部加载出来。

    一、 方案分析

    这里面牵扯到两个问题:第一个是如何加载 GeoJSON 格式的数据,其实也就是矢量数据,因为矢量数据之间是可以任意转换的;第二个是如何让加载的数据根据自身的时间显示。

    所以就有两种解决问题的思路了:第一种,一次加载 GeoJSON 中所有数据,然后逐个设置显示时间;第二种,逐个加载 GeoJSON 中数据,并设置每个对象的显示时间。

    下面我们就一步步来实现解决方案。

    二、 解决方案

    先来看一下整体效果:

    2.1 加载 GeoJSON 数据

    Cesium基础使用介绍一文中已经介绍了如何加载多种格式矢量数据,加载 GeoJSON 数据已经写出了两种方式,第一种是整体读取的,明显无法满足我们的需求,那么就只能寻求第二种方式了:

    Cesium.GeoJsonDataSource.load('data/earthquake.geojson').then(function(dataSource) {
        viewer.dataSources.add(dataSource);
    
        var entities = dataSource.entities.values;
    
        for (var i = 0; i < entities.length; i++) {
            var entity = entities[i];
            entity.billboard = undefined;
            entity.point = new Cesium.PointGraphics({
                color: Cesium.Color.RED,
                pixelSize: 10
            });
        }
    });
    

    这里需要注意一个细节,地震数据为点状数据,需要先设置 entity.billboard = undefined,而后再设置 entity.point 来显示点状元素,否则会显示一个图标而不是点。

    这样看上去是逐一添加了点状元素,但是我们的问题并没有解决,所有地震点还是全部显示出来了,并没有按照时间显示。

    2.2 空间对象按照时间显示

    查阅了很多资料,发现可以通过设置对象的 availability 属性来控制对象的显示时间,这正是我需要的,于是修改如下:

        Cesium.GeoJsonDataSource.load('data/earthquake.geojson').then(function(dataSource) {
            viewer.dataSources.add(dataSource);
    
            var entities = dataSource.entities.values; 
    
            for (var i = 0; i < entities.length; i++) {
                var entity = entities[i];
                entity.billboard = undefined;
                entity.point = new Cesium.PointGraphics({
                    color: Cesium.Color.RED,
                    pixelSize: 10
                });
                entity.availability = new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
                    start: Cesium.JulianDate.fromIso8601(entity.properties.date),
                    stop: addDay(Cesium.JulianDate.fromIso8601(entity.properties.date))
                })]);
            }
        });
    });
    

    可以看到只是多加了 entity.availability = ... 一项,这样就能够按照时间显示,主要是其中的 start 和 stop 属性,控制显示的时间范围。date 是 GeoJSON 中数据的一个字段,格式为 '2008-01-01',当然你也可以使用其他格式,在此处进行自定义处理即可,addDay 用于控制显示一天,此处不用多考虑。

    2.3 GeoJSON 的另外一种读取方式

    写到这里问题已经解决了,但是这里再说一个小插曲。刚开始的时候我将 availability 属性直接写到了 point 里,无法得到结果,于是怀疑是此方法走不通,又思考和搜索了片刻,找到了另一种读取 GeoJSON 的方法,如下:

    Cesium.loadJson('data/boundary/earthquake.geojson').then(function(jsonData) {
        for (var i =0 ;i<=jsonData.features.length; i++) {
            var ifeature = jsonData.features[i];
            viewer.entities.add({
                position: Cesium.Cartesian3.fromDegrees(ifeature.geometry.coordinates[0], ifeature.geometry.coordinates[1]),
                availability: new Cesium.TimeIntervalCollection([new Cesium.TimeInterval({
                    start: Cesium.JulianDate.fromIso8601(ifeature.properties.date),
                    stop: addDay(Cesium.JulianDate.fromIso8601(ifeature.properties.date))
                })]),
                point: {
                    pixelSize: 10,
                    color: Cesium.Color.RED
                }
            });
        }
    });
    
    

    这同样能达到效果,这就是刚开始讨论时描述的逐个读取数据,这与前一种方式不同的是此处读取到的是逐个的 feature 对象(前一种直接读取 entity 对象),根据 feature 生成 entity 对象,再使用 viewer.entities.add 将对象添加到场景中,每个对象单独根据时间设置 availability 属性,这样同样达到了效果。

    当此种方式达到效果的时候,再回头来看第一种方式豁然开朗,读取到的 entity 就是一个真实的 entity 对象,于是将 availability 从 point 中移出到外面便达到了效果。

    2.4 问题分析

    两种方式都能达到效果,而我在刚开始的时候对细节、对 cesium 的各个对象并没有理解的那么透彻,只是看到了表面现象,当研究的稍微深入的时候对整个 cesium 框架也就有了更多的理解,于是条条道路通罗马。

    三、 总结

    本文简单介绍了如何动态的根据时间加载 GeoJSON 对象,一定要保持深度思考的习惯,凡事不能只看到表面,应该多一些深入的思考。

  • 相关阅读:
    【转载】make: Nothing to be done for `all'. 解决方法
    P4行为模型BMV2安装
    P4行为模型BMV2依赖关系安装:thrift nanomsg nnpy安装
    P4factory ReadMe 剩余部分
    P4factory ReadMe Quickstart 安装p4factory
    Git 使用ssh密钥
    c++ 有swap函数
    c++ 引用
    topk两种解法
    xgboost和gbdt区别
  • 原文地址:https://www.cnblogs.com/shoufengwei/p/8883013.html
Copyright © 2011-2022 走看看