四葉小天使!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
// 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中全部方法的定義。
當渲染錯誤時,調用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