使用 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 對象,一定要保持深度思考的習慣,凡事不能只看到表面,應該多一些深入的思考。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章