CesiumWidget.js 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641
  1. /*global define,console*/
  2. define([
  3. '../../Core/buildModuleUrl',
  4. '../../Core/Cartesian3',
  5. '../../Core/Clock',
  6. '../../Core/Credit',
  7. '../../Core/defaultValue',
  8. '../../Core/defined',
  9. '../../Core/defineProperties',
  10. '../../Core/destroyObject',
  11. '../../Core/DeveloperError',
  12. '../../Core/Ellipsoid',
  13. '../../Core/formatError',
  14. '../../Core/requestAnimationFrame',
  15. '../../Core/ScreenSpaceEventHandler',
  16. '../../Scene/BingMapsImageryProvider',
  17. '../../Scene/Globe',
  18. '../../Scene/Moon',
  19. '../../Scene/Scene',
  20. '../../Scene/SceneMode',
  21. '../../Scene/SkyAtmosphere',
  22. '../../Scene/SkyBox',
  23. '../../Scene/Sun',
  24. '../getElement'
  25. ], function(
  26. buildModuleUrl,
  27. Cartesian3,
  28. Clock,
  29. Credit,
  30. defaultValue,
  31. defined,
  32. defineProperties,
  33. destroyObject,
  34. DeveloperError,
  35. Ellipsoid,
  36. formatError,
  37. requestAnimationFrame,
  38. ScreenSpaceEventHandler,
  39. BingMapsImageryProvider,
  40. Globe,
  41. Moon,
  42. Scene,
  43. SceneMode,
  44. SkyAtmosphere,
  45. SkyBox,
  46. Sun,
  47. getElement) {
  48. "use strict";
  49. function getDefaultSkyBoxUrl(suffix) {
  50. return buildModuleUrl('Assets/Textures/SkyBox/tycho2t3_80_' + suffix + '.jpg');
  51. }
  52. function startRenderLoop(widget) {
  53. widget._renderLoopRunning = true;
  54. var lastFrameTime = 0;
  55. function render(frameTime) {
  56. if (widget.isDestroyed()) {
  57. return;
  58. }
  59. if (widget._useDefaultRenderLoop) {
  60. try {
  61. var targetFrameRate = widget._targetFrameRate;
  62. if (!defined(targetFrameRate)) {
  63. widget.resize();
  64. widget.render();
  65. requestAnimationFrame(render);
  66. } else {
  67. var interval = 1000.0 / targetFrameRate;
  68. var delta = frameTime - lastFrameTime;
  69. if (delta > interval) {
  70. widget.resize();
  71. widget.render();
  72. lastFrameTime = frameTime - (delta % interval);
  73. }
  74. requestAnimationFrame(render);
  75. }
  76. } catch (error) {
  77. widget._useDefaultRenderLoop = false;
  78. widget._renderLoopRunning = false;
  79. if (widget._showRenderLoopErrors) {
  80. var title = 'An error occurred while rendering. Rendering has stopped.';
  81. widget.showErrorPanel(title, undefined, error);
  82. }
  83. }
  84. } else {
  85. widget._renderLoopRunning = false;
  86. }
  87. }
  88. requestAnimationFrame(render);
  89. }
  90. function configureCanvasSize(widget) {
  91. var canvas = widget._canvas;
  92. var width = canvas.clientWidth;
  93. var height = canvas.clientHeight;
  94. var zoomFactor = defaultValue(window.devicePixelRatio, 1.0) * widget._resolutionScale;
  95. widget._canvasWidth = width;
  96. widget._canvasHeight = height;
  97. width *= zoomFactor;
  98. height *= zoomFactor;
  99. canvas.width = width;
  100. canvas.height = height;
  101. widget._canRender = width !== 0 && height !== 0;
  102. }
  103. function configureCameraFrustum(widget) {
  104. var canvas = widget._canvas;
  105. var width = canvas.width;
  106. var height = canvas.height;
  107. if (width !== 0 && height !== 0) {
  108. var frustum = widget._scene.camera.frustum;
  109. if (defined(frustum.aspectRatio)) {
  110. frustum.aspectRatio = width / height;
  111. } else {
  112. frustum.top = frustum.right * (height / width);
  113. frustum.bottom = -frustum.top;
  114. }
  115. }
  116. }
  117. var cesiumLogoData = 'data:image/png;base64,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';
  118. /**
  119. * A widget containing a Cesium scene.
  120. *
  121. * @alias CesiumWidget
  122. * @constructor
  123. *
  124. * @param {Element|String} container The DOM element or ID that will contain the widget.
  125. * @param {Object} [options] Object with the following properties:
  126. * @param {Clock} [options.clock=new Clock()] The clock to use to control current time.
  127. * @param {ImageryProvider} [options.imageryProvider=new BingMapsImageryProvider()] The imagery provider to serve as the base layer. If set to false, no imagery provider will be added.
  128. * @param {TerrainProvider} [options.terrainProvider=new EllipsoidTerrainProvider] The terrain provider.
  129. * @param {SkyBox} [options.skyBox] The skybox used to render the stars. When <code>undefined</code>, the default stars are used.
  130. * @param {SceneMode} [options.sceneMode=SceneMode.SCENE3D] The initial scene mode.
  131. * @param {Boolean} [options.scene3DOnly=false] When <code>true</code>, each geometry instance will only be rendered in 3D to save GPU memory.
  132. * @param {Boolean} [options.orderIndependentTranslucency=true] If true and the configuration supports it, use order independent translucency.
  133. * @param {MapProjection} [options.mapProjection=new GeographicProjection()] The map projection to use in 2D and Columbus View modes.
  134. * @param {Boolean} [options.useDefaultRenderLoop=true] True if this widget should control the render loop, false otherwise.
  135. * @param {Number} [options.targetFrameRate] The target frame rate when using the default render loop.
  136. * @param {Boolean} [options.showRenderLoopErrors=true] If true, this widget will automatically display an HTML panel to the user containing the error, if a render loop error occurs.
  137. * @param {Object} [options.contextOptions] Context and WebGL creation properties corresponding to <code>options</code> passed to {@link Scene}.
  138. * @param {Element|String} [options.creditContainer] The DOM element or ID that will contain the {@link CreditDisplay}. If not specified, the credits are added
  139. * to the bottom of the widget itself.
  140. *
  141. * @exception {DeveloperError} Element with id "container" does not exist in the document.
  142. *
  143. * @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Cesium%20Widget.html|Cesium Sandcastle Cesium Widget Demo}
  144. *
  145. * @example
  146. * // For each example, include a link to CesiumWidget.css stylesheet in HTML head,
  147. * // and in the body, include: <div id="cesiumContainer"></div>
  148. *
  149. * //Widget with no terrain and default Bing Maps imagery provider.
  150. * var widget = new Cesium.CesiumWidget('cesiumContainer');
  151. *
  152. * //Widget with OpenStreetMaps imagery provider and Cesium terrain provider hosted by AGI.
  153. * var widget = new Cesium.CesiumWidget('cesiumContainer', {
  154. * imageryProvider : new Cesium.OpenStreetMapImageryProvider(),
  155. * terrainProvider : new Cesium.CesiumTerrainProvider({
  156. * url : '//cesiumjs.org/smallterrain',
  157. * credit : 'Terrain data courtesy Analytical Graphics, Inc.'
  158. * }),
  159. * // Use high-res stars downloaded from https://github.com/AnalyticalGraphicsInc/cesium-assets
  160. * skyBox : new Cesium.SkyBox({
  161. * sources : {
  162. * positiveX : 'stars/TychoSkymapII.t3_08192x04096_80_px.jpg',
  163. * negativeX : 'stars/TychoSkymapII.t3_08192x04096_80_mx.jpg',
  164. * positiveY : 'stars/TychoSkymapII.t3_08192x04096_80_py.jpg',
  165. * negativeY : 'stars/TychoSkymapII.t3_08192x04096_80_my.jpg',
  166. * positiveZ : 'stars/TychoSkymapII.t3_08192x04096_80_pz.jpg',
  167. * negativeZ : 'stars/TychoSkymapII.t3_08192x04096_80_mz.jpg'
  168. * }
  169. * }),
  170. * // Show Columbus View map with Web Mercator projection
  171. * sceneMode : Cesium.SceneMode.COLUMBUS_VIEW,
  172. * mapProjection : new Cesium.WebMercatorProjection()
  173. * });
  174. */
  175. var CesiumWidget = function(container, options) {
  176. //>>includeStart('debug', pragmas.debug);
  177. if (!defined(container)) {
  178. throw new DeveloperError('container is required.');
  179. }
  180. //>>includeEnd('debug');
  181. container = getElement(container);
  182. options = defaultValue(options, {});
  183. //Configure the widget DOM elements
  184. var element = document.createElement('div');
  185. element.className = 'cesium-widget';
  186. container.appendChild(element);
  187. var canvas = document.createElement('canvas');
  188. canvas.oncontextmenu = function() {
  189. return false;
  190. };
  191. canvas.onselectstart = function() {
  192. return false;
  193. };
  194. element.appendChild(canvas);
  195. var creditContainer = document.createElement('div');
  196. creditContainer.className = 'cesium-widget-credits';
  197. var creditContainerContainer = defined(options.creditContainer) ? getElement(options.creditContainer) : element;
  198. creditContainerContainer.appendChild(creditContainer);
  199. this._element = element;
  200. this._container = container;
  201. this._canvas = canvas;
  202. this._canvasWidth = 0;
  203. this._canvasHeight = 0;
  204. this._creditContainer = creditContainer;
  205. this._canRender = false;
  206. this._renderLoopRunning = false;
  207. this._showRenderLoopErrors = defaultValue(options.showRenderLoopErrors, true);
  208. this._resolutionScale = 1.0;
  209. this._forceResize = false;
  210. this._clock = defined(options.clock) ? options.clock : new Clock();
  211. configureCanvasSize(this);
  212. try {
  213. var scene = new Scene({
  214. canvas : canvas,
  215. contextOptions : options.contextOptions,
  216. creditContainer : creditContainer,
  217. mapProjection : options.mapProjection,
  218. orderIndependentTranslucency : options.orderIndependentTranslucency,
  219. scene3DOnly : defaultValue(options.scene3DOnly, false)
  220. });
  221. this._scene = scene;
  222. scene.camera.constrainedAxis = Cartesian3.UNIT_Z;
  223. configureCameraFrustum(this);
  224. var ellipsoid = Ellipsoid.WGS84;
  225. var creditDisplay = scene.frameState.creditDisplay;
  226. var cesiumCredit = new Credit('Cesium', cesiumLogoData, 'http://cesiumjs.org/');
  227. creditDisplay.addDefaultCredit(cesiumCredit);
  228. var globe = new Globe(ellipsoid);
  229. this._globe = globe;
  230. scene.globe = globe;
  231. var skyBox = options.skyBox;
  232. if (!defined(skyBox)) {
  233. skyBox = new SkyBox({
  234. sources : {
  235. positiveX : getDefaultSkyBoxUrl('px'),
  236. negativeX : getDefaultSkyBoxUrl('mx'),
  237. positiveY : getDefaultSkyBoxUrl('py'),
  238. negativeY : getDefaultSkyBoxUrl('my'),
  239. positiveZ : getDefaultSkyBoxUrl('pz'),
  240. negativeZ : getDefaultSkyBoxUrl('mz')
  241. }
  242. });
  243. }
  244. scene.skyBox = skyBox;
  245. scene.skyAtmosphere = new SkyAtmosphere(ellipsoid);
  246. scene.sun = new Sun();
  247. scene.moon = new Moon();
  248. //Set the base imagery layer
  249. var imageryProvider = options.imageryProvider;
  250. if (!defined(imageryProvider)) {
  251. imageryProvider = new BingMapsImageryProvider({
  252. url : '//dev.virtualearth.net'
  253. });
  254. }
  255. if (imageryProvider !== false) {
  256. scene.imageryLayers.addImageryProvider(imageryProvider);
  257. }
  258. //Set the terrain provider if one is provided.
  259. if (defined(options.terrainProvider)) {
  260. scene.terrainProvider = options.terrainProvider;
  261. }
  262. this._screenSpaceEventHandler = new ScreenSpaceEventHandler(canvas);
  263. if (defined(options.sceneMode)) {
  264. if (options.sceneMode === SceneMode.SCENE2D) {
  265. this._scene.morphTo2D(0);
  266. }
  267. if (options.sceneMode === SceneMode.COLUMBUS_VIEW) {
  268. this._scene.morphToColumbusView(0);
  269. }
  270. }
  271. this._useDefaultRenderLoop = undefined;
  272. this.useDefaultRenderLoop = defaultValue(options.useDefaultRenderLoop, true);
  273. this._targetFrameRate = undefined;
  274. this.targetFrameRate = options.targetFrameRate;
  275. var that = this;
  276. scene.renderError.addEventListener(function(scene, error) {
  277. that._useDefaultRenderLoop = false;
  278. that._renderLoopRunning = false;
  279. if (that._showRenderLoopErrors) {
  280. var title = 'An error occurred while rendering. Rendering has stopped.';
  281. that.showErrorPanel(title, undefined, error);
  282. }
  283. });
  284. } catch (error) {
  285. var title = 'Error constructing CesiumWidget.';
  286. var message = 'Visit <a href="http://get.webgl.org">http://get.webgl.org</a> to verify that your web browser and hardware support WebGL. Consider trying a different web browser or updating your video drivers. Detailed error information is below:';
  287. this.showErrorPanel(title, message, error);
  288. throw error;
  289. }
  290. };
  291. defineProperties(CesiumWidget.prototype, {
  292. /**
  293. * Gets the parent container.
  294. * @memberof CesiumWidget.prototype
  295. *
  296. * @type {Element}
  297. */
  298. container : {
  299. get : function() {
  300. return this._container;
  301. }
  302. },
  303. /**
  304. * Gets the canvas.
  305. * @memberof CesiumWidget.prototype
  306. *
  307. * @type {Canvas}
  308. */
  309. canvas : {
  310. get : function() {
  311. return this._canvas;
  312. }
  313. },
  314. /**
  315. * Gets the credit container.
  316. * @memberof CesiumWidget.prototype
  317. *
  318. * @type {Element}
  319. */
  320. creditContainer: {
  321. get : function() {
  322. return this._creditContainer;
  323. }
  324. },
  325. /**
  326. * Gets the scene.
  327. * @memberof CesiumWidget.prototype
  328. *
  329. * @type {Scene}
  330. */
  331. scene : {
  332. get : function() {
  333. return this._scene;
  334. }
  335. },
  336. /**
  337. * Gets the collection of image layers that will be rendered on the globe.
  338. * @memberof Viewer.prototype
  339. *
  340. * @type {ImageryLayerCollection}
  341. * @readonly
  342. */
  343. imageryLayers : {
  344. get : function() {
  345. return this._scene.imageryLayers;
  346. }
  347. },
  348. /**
  349. * The terrain provider providing surface geometry for the globe.
  350. * @memberof CesiumWidget.prototype
  351. *
  352. * @type {TerrainProvider}
  353. */
  354. terrainProvider : {
  355. get : function() {
  356. return this._scene.terrainProvider;
  357. },
  358. set : function(terrainProvider) {
  359. this._scene.terrainProvider = terrainProvider;
  360. }
  361. },
  362. /**
  363. * Gets the camera.
  364. * @memberof CesiumWidget.prototype
  365. *
  366. * @type {Camera}
  367. * @readonly
  368. */
  369. camera : {
  370. get : function() {
  371. return this._scene.camera;
  372. }
  373. },
  374. /**
  375. * Gets the clock.
  376. * @memberof CesiumWidget.prototype
  377. *
  378. * @type {Clock}
  379. */
  380. clock : {
  381. get : function() {
  382. return this._clock;
  383. }
  384. },
  385. /**
  386. * Gets the screen space event handler.
  387. * @memberof CesiumWidget.prototype
  388. *
  389. * @type {ScreenSpaceEventHandler}
  390. */
  391. screenSpaceEventHandler : {
  392. get : function() {
  393. return this._screenSpaceEventHandler;
  394. }
  395. },
  396. /**
  397. * Gets or sets the target frame rate of the widget when <code>useDefaultRenderLoop</code>
  398. * is true. If undefined, the browser's {@link requestAnimationFrame} implementation
  399. * determines the frame rate. This value must be greater than 0 and a value higher than
  400. * the underlying requestAnimationFrame implementatin will have no affect.
  401. * @memberof CesiumWidget.prototype
  402. *
  403. * @type {Number}
  404. */
  405. targetFrameRate : {
  406. get : function() {
  407. return this._targetFrameRate;
  408. },
  409. set : function(value) {
  410. if (value <= 0) {
  411. throw new DeveloperError('targetFrameRate must be greater than 0.');
  412. }
  413. this._targetFrameRate = value;
  414. }
  415. },
  416. /**
  417. * Gets or sets whether or not this widget should control the render loop.
  418. * If set to true the widget will use {@link requestAnimationFrame} to
  419. * perform rendering and resizing of the widget, as well as drive the
  420. * simulation clock. If set to false, you must manually call the
  421. * <code>resize</code>, <code>render</code> methods as part of a custom
  422. * render loop. If an error occurs during rendering, {@link Scene}'s
  423. * <code>renderError</code> event will be raised and this property
  424. * will be set to false. It must be set back to true to continue rendering
  425. * after the error.
  426. * @memberof CesiumWidget.prototype
  427. *
  428. * @type {Boolean}
  429. */
  430. useDefaultRenderLoop : {
  431. get : function() {
  432. return this._useDefaultRenderLoop;
  433. },
  434. set : function(value) {
  435. if (this._useDefaultRenderLoop !== value) {
  436. this._useDefaultRenderLoop = value;
  437. if (value && !this._renderLoopRunning) {
  438. startRenderLoop(this);
  439. }
  440. }
  441. }
  442. },
  443. /**
  444. * Gets or sets a scaling factor for rendering resolution. Values less than 1.0 can improve
  445. * performance on less powerful devices while values greater than 1.0 will render at a higher
  446. * resolution and then scale down, resulting in improved visual fidelity.
  447. * For example, if the widget is laid out at a size of 640x480, setting this value to 0.5
  448. * will cause the scene to be rendered at 320x240 and then scaled up while setting
  449. * it to 2.0 will cause the scene to be rendered at 1280x960 and then scaled down.
  450. * @memberof CesiumWidget.prototype
  451. *
  452. * @type {Number}
  453. * @default 1.0
  454. */
  455. resolutionScale : {
  456. get : function() {
  457. return this._resolutionScale;
  458. },
  459. set : function(value) {
  460. if (value <= 0) {
  461. throw new DeveloperError('resolutionScale must be greater than 0.');
  462. }
  463. this._resolutionScale = value;
  464. this._forceResize = true;
  465. }
  466. }
  467. });
  468. /**
  469. * Show an error panel to the user containing a title and a longer error message,
  470. * which can be dismissed using an OK button. This panel is displayed automatically
  471. * when a render loop error occurs, if showRenderLoopErrors was not false when the
  472. * widget was constructed.
  473. *
  474. * @param {String} title The title to be displayed on the error panel. This string is interpreted as text.
  475. * @param {String} message A helpful, user-facing message to display prior to the detailed error information. This string is interpreted as HTML.
  476. * @param {String} [error] The error to be displayed on the error panel. This string is formatted using {@link formatError} and then displayed as text.
  477. */
  478. CesiumWidget.prototype.showErrorPanel = function(title, message, error) {
  479. var element = this._element;
  480. var overlay = document.createElement('div');
  481. overlay.className = 'cesium-widget-errorPanel';
  482. var content = document.createElement('div');
  483. content.className = 'cesium-widget-errorPanel-content';
  484. overlay.appendChild(content);
  485. var errorHeader = document.createElement('div');
  486. errorHeader.className = 'cesium-widget-errorPanel-header';
  487. errorHeader.appendChild(document.createTextNode(title));
  488. content.appendChild(errorHeader);
  489. var errorPanelScroller = document.createElement('div');
  490. errorPanelScroller.className = 'cesium-widget-errorPanel-scroll';
  491. content.appendChild(errorPanelScroller);
  492. var resizeCallback = function() {
  493. errorPanelScroller.style.maxHeight = Math.max(Math.round(element.clientHeight * 0.9 - 100), 30) + 'px';
  494. };
  495. resizeCallback();
  496. if (defined(window.addEventListener)) {
  497. window.addEventListener('resize', resizeCallback, false);
  498. }
  499. if (defined(message)) {
  500. var errorMessage = document.createElement('div');
  501. errorMessage.className = 'cesium-widget-errorPanel-message';
  502. errorMessage.innerHTML = '<p>' + message + '</p>';
  503. errorPanelScroller.appendChild(errorMessage);
  504. }
  505. var errorDetails = '(no error details available)';
  506. if (defined(error)) {
  507. errorDetails = formatError(error);
  508. }
  509. var errorMessageDetails = document.createElement('div');
  510. errorMessageDetails.className = 'cesium-widget-errorPanel-message';
  511. errorMessageDetails.appendChild(document.createTextNode(errorDetails));
  512. errorPanelScroller.appendChild(errorMessageDetails);
  513. var buttonPanel = document.createElement('div');
  514. buttonPanel.className = 'cesium-widget-errorPanel-buttonPanel';
  515. content.appendChild(buttonPanel);
  516. var okButton = document.createElement('button');
  517. okButton.setAttribute('type', 'button');
  518. okButton.className = 'cesium-button';
  519. okButton.appendChild(document.createTextNode('OK'));
  520. okButton.onclick = function() {
  521. if (defined(resizeCallback) && defined(window.removeEventListener)) {
  522. window.removeEventListener('resize', resizeCallback, false);
  523. }
  524. element.removeChild(overlay);
  525. };
  526. buttonPanel.appendChild(okButton);
  527. element.appendChild(overlay);
  528. console.error(title + '\n' + message + '\n' + errorDetails);
  529. };
  530. /**
  531. * @returns {Boolean} true if the object has been destroyed, false otherwise.
  532. */
  533. CesiumWidget.prototype.isDestroyed = function() {
  534. return false;
  535. };
  536. /**
  537. * Destroys the widget. Should be called if permanently
  538. * removing the widget from layout.
  539. */
  540. CesiumWidget.prototype.destroy = function() {
  541. this._scene = this._scene && this._scene.destroy();
  542. this._container.removeChild(this._element);
  543. destroyObject(this);
  544. };
  545. /**
  546. * Updates the canvas size, camera aspect ratio, and viewport size.
  547. * This function is called automatically as needed unless
  548. * <code>useDefaultRenderLoop</code> is set to false.
  549. */
  550. CesiumWidget.prototype.resize = function() {
  551. var canvas = this._canvas;
  552. var width = canvas.clientWidth;
  553. var height = canvas.clientHeight;
  554. if (!this._forceResize && this._canvasWidth === width && this._canvasHeight === height) {
  555. return;
  556. }
  557. this._forceResize = false;
  558. configureCanvasSize(this);
  559. configureCameraFrustum(this);
  560. };
  561. /**
  562. * Renders the scene. This function is called automatically
  563. * unless <code>useDefaultRenderLoop</code> is set to false;
  564. */
  565. CesiumWidget.prototype.render = function() {
  566. this._scene.initializeFrame();
  567. var currentTime = this._clock.tick();
  568. if (this._canRender) {
  569. this._scene.render(currentTime);
  570. }
  571. };
  572. return CesiumWidget;
  573. });