1. 程式人生 > >Cesium 原始碼筆記[1] Viewer模組例項化的大致過程

Cesium 原始碼筆記[1] Viewer模組例項化的大致過程

> 我原本想寫日記的,但是不太現實。 # 原始碼下載 原始碼可以從原始碼包和發行包中的Source目錄中獲取。 Cesium的模組化機制從1.63版本開始,由原來的RequireJs變為ES6。但有可能是原先設計耦合的問題,內部依舊是ES5實現。 # 入口:例項化Viewer時到底發生了什麼 寫Cesium程式時,都寫過這一句: ``` JS let viewer = new Cesium.Viewer(dom) ``` 或者這樣 ``` JS let viewer = new Cesium.Viewer(dom, { terrainProvider: Cesium.createWorldTerrain() }) ``` 那它究竟在後面發生了什麼呢? # Viewer.js 定位到302行,Viewer的建構函式如下: ``` JS function Viewer(container, options) { ... } ``` 就從這個長達400多行的建構函式看起吧! ``` JS // 304~309行 if (!defined(container)) { throw new DeveloperError('container is required.'); } container = getElement(container); ``` 這一步,是看看DOM元素是否存在,使用getElement模組判斷是domID或者是DOM元素變數,並返回。 ## 工具模組:defaultValue ``` JS // 310行 options = defaultValue(options, defaultValue.EMPTY_OBJECT); ``` 這一步是判斷傳進來的options物件是否為空,如果為空,那就使用空物件預設值(`defaultValue.EMPTY_OBJECT)`)。其中,`defaultValue`是一個重要的模組,它判斷第一個引數如果是undefined,就把第二個引數作為它的值返回,如果不是undefined,那就返回它本身。 ## 工具模組:defined ``` js // 312~313行 var createBaseLayerPicker = (!defined(options.globe) || options.globe !== false) && (!defined(options.baseLayerPicker) || options.baseLayerPicker !== false); ``` 這一步通過defined模組判斷構造引數options是否有globe屬性、baseLayerPicker屬性來決定是否建立底圖選擇器控制元件。defined模組的作用就是,判斷傳入值是否定義,定義了就返回true。 329行將Viewer例項的this變數賦予給that變數。 331~344行是Viewer檢視底下的一堆空間的div DOM元素建立。 346~362行,利用defaultValue模組和defined模組 - 判斷傳入引數options中scene3DOnly引數是否賦值,如果沒有則預設為false,即是否僅使用3d場景的意思; - 判斷傳入引數options中的時鐘模型屬性clockViewModel是否存在,來決定是用傳入的時鐘模型,亦或者是用系統的時鐘模型; - 判斷傳入引數options中是否定義了shouldAnimate屬性,如果定義了,則將時鐘的同名屬性設為同樣的值。 # 最初的一步: CesiumWidget建立 ``` JS // Cesium.js 364~388行 var cesiumWidget = new CesiumWidget(cesiumWidgetContainer, { imageryProvider: createBaseLayerPicker || defined(options.imageryProvider) ? false : undefined, clock : clock, skyBox : options.skyBox, skyAtmosphere : options.skyAtmosphere, sceneMode : options.sceneMode, mapProjection : options.mapProjection, globe : options.globe, // ... 太長了不貼了 }); ``` 這一步和建立Viewer很像,但是它卻更接近資料承載體一步。 為了保證單元的完整性,CesiumWidget的例項化,後面再說。提前透露:高頻API,Scene、imageryProvider、Globe等均在這一步繼續建立。 # 其他的初始化 390~615行,是對Viewer的一些其他屬性的初始化,分別是介面上的一眾按鈕、時間軸等控制元件的初始化,以及事件總管理者(EventHelper模組)的初始化、重要的DataSourceCollection/DataSourceDisplay的初始化。 在後面Viewer部分的筆記中,關於這些控制元件的初始化,還會繼續詳細展開。 DataSourceCollection/DataSourceDisplay屬於資料範圍,不列入Viewer部分的筆記中。 最後,將以上初始化的物件,全部註冊註冊為當前Viewer例項的屬性,並將其中一些物件例如dataSourceCollection的一些事件一併註冊到Viewer的原型上。 除了以上初始化之外,Cesium還預設為cesiumWidget註冊了螢幕操作事件的點選、雙擊事件,方便初始化完成後能通過點選來拾取場景中的Entity(場景Scene、實體Entity是資料範圍,不作詳細介紹了),這兩個事件使用cesiumWidget.screenSpaceEventHandler.setInputAction方法來註冊。這兩個事件位於建構函式的689~708行。 # 原型定義 ## 工具方法:Object.defineProperties 這幾乎是每一個Cesium模組都會做的一步,使用Object.defineProperties,為某個物件賦予某個屬性。 > 據說這個Object.defineProperties是近幾個版本才啟用的,之前js沒有這個方法時,是用Cesium.defineProperties的。 在Viewer.js模組中的711~1292行,官方為Viewer的原型定義了一大批屬性,包括上文提及的初始化的多個物件、事件等,還包括上文建立的各個初始化的物件的一些屬性快捷連線,以便能在Viewer例項上直接訪問其他模組的屬性。 例如你既能在Viewer上獲取camera,也能在Scene模組獲取camera,只不過Viewer上返回的camera也要先訪問scene罷了。 隨後,在1294~1523行和1724~1858行,為Viewer的原型定義了一堆API文件中能看到的公共方法;在1525~1703和1863~2056行為Viewer的原型定義了一堆私有方法。 # 匯出Viewer模組 最後,在2066行,使用es6語法匯出Viewer建構函式。 > 版權所有。轉載請聯絡我,B站/知乎/小專欄/部落格園/CSDN @秋意正寒 > https://www.cnblogs.com/onsummer/p/12571