Cesium 源碼筆記[2] CesiumWidget模塊的實例化過程 ver1.67

四葉小天使!html

上承

CesiumWidget實際上和Viewer差很少。如下兩句代碼用於初始化,效果是差很少的。canvas

const widget = new Cesium.CesiumWidget('id選擇器')
const viewer = new Cesium.Viewer('id選擇器')

實例化Viewer一定會實例化一個CesiumWidget。CesiumWidget實際上表明的是三維數據可視區域,而Viewer除了包括可視區域,還包括各類控件(時間軸、右上角各類按鈕、搜索框、時間撥盤等),更像是一個整體承載容器。Viewer能經過extend()方法擴充自定義的控件。設計模式

真正使用WebGL繪圖的,還不是CesiumWidget模塊,而是在CesiumWidget中實例化的Scene模塊。app

不過,CesiumWidget起了一個橋樑的做用,它將構造時傳遞的DOM元素(或ID選擇器)再內嵌了一個canvas元素,再將此canvas元素傳遞給Scene,讓Scene接着繪圖。dom

比較Viewer和CesiumWidget和Scene分別做用的DOM元素,用一張圖表示:
ide

構造原理

DOM構造

// function CesiumWidget(container, options)構造函數內,第180~207行
if (!defined(container)) {
    throw new DeveloperError('container is required.');
}
container = getElement(container);
options = defaultValue(options, defaultValue.EMPTY_OBJECT);

var element = document.createElement('div');
element.className = 'cesium-widget';
container.appendChild(element);
// ...
var canvas = document.createElement('canvas');
// ...
element.appendChild(canvas);

我忽略了一些內容。這不到30行代碼,完成了上級Viewer的DOM元素判斷,完成了本級DOM元素建立,並完成了下一級DOM元素——canvas的建立,判斷了傳遞進來的options參數是否爲空。函數

關於下一級DOM元素canvas,還配置了一些HTML相關的事件、配置等,不詳細展開了。oop

這樣,DOM的層級關係就製造完畢了。ui

接下來還有一些其餘的小部件(例如商標版權等)以及分辨率等設置,位於209~219行。this

221~238行,將CesiumWidget的私有變量賦值完畢,並調用configureCanvasSize()來調整canvas的尺寸。

場景及有關對象構造

在240~349行,是一個大大的try/catch塊,CesiumWidget模塊的構造函數這部分代碼,完成了Scene、Globe、SkyBox、SkyAtmosphere模塊的實例化。

而最終暴露到CesiumWidget的API中的,有camera、scene、imageryLayers、terrainProvider、screenSpaceEventHandler、clock這幾個主要的對象。

這讓我十分鬱悶的事情來了,某個模塊的屬性(例如CesiumWidget的屬性——camera)並非它原型上的,而是這個模塊的別的屬性的原型上的(camera屬性實際上是屬於Scene模塊的)。不理解Js原型的同窗能夠理解爲Java的類,原型是Js(ES5)實現面向對象的一個重要設計模式。

從如下代碼能夠看到:

// CesiumWidget.js模塊
Object.defineProperties(CesiumWidget.prototype, {
    // ...
    camera : { // 449行
        get : function() {
            return this._scene.camera;
        }
    },
    // ...
}

這種設計在Cesium的API中很是常見,原理歸原理,API歸API。想要弄清楚誰是誰的崽兒(Scene.camera),而不是被誰撫養的(CesiumWidget.camera),只能經過源碼來知曉。

迴歸正題。

// CesiumWidget.js,241~255行
var scene = new Scene({
    canvas : canvas,
    contextOptions : options.contextOptions,
    creditContainer : innerCreditContainer,
    creditViewport: creditViewport,
    mapProjection : options.mapProjection,
    // 太長了不貼了
    // ...
});
this._scene = scene;

實例化Scene對象,傳遞主要的構造參數,大部分來自CesiumWidget的構造參數options中。

// CesiumWidget.js,257~260行
scene.camera.constrainedAxis = Cartesian3.UNIT_Z;

configurePixelRatio(this);
configureCameraFrustum(this);

指定攝像機的約束軸爲Z軸,觸發私有函數調整像素比例和攝像機視錐體。

// CesiumWidget.js,262~271行
var ellipsoid = defaultValue(scene.mapProjection.ellipsoid, Ellipsoid.WGS84);

var globe = options.globe;
if (!defined(globe)) {
    globe = new Globe(ellipsoid);
}
if (globe !== false) {
    scene.globe = globe;
    scene.globe.shadows = defaultValue(options.terrainShadows, ShadowMode.RECEIVE_ONLY);
}

建立ellipsoid和globe,並傳遞給scene.

273~299行建立環境因素,主要是天空盒和太陽、月亮、大氣環境。

302~314行建立影像數據源(若無,則調用createWorldImagery模塊建立世界影像,和CesiumION的token有關)和地形數據源,並傳遞給scene。影像數據源和地形數據源都可以從options中獲取,若options沒有,則使用Cesium官方給的,須要注意token問題。

318~325行肯定scene對象的視圖模式是二維的、三維的仍是哥倫布的(2.5D)。

316,333~341行給scene綁定了渲染錯誤事件處理函數。

327~331行,肯定了是否使用默認的循環渲染機制(useDefaultRenderLoop屬性),這個屬性若爲false,則須要手動調用CesiumWidget.render()渲染。還肯定了在默認循環渲染機制時,目標幀速率(targetFrameRate屬性)。

原型上的屬性定義

// CesiumWidget.js,352~581行
Object.defineProperties(CesiumWidget.prototype, {
    container : {
        get : function() {
            return this._container;
        }
    },
    // ...
    // 太長不貼了
}

API文檔中能看到的CesiumWidget的屬性,均在此定義了,使用的是Object.defineProperties()方法。

原型上的方法定義

CesiumWidget.js中593~708行,是CesiumWidget的API中全部方法的定義。

  • CesiumWidget.prototype.showErrorPanel = function(title, message, error) {...}
  • CesiumWidget.prototype.isDestroyed = function() {...}
  • CesiumWidget.prototype.destroy = function() {...}
  • CesiumWidget.prototype.resize = function() {...}
  • CesiumWidget.prototype.render = function() {...}

當渲染錯誤時,調用showErrorPanel方法,彈出個對話框。

若是CesiumWidget被銷燬了,調用isDestroyed方法返回的是true。

destroy()方法用於須要銷燬整個視圖時。

當窗口大小發生變化時,調用resize方法調整canvas和camera。

render方法是自動調用的,一般不須要開發者關心,除非設置CesiumWidget.useDefaultRenderLoop爲false。這個方法是用來渲染場景的。

導出模塊

最後在709行,導出此模塊。

// CesiumWidget.js,709行
export default CesiumWidget;

版權全部。轉載請聯繫我,B站/知乎/小專欄/博客園/CSDN @秋意正寒
http://www.javashuo.com/article/p-yapleysq-kp.html

相關文章
相關標籤/搜索