Cesium3DTilesInspectorViewModel.js 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604
  1. import {
  2. Check,
  3. Color,
  4. defined,
  5. destroyObject,
  6. Cesium3DTileColorBlendMode,
  7. Cesium3DTileFeature,
  8. Cesium3DTilePass,
  9. Cesium3DTileset,
  10. Cesium3DTileStyle,
  11. PerformanceDisplay,
  12. ResourceCache,
  13. ScreenSpaceEventHandler,
  14. ScreenSpaceEventType,
  15. } from "@cesium/engine";
  16. import knockout from "../ThirdParty/knockout.js";
  17. function getPickTileset(viewModel) {
  18. return function (e) {
  19. const pick = viewModel._scene.pick(e.position);
  20. if (defined(pick) && pick.primitive instanceof Cesium3DTileset) {
  21. viewModel.tileset = pick.primitive;
  22. }
  23. viewModel.pickActive = false;
  24. };
  25. }
  26. function selectTilesetOnHover(viewModel, value) {
  27. if (value) {
  28. viewModel._eventHandler.setInputAction(function (e) {
  29. const pick = viewModel._scene.pick(e.endPosition);
  30. if (defined(pick) && pick.primitive instanceof Cesium3DTileset) {
  31. viewModel.tileset = pick.primitive;
  32. }
  33. }, ScreenSpaceEventType.MOUSE_MOVE);
  34. } else {
  35. viewModel._eventHandler.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE);
  36. // Restore hover-over selection to its current value
  37. // eslint-disable-next-line no-self-assign
  38. viewModel.picking = viewModel.picking;
  39. }
  40. }
  41. const stringOptions = {
  42. maximumFractionDigits: 3,
  43. };
  44. function formatMemoryString(memorySizeInBytes) {
  45. const memoryInMegabytes = memorySizeInBytes / 1048576;
  46. if (memoryInMegabytes < 1.0) {
  47. return memoryInMegabytes.toLocaleString(undefined, stringOptions);
  48. }
  49. return Math.round(memoryInMegabytes).toLocaleString();
  50. }
  51. function getStatistics(tileset, isPick) {
  52. if (!defined(tileset)) {
  53. return "";
  54. }
  55. const statistics = isPick
  56. ? tileset._statisticsPerPass[Cesium3DTilePass.PICK]
  57. : tileset._statisticsPerPass[Cesium3DTilePass.RENDER];
  58. // Since the pick pass uses a smaller frustum around the pixel of interest,
  59. // the statistics will be different than the normal render pass.
  60. let s = '<ul class="cesium-cesiumInspector-statistics">';
  61. s +=
  62. // --- Rendering statistics
  63. `<li><strong>Visited: </strong>${statistics.visited.toLocaleString()}</li>` +
  64. // Number of commands returned is likely to be higher than the number of tiles selected
  65. // because of tiles that create multiple commands.
  66. `<li><strong>Selected: </strong>${statistics.selected.toLocaleString()}</li>` +
  67. // Number of commands executed is likely to be higher because of commands overlapping
  68. // multiple frustums.
  69. `<li><strong>Commands: </strong>${statistics.numberOfCommands.toLocaleString()}</li>`;
  70. s += "</ul>";
  71. if (!isPick) {
  72. s += '<ul class="cesium-cesiumInspector-statistics">';
  73. s +=
  74. // --- Cache/loading statistics
  75. `<li><strong>Requests: </strong>${statistics.numberOfPendingRequests.toLocaleString()}</li>` +
  76. `<li><strong>Attempted: </strong>${statistics.numberOfAttemptedRequests.toLocaleString()}</li>` +
  77. `<li><strong>Processing: </strong>${statistics.numberOfTilesProcessing.toLocaleString()}</li>` +
  78. `<li><strong>Content Ready: </strong>${statistics.numberOfTilesWithContentReady.toLocaleString()}</li>` +
  79. // Total number of tiles includes tiles without content, so "Ready" may never reach
  80. // "Total." Total also will increase when a tile with a tileset JSON content is loaded.
  81. `<li><strong>Total: </strong>${statistics.numberOfTilesTotal.toLocaleString()}</li>`;
  82. s += "</ul>";
  83. s += '<ul class="cesium-cesiumInspector-statistics">';
  84. s +=
  85. // --- Features statistics
  86. `<li><strong>Features Selected: </strong>${statistics.numberOfFeaturesSelected.toLocaleString()}</li>` +
  87. `<li><strong>Features Loaded: </strong>${statistics.numberOfFeaturesLoaded.toLocaleString()}</li>` +
  88. `<li><strong>Points Selected: </strong>${statistics.numberOfPointsSelected.toLocaleString()}</li>` +
  89. `<li><strong>Points Loaded: </strong>${statistics.numberOfPointsLoaded.toLocaleString()}</li>` +
  90. `<li><strong>Triangles Selected: </strong>${statistics.numberOfTrianglesSelected.toLocaleString()}</li>`;
  91. s += "</ul>";
  92. s += '<ul class="cesium-cesiumInspector-statistics">';
  93. s +=
  94. // --- Styling statistics
  95. `<li><strong>Tiles styled: </strong>${statistics.numberOfTilesStyled.toLocaleString()}</li>` +
  96. `<li><strong>Features styled: </strong>${statistics.numberOfFeaturesStyled.toLocaleString()}</li>`;
  97. s += "</ul>";
  98. s += '<ul class="cesium-cesiumInspector-statistics">';
  99. s +=
  100. // --- Optimization statistics
  101. `<li><strong>Children Union Culled: </strong>${statistics.numberOfTilesCulledWithChildrenUnion.toLocaleString()}</li>`;
  102. s += "</ul>";
  103. s += '<ul class="cesium-cesiumInspector-statistics">';
  104. s +=
  105. // --- Memory statistics
  106. `<li><strong>Geometry Memory (MB): </strong>${formatMemoryString(
  107. statistics.geometryByteLength
  108. )}</li>` +
  109. `<li><strong>Texture Memory (MB): </strong>${formatMemoryString(
  110. statistics.texturesByteLength
  111. )}</li>` +
  112. `<li><strong>Batch Table Memory (MB): </strong>${formatMemoryString(
  113. statistics.batchTableByteLength
  114. )}</li>`;
  115. s += "</ul>";
  116. }
  117. return s;
  118. }
  119. function getResourceCacheStatistics() {
  120. const statistics = ResourceCache.statistics;
  121. return `
  122. <ul class="cesium-cesiumInspector-statistics">
  123. <li><strong>Geometry Memory (MB): </strong>${formatMemoryString(
  124. statistics.geometryByteLength
  125. )}</li>
  126. <li><strong>Texture Memory (MB): </strong>${formatMemoryString(
  127. statistics.texturesByteLength
  128. )}</li>
  129. </ul>
  130. `;
  131. }
  132. const colorBlendModes = [
  133. {
  134. text: "Highlight",
  135. value: Cesium3DTileColorBlendMode.HIGHLIGHT,
  136. },
  137. {
  138. text: "Replace",
  139. value: Cesium3DTileColorBlendMode.REPLACE,
  140. },
  141. {
  142. text: "Mix",
  143. value: Cesium3DTileColorBlendMode.MIX,
  144. },
  145. ];
  146. const highlightColor = new Color(1.0, 1.0, 0.0, 0.4);
  147. const scratchColor = new Color();
  148. const oldColor = new Color();
  149. /**
  150. * The view model for {@link Cesium3DTilesInspector}.
  151. * @alias Cesium3DTilesInspectorViewModel
  152. * @constructor
  153. *
  154. * @param {Scene} scene The scene instance to use.
  155. * @param {HTMLElement} performanceContainer The container for the performance display
  156. */
  157. function Cesium3DTilesInspectorViewModel(scene, performanceContainer) {
  158. //>>includeStart('debug', pragmas.debug);
  159. Check.typeOf.object("scene", scene);
  160. Check.typeOf.object("performanceContainer", performanceContainer);
  161. //>>includeEnd('debug');
  162. const that = this;
  163. const canvas = scene.canvas;
  164. this._eventHandler = new ScreenSpaceEventHandler(canvas);
  165. this._scene = scene;
  166. this._performanceContainer = performanceContainer;
  167. this._canvas = canvas;
  168. this._performanceDisplay = new PerformanceDisplay({
  169. container: performanceContainer,
  170. });
  171. this._statisticsText = "";
  172. this._pickStatisticsText = "";
  173. this._resourceCacheStatisticsText = "";
  174. this._editorError = "";
  175. /**
  176. * Gets or sets the flag to enable performance display. This property is observable.
  177. *
  178. * @type {boolean}
  179. * @default false
  180. */
  181. this.performance = false;
  182. /**
  183. * Gets or sets the flag to show statistics. This property is observable.
  184. *
  185. * @type {boolean}
  186. * @default true
  187. */
  188. this.showStatistics = true;
  189. /**
  190. * Gets or sets the flag to show pick statistics. This property is observable.
  191. *
  192. * @type {boolean}
  193. * @default true
  194. */
  195. this.showPickStatistics = true;
  196. /**
  197. * Gets or sets the flag to show resource cache statistics. This property is
  198. * observable.
  199. *
  200. * @type {boolean}
  201. * @default false
  202. */
  203. this.showResourceCacheStatistics = false;
  204. /**
  205. * Gets or sets the flag to show the inspector. This property is observable.
  206. *
  207. * @type {boolean}
  208. * @default true
  209. */
  210. this.inspectorVisible = true;
  211. /**
  212. * Gets or sets the flag to show the tileset section. This property is observable.
  213. *
  214. * @type {boolean}
  215. * @default false
  216. */
  217. this.tilesetVisible = false;
  218. /**
  219. * Gets or sets the flag to show the display section. This property is observable.
  220. *
  221. * @type {boolean}
  222. * @default false
  223. */
  224. this.displayVisible = false;
  225. /**
  226. * Gets or sets the flag to show the update section. This property is observable.
  227. *
  228. * @type {boolean}
  229. * @default false
  230. */
  231. this.updateVisible = false;
  232. /**
  233. * Gets or sets the flag to show the logging section. This property is observable.
  234. *
  235. * @type {boolean}
  236. * @default false
  237. */
  238. this.loggingVisible = false;
  239. /**
  240. * Gets or sets the flag to show the style section. This property is observable.
  241. *
  242. * @type {boolean}
  243. * @default false
  244. */
  245. this.styleVisible = false;
  246. /**
  247. * Gets or sets the flag to show the tile info section. This property is observable.
  248. *
  249. * @type {boolean}
  250. * @default false
  251. */
  252. this.tileDebugLabelsVisible = false;
  253. /**
  254. * Gets or sets the flag to show the optimization info section. This property is observable.
  255. *
  256. * @type {boolean}
  257. * @default false;
  258. */
  259. this.optimizationVisible = false;
  260. /**
  261. * Gets or sets the JSON for the tileset style. This property is observable.
  262. *
  263. * @type {string}
  264. * @default '{}'
  265. */
  266. this.styleString = "{}";
  267. /**
  268. * Gets or sets the JSON for the tileset enableDebugWireframe attribute. This property is observable.
  269. *
  270. * @type {boolean}
  271. * @default false
  272. */
  273. this.hasEnabledWireframe = false;
  274. this._tileset = undefined;
  275. this._feature = undefined;
  276. this._tile = undefined;
  277. knockout.track(this, [
  278. "performance",
  279. "inspectorVisible",
  280. "_statisticsText",
  281. "_pickStatisticsText",
  282. "_resourceCacheStatisticsText",
  283. "_editorError",
  284. "showPickStatistics",
  285. "showStatistics",
  286. "showResourceCacheStatistics",
  287. "tilesetVisible",
  288. "displayVisible",
  289. "updateVisible",
  290. "loggingVisible",
  291. "styleVisible",
  292. "optimizationVisible",
  293. "tileDebugLabelsVisible",
  294. "styleString",
  295. "_feature",
  296. "_tile",
  297. "_tileset",
  298. "hasEnabledWireframe",
  299. ]);
  300. this._properties = knockout.observable({});
  301. /**
  302. * Gets the names of the properties in the tileset. This property is observable.
  303. * @type {string[]}
  304. * @readonly
  305. */
  306. this.properties = [];
  307. knockout.defineProperty(this, "properties", function () {
  308. const names = [];
  309. const properties = that._properties();
  310. for (const prop in properties) {
  311. if (properties.hasOwnProperty(prop)) {
  312. names.push(prop);
  313. }
  314. }
  315. return names;
  316. });
  317. const dynamicScreenSpaceError = knockout.observable();
  318. knockout.defineProperty(this, "dynamicScreenSpaceError", {
  319. get: function () {
  320. return dynamicScreenSpaceError();
  321. },
  322. set: function (value) {
  323. dynamicScreenSpaceError(value);
  324. if (defined(that._tileset)) {
  325. that._tileset.dynamicScreenSpaceError = value;
  326. }
  327. },
  328. });
  329. /**
  330. * Gets or sets the flag to enable dynamic screen space error. This property is observable.
  331. *
  332. * @type {boolean}
  333. * @default false
  334. */
  335. this.dynamicScreenSpaceError = false;
  336. const colorBlendMode = knockout.observable();
  337. knockout.defineProperty(this, "colorBlendMode", {
  338. get: function () {
  339. return colorBlendMode();
  340. },
  341. set: function (value) {
  342. colorBlendMode(value);
  343. if (defined(that._tileset)) {
  344. that._tileset.colorBlendMode = value;
  345. that._scene.requestRender();
  346. }
  347. },
  348. });
  349. /**
  350. * Gets or sets the color blend mode. This property is observable.
  351. *
  352. * @type {Cesium3DTileColorBlendMode}
  353. * @default Cesium3DTileColorBlendMode.HIGHLIGHT
  354. */
  355. this.colorBlendMode = Cesium3DTileColorBlendMode.HIGHLIGHT;
  356. const showOnlyPickedTileDebugLabel = knockout.observable();
  357. const picking = knockout.observable();
  358. knockout.defineProperty(this, "picking", {
  359. get: function () {
  360. return picking();
  361. },
  362. set: function (value) {
  363. picking(value);
  364. if (value) {
  365. that._eventHandler.setInputAction(function (e) {
  366. const picked = scene.pick(e.endPosition);
  367. if (picked instanceof Cesium3DTileFeature) {
  368. // Picked a feature
  369. that.feature = picked;
  370. that.tile = picked.content.tile;
  371. } else if (defined(picked) && defined(picked.content)) {
  372. // Picked a tile
  373. that.feature = undefined;
  374. that.tile = picked.content.tile;
  375. } else {
  376. // Picked nothing
  377. that.feature = undefined;
  378. that.tile = undefined;
  379. }
  380. if (!defined(that._tileset)) {
  381. return;
  382. }
  383. if (
  384. showOnlyPickedTileDebugLabel &&
  385. defined(picked) &&
  386. defined(picked.content)
  387. ) {
  388. let position;
  389. if (scene.pickPositionSupported) {
  390. position = scene.pickPosition(e.endPosition);
  391. if (defined(position)) {
  392. that._tileset.debugPickPosition = position;
  393. }
  394. }
  395. that._tileset.debugPickedTile = picked.content.tile;
  396. } else {
  397. that._tileset.debugPickedTile = undefined;
  398. }
  399. that._scene.requestRender();
  400. }, ScreenSpaceEventType.MOUSE_MOVE);
  401. } else {
  402. that.feature = undefined;
  403. that.tile = undefined;
  404. that._eventHandler.removeInputAction(ScreenSpaceEventType.MOUSE_MOVE);
  405. }
  406. },
  407. });
  408. /**
  409. * Gets or sets the flag to enable picking. This property is observable.
  410. *
  411. * @type {boolean}
  412. * @default true
  413. */
  414. this.picking = true;
  415. const colorize = knockout.observable();
  416. knockout.defineProperty(this, "colorize", {
  417. get: function () {
  418. return colorize();
  419. },
  420. set: function (value) {
  421. colorize(value);
  422. if (defined(that._tileset)) {
  423. that._tileset.debugColorizeTiles = value;
  424. that._scene.requestRender();
  425. }
  426. },
  427. });
  428. /**
  429. * Gets or sets the flag to colorize tiles. This property is observable.
  430. *
  431. * @type {boolean}
  432. * @default false
  433. */
  434. this.colorize = false;
  435. const wireframe = knockout.observable();
  436. knockout.defineProperty(this, "wireframe", {
  437. get: function () {
  438. return wireframe();
  439. },
  440. set: function (value) {
  441. wireframe(value);
  442. if (defined(that._tileset)) {
  443. that._tileset.debugWireframe = value;
  444. that._scene.requestRender();
  445. }
  446. },
  447. });
  448. /**
  449. * Gets or sets the flag to draw with wireframe. This property is observable.
  450. *
  451. * @type {boolean}
  452. * @default false
  453. */
  454. this.wireframe = false;
  455. const showBoundingVolumes = knockout.observable();
  456. knockout.defineProperty(this, "showBoundingVolumes", {
  457. get: function () {
  458. return showBoundingVolumes();
  459. },
  460. set: function (value) {
  461. showBoundingVolumes(value);
  462. if (defined(that._tileset)) {
  463. that._tileset.debugShowBoundingVolume = value;
  464. that._scene.requestRender();
  465. }
  466. },
  467. });
  468. /**
  469. * Gets or sets the flag to show bounding volumes. This property is observable.
  470. *
  471. * @type {boolean}
  472. * @default false
  473. */
  474. this.showBoundingVolumes = false;
  475. const showContentBoundingVolumes = knockout.observable();
  476. knockout.defineProperty(this, "showContentBoundingVolumes", {
  477. get: function () {
  478. return showContentBoundingVolumes();
  479. },
  480. set: function (value) {
  481. showContentBoundingVolumes(value);
  482. if (defined(that._tileset)) {
  483. that._tileset.debugShowContentBoundingVolume = value;
  484. that._scene.requestRender();
  485. }
  486. },
  487. });
  488. /**
  489. * Gets or sets the flag to show content volumes. This property is observable.
  490. *
  491. * @type {boolean}
  492. * @default false
  493. */
  494. this.showContentBoundingVolumes = false;
  495. const showRequestVolumes = knockout.observable();
  496. knockout.defineProperty(this, "showRequestVolumes", {
  497. get: function () {
  498. return showRequestVolumes();
  499. },
  500. set: function (value) {
  501. showRequestVolumes(value);
  502. if (defined(that._tileset)) {
  503. that._tileset.debugShowViewerRequestVolume = value;
  504. that._scene.requestRender();
  505. }
  506. },
  507. });
  508. /**
  509. * Gets or sets the flag to show request volumes. This property is observable.
  510. *
  511. * @type {boolean}
  512. * @default false
  513. */
  514. this.showRequestVolumes = false;
  515. const freezeFrame = knockout.observable();
  516. knockout.defineProperty(this, "freezeFrame", {
  517. get: function () {
  518. return freezeFrame();
  519. },
  520. set: function (value) {
  521. freezeFrame(value);
  522. if (defined(that._tileset)) {
  523. that._tileset.debugFreezeFrame = value;
  524. that._scene.debugShowFrustumPlanes = value;
  525. that._scene.requestRender();
  526. }
  527. },
  528. });
  529. /**
  530. * Gets or sets the flag to suspend updates. This property is observable.
  531. *
  532. * @type {boolean}
  533. * @default false
  534. */
  535. this.freezeFrame = false;
  536. knockout.defineProperty(this, "showOnlyPickedTileDebugLabel", {
  537. get: function () {
  538. return showOnlyPickedTileDebugLabel();
  539. },
  540. set: function (value) {
  541. showOnlyPickedTileDebugLabel(value);
  542. if (defined(that._tileset)) {
  543. that._tileset.debugPickedTileLabelOnly = value;
  544. that._scene.requestRender();
  545. }
  546. },
  547. });
  548. /**
  549. * Gets or sets the flag to show debug labels only for the currently picked tile. This property is observable.
  550. *
  551. * @type {boolean}
  552. * @default false
  553. */
  554. this.showOnlyPickedTileDebugLabel = false;
  555. const showGeometricError = knockout.observable();
  556. knockout.defineProperty(this, "showGeometricError", {
  557. get: function () {
  558. return showGeometricError();
  559. },
  560. set: function (value) {
  561. showGeometricError(value);
  562. if (defined(that._tileset)) {
  563. that._tileset.debugShowGeometricError = value;
  564. that._scene.requestRender();
  565. }
  566. },
  567. });
  568. /**
  569. * Gets or sets the flag to show tile geometric error. This property is observable.
  570. *
  571. * @type {boolean}
  572. * @default false
  573. */
  574. this.showGeometricError = false;
  575. const showRenderingStatistics = knockout.observable();
  576. knockout.defineProperty(this, "showRenderingStatistics", {
  577. get: function () {
  578. return showRenderingStatistics();
  579. },
  580. set: function (value) {
  581. showRenderingStatistics(value);
  582. if (defined(that._tileset)) {
  583. that._tileset.debugShowRenderingStatistics = value;
  584. that._scene.requestRender();
  585. }
  586. },
  587. });
  588. /**
  589. * Displays the number of commands, points, triangles and features used per tile. This property is observable.
  590. *
  591. * @type {boolean}
  592. * @default false
  593. */
  594. this.showRenderingStatistics = false;
  595. const showMemoryUsage = knockout.observable();
  596. knockout.defineProperty(this, "showMemoryUsage", {
  597. get: function () {
  598. return showMemoryUsage();
  599. },
  600. set: function (value) {
  601. showMemoryUsage(value);
  602. if (defined(that._tileset)) {
  603. that._tileset.debugShowMemoryUsage = value;
  604. that._scene.requestRender();
  605. }
  606. },
  607. });
  608. /**
  609. * Displays the memory used per tile. This property is observable.
  610. *
  611. * @type {boolean}
  612. * @default false
  613. */
  614. this.showMemoryUsage = false;
  615. const showUrl = knockout.observable();
  616. knockout.defineProperty(this, "showUrl", {
  617. get: function () {
  618. return showUrl();
  619. },
  620. set: function (value) {
  621. showUrl(value);
  622. if (defined(that._tileset)) {
  623. that._tileset.debugShowUrl = value;
  624. that._scene.requestRender();
  625. }
  626. },
  627. });
  628. /**
  629. * Gets or sets the flag to show the tile url. This property is observable.
  630. *
  631. * @type {boolean}
  632. * @default false
  633. */
  634. this.showUrl = false;
  635. const maximumScreenSpaceError = knockout.observable();
  636. knockout.defineProperty(this, "maximumScreenSpaceError", {
  637. get: function () {
  638. return maximumScreenSpaceError();
  639. },
  640. set: function (value) {
  641. value = Number(value);
  642. if (!isNaN(value)) {
  643. maximumScreenSpaceError(value);
  644. if (defined(that._tileset)) {
  645. that._tileset.maximumScreenSpaceError = value;
  646. }
  647. }
  648. },
  649. });
  650. /**
  651. * Gets or sets the maximum screen space error. This property is observable.
  652. *
  653. * @type {number}
  654. * @default 16
  655. */
  656. this.maximumScreenSpaceError = 16;
  657. const dynamicScreenSpaceErrorDensity = knockout.observable();
  658. knockout.defineProperty(this, "dynamicScreenSpaceErrorDensity", {
  659. get: function () {
  660. return dynamicScreenSpaceErrorDensity();
  661. },
  662. set: function (value) {
  663. value = Number(value);
  664. if (!isNaN(value)) {
  665. dynamicScreenSpaceErrorDensity(value);
  666. if (defined(that._tileset)) {
  667. that._tileset.dynamicScreenSpaceErrorDensity = value;
  668. }
  669. }
  670. },
  671. });
  672. /**
  673. * Gets or sets the dynamic screen space error density. This property is observable.
  674. *
  675. * @type {number}
  676. * @default 0.00278
  677. */
  678. this.dynamicScreenSpaceErrorDensity = 0.00278;
  679. /**
  680. * Gets or sets the dynamic screen space error density slider value.
  681. * This allows the slider to be exponential because values tend to be closer to 0 than 1.
  682. * This property is observable.
  683. *
  684. * @type {number}
  685. * @default 0.00278
  686. */
  687. this.dynamicScreenSpaceErrorDensitySliderValue = undefined;
  688. knockout.defineProperty(this, "dynamicScreenSpaceErrorDensitySliderValue", {
  689. get: function () {
  690. return Math.pow(dynamicScreenSpaceErrorDensity(), 1 / 6);
  691. },
  692. set: function (value) {
  693. dynamicScreenSpaceErrorDensity(Math.pow(value, 6));
  694. },
  695. });
  696. const dynamicScreenSpaceErrorFactor = knockout.observable();
  697. knockout.defineProperty(this, "dynamicScreenSpaceErrorFactor", {
  698. get: function () {
  699. return dynamicScreenSpaceErrorFactor();
  700. },
  701. set: function (value) {
  702. value = Number(value);
  703. if (!isNaN(value)) {
  704. dynamicScreenSpaceErrorFactor(value);
  705. if (defined(that._tileset)) {
  706. that._tileset.dynamicScreenSpaceErrorFactor = value;
  707. }
  708. }
  709. },
  710. });
  711. /**
  712. * Gets or sets the dynamic screen space error factor. This property is observable.
  713. *
  714. * @type {number}
  715. * @default 4.0
  716. */
  717. this.dynamicScreenSpaceErrorFactor = 4.0;
  718. const pickTileset = getPickTileset(this);
  719. const pickActive = knockout.observable();
  720. knockout.defineProperty(this, "pickActive", {
  721. get: function () {
  722. return pickActive();
  723. },
  724. set: function (value) {
  725. pickActive(value);
  726. if (value) {
  727. that._eventHandler.setInputAction(
  728. pickTileset,
  729. ScreenSpaceEventType.LEFT_CLICK
  730. );
  731. } else {
  732. that._eventHandler.removeInputAction(ScreenSpaceEventType.LEFT_CLICK);
  733. }
  734. },
  735. });
  736. const pointCloudShading = knockout.observable();
  737. knockout.defineProperty(this, "pointCloudShading", {
  738. get: function () {
  739. return pointCloudShading();
  740. },
  741. set: function (value) {
  742. pointCloudShading(value);
  743. if (defined(that._tileset)) {
  744. that._tileset.pointCloudShading.attenuation = value;
  745. }
  746. },
  747. });
  748. /**
  749. * Gets or sets the flag to enable point cloud shading. This property is observable.
  750. *
  751. * @type {boolean}
  752. * @default false
  753. */
  754. this.pointCloudShading = false;
  755. const geometricErrorScale = knockout.observable();
  756. knockout.defineProperty(this, "geometricErrorScale", {
  757. get: function () {
  758. return geometricErrorScale();
  759. },
  760. set: function (value) {
  761. value = Number(value);
  762. if (!isNaN(value)) {
  763. geometricErrorScale(value);
  764. if (defined(that._tileset)) {
  765. that._tileset.pointCloudShading.geometricErrorScale = value;
  766. }
  767. }
  768. },
  769. });
  770. /**
  771. * Gets or sets the geometric error scale. This property is observable.
  772. *
  773. * @type {number}
  774. * @default 1.0
  775. */
  776. this.geometricErrorScale = 1.0;
  777. const maximumAttenuation = knockout.observable();
  778. knockout.defineProperty(this, "maximumAttenuation", {
  779. get: function () {
  780. return maximumAttenuation();
  781. },
  782. set: function (value) {
  783. value = Number(value);
  784. if (!isNaN(value)) {
  785. maximumAttenuation(value);
  786. if (defined(that._tileset)) {
  787. that._tileset.pointCloudShading.maximumAttenuation =
  788. value === 0 ? undefined : value;
  789. }
  790. }
  791. },
  792. });
  793. /**
  794. * Gets or sets the maximum attenuation. This property is observable.
  795. *
  796. * @type {number}
  797. * @default 0
  798. */
  799. this.maximumAttenuation = 0;
  800. const baseResolution = knockout.observable();
  801. knockout.defineProperty(this, "baseResolution", {
  802. get: function () {
  803. return baseResolution();
  804. },
  805. set: function (value) {
  806. value = Number(value);
  807. if (!isNaN(value)) {
  808. baseResolution(value);
  809. if (defined(that._tileset)) {
  810. that._tileset.pointCloudShading.baseResolution =
  811. value === 0 ? undefined : value;
  812. }
  813. }
  814. },
  815. });
  816. /**
  817. * Gets or sets the base resolution. This property is observable.
  818. *
  819. * @type {number}
  820. * @default 0
  821. */
  822. this.baseResolution = 0;
  823. const eyeDomeLighting = knockout.observable();
  824. knockout.defineProperty(this, "eyeDomeLighting", {
  825. get: function () {
  826. return eyeDomeLighting();
  827. },
  828. set: function (value) {
  829. eyeDomeLighting(value);
  830. if (defined(that._tileset)) {
  831. that._tileset.pointCloudShading.eyeDomeLighting = value;
  832. }
  833. },
  834. });
  835. /**
  836. * Gets or sets the flag to enable eye dome lighting. This property is observable.
  837. *
  838. * @type {boolean}
  839. * @default false
  840. */
  841. this.eyeDomeLighting = false;
  842. const eyeDomeLightingStrength = knockout.observable();
  843. knockout.defineProperty(this, "eyeDomeLightingStrength", {
  844. get: function () {
  845. return eyeDomeLightingStrength();
  846. },
  847. set: function (value) {
  848. value = Number(value);
  849. if (!isNaN(value)) {
  850. eyeDomeLightingStrength(value);
  851. if (defined(that._tileset)) {
  852. that._tileset.pointCloudShading.eyeDomeLightingStrength = value;
  853. }
  854. }
  855. },
  856. });
  857. /**
  858. * Gets or sets the eye dome lighting strength. This property is observable.
  859. *
  860. * @type {number}
  861. * @default 1.0
  862. */
  863. this.eyeDomeLightingStrength = 1.0;
  864. const eyeDomeLightingRadius = knockout.observable();
  865. knockout.defineProperty(this, "eyeDomeLightingRadius", {
  866. get: function () {
  867. return eyeDomeLightingRadius();
  868. },
  869. set: function (value) {
  870. value = Number(value);
  871. if (!isNaN(value)) {
  872. eyeDomeLightingRadius(value);
  873. if (defined(that._tileset)) {
  874. that._tileset.pointCloudShading.eyeDomeLightingRadius = value;
  875. }
  876. }
  877. },
  878. });
  879. /**
  880. * Gets or sets the eye dome lighting radius. This property is observable.
  881. *
  882. * @type {number}
  883. * @default 1.0
  884. */
  885. this.eyeDomeLightingRadius = 1.0;
  886. /**
  887. * Gets or sets the pick state
  888. *
  889. * @type {boolean}
  890. * @default false
  891. */
  892. this.pickActive = false;
  893. const skipLevelOfDetail = knockout.observable();
  894. knockout.defineProperty(this, "skipLevelOfDetail", {
  895. get: function () {
  896. return skipLevelOfDetail();
  897. },
  898. set: function (value) {
  899. skipLevelOfDetail(value);
  900. if (defined(that._tileset)) {
  901. that._tileset.skipLevelOfDetail = value;
  902. }
  903. },
  904. });
  905. /**
  906. * Gets or sets the flag to determine if level of detail skipping should be applied during the traversal.
  907. * This property is observable.
  908. * @type {boolean}
  909. * @default true
  910. */
  911. this.skipLevelOfDetail = true;
  912. const skipScreenSpaceErrorFactor = knockout.observable();
  913. knockout.defineProperty(this, "skipScreenSpaceErrorFactor", {
  914. get: function () {
  915. return skipScreenSpaceErrorFactor();
  916. },
  917. set: function (value) {
  918. value = Number(value);
  919. if (!isNaN(value)) {
  920. skipScreenSpaceErrorFactor(value);
  921. if (defined(that._tileset)) {
  922. that._tileset.skipScreenSpaceErrorFactor = value;
  923. }
  924. }
  925. },
  926. });
  927. /**
  928. * Gets or sets the multiplier defining the minimum screen space error to skip. This property is observable.
  929. * @type {number}
  930. * @default 16
  931. */
  932. this.skipScreenSpaceErrorFactor = 16;
  933. const baseScreenSpaceError = knockout.observable();
  934. knockout.defineProperty(this, "baseScreenSpaceError", {
  935. get: function () {
  936. return baseScreenSpaceError();
  937. },
  938. set: function (value) {
  939. value = Number(value);
  940. if (!isNaN(value)) {
  941. baseScreenSpaceError(value);
  942. if (defined(that._tileset)) {
  943. that._tileset.baseScreenSpaceError = value;
  944. }
  945. }
  946. },
  947. });
  948. /**
  949. * Gets or sets the screen space error that must be reached before skipping levels of detail. This property is observable.
  950. * @type {number}
  951. * @default 1024
  952. */
  953. this.baseScreenSpaceError = 1024;
  954. const skipLevels = knockout.observable();
  955. knockout.defineProperty(this, "skipLevels", {
  956. get: function () {
  957. return skipLevels();
  958. },
  959. set: function (value) {
  960. value = Number(value);
  961. if (!isNaN(value)) {
  962. skipLevels(value);
  963. if (defined(that._tileset)) {
  964. that._tileset.skipLevels = value;
  965. }
  966. }
  967. },
  968. });
  969. /**
  970. * Gets or sets the constant defining the minimum number of levels to skip when loading tiles. This property is observable.
  971. * @type {number}
  972. * @default 1
  973. */
  974. this.skipLevels = 1;
  975. const immediatelyLoadDesiredLevelOfDetail = knockout.observable();
  976. knockout.defineProperty(this, "immediatelyLoadDesiredLevelOfDetail", {
  977. get: function () {
  978. return immediatelyLoadDesiredLevelOfDetail();
  979. },
  980. set: function (value) {
  981. immediatelyLoadDesiredLevelOfDetail(value);
  982. if (defined(that._tileset)) {
  983. that._tileset.immediatelyLoadDesiredLevelOfDetail = value;
  984. }
  985. },
  986. });
  987. /**
  988. * Gets or sets the flag which, when true, only tiles that meet the maximum screen space error will ever be downloaded.
  989. * This property is observable.
  990. * @type {boolean}
  991. * @default false
  992. */
  993. this.immediatelyLoadDesiredLevelOfDetail = false;
  994. const loadSiblings = knockout.observable();
  995. knockout.defineProperty(this, "loadSiblings", {
  996. get: function () {
  997. return loadSiblings();
  998. },
  999. set: function (value) {
  1000. loadSiblings(value);
  1001. if (defined(that._tileset)) {
  1002. that._tileset.loadSiblings = value;
  1003. }
  1004. },
  1005. });
  1006. /**
  1007. * Gets or sets the flag which determines whether siblings of visible tiles are always downloaded during traversal.
  1008. * This property is observable
  1009. * @type {boolean}
  1010. * @default false
  1011. */
  1012. this.loadSiblings = false;
  1013. this._style = undefined;
  1014. this._shouldStyle = false;
  1015. this._definedProperties = [
  1016. "properties",
  1017. "dynamicScreenSpaceError",
  1018. "colorBlendMode",
  1019. "picking",
  1020. "colorize",
  1021. "wireframe",
  1022. "showBoundingVolumes",
  1023. "showContentBoundingVolumes",
  1024. "showRequestVolumes",
  1025. "freezeFrame",
  1026. "maximumScreenSpaceError",
  1027. "dynamicScreenSpaceErrorDensity",
  1028. "baseScreenSpaceError",
  1029. "skipScreenSpaceErrorFactor",
  1030. "skipLevelOfDetail",
  1031. "skipLevels",
  1032. "immediatelyLoadDesiredLevelOfDetail",
  1033. "loadSiblings",
  1034. "dynamicScreenSpaceErrorDensitySliderValue",
  1035. "dynamicScreenSpaceErrorFactor",
  1036. "pickActive",
  1037. "showOnlyPickedTileDebugLabel",
  1038. "showGeometricError",
  1039. "showRenderingStatistics",
  1040. "showMemoryUsage",
  1041. "showUrl",
  1042. "pointCloudShading",
  1043. "geometricErrorScale",
  1044. "maximumAttenuation",
  1045. "baseResolution",
  1046. "eyeDomeLighting",
  1047. "eyeDomeLightingStrength",
  1048. "eyeDomeLightingRadius",
  1049. ];
  1050. this._removePostRenderEvent = scene.postRender.addEventListener(function () {
  1051. that._update();
  1052. });
  1053. if (!defined(this._tileset)) {
  1054. selectTilesetOnHover(this, true);
  1055. }
  1056. }
  1057. Object.defineProperties(Cesium3DTilesInspectorViewModel.prototype, {
  1058. /**
  1059. * Gets the scene
  1060. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1061. * @type {Scene}
  1062. * @readonly
  1063. */
  1064. scene: {
  1065. get: function () {
  1066. return this._scene;
  1067. },
  1068. },
  1069. /**
  1070. * Gets the performance container
  1071. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1072. * @type {HTMLElement}
  1073. * @readonly
  1074. */
  1075. performanceContainer: {
  1076. get: function () {
  1077. return this._performanceContainer;
  1078. },
  1079. },
  1080. /**
  1081. * Gets the statistics text. This property is observable.
  1082. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1083. * @type {string}
  1084. * @readonly
  1085. */
  1086. statisticsText: {
  1087. get: function () {
  1088. return this._statisticsText;
  1089. },
  1090. },
  1091. /**
  1092. * Gets the pick statistics text. This property is observable.
  1093. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1094. * @type {string}
  1095. * @readonly
  1096. */
  1097. pickStatisticsText: {
  1098. get: function () {
  1099. return this._pickStatisticsText;
  1100. },
  1101. },
  1102. /**
  1103. * Gets the resource cache statistics text. This property is observable.
  1104. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1105. * @type {string}
  1106. * @readonly
  1107. */
  1108. resourceCacheStatisticsText: {
  1109. get: function () {
  1110. return this._resourceCacheStatisticsText;
  1111. },
  1112. },
  1113. /**
  1114. * Gets the available blend modes
  1115. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1116. * @type {Object[]}
  1117. * @readonly
  1118. */
  1119. colorBlendModes: {
  1120. get: function () {
  1121. return colorBlendModes;
  1122. },
  1123. },
  1124. /**
  1125. * Gets the editor error message
  1126. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1127. * @type {string}
  1128. * @readonly
  1129. */
  1130. editorError: {
  1131. get: function () {
  1132. return this._editorError;
  1133. },
  1134. },
  1135. /**
  1136. * Gets or sets the tileset of the view model.
  1137. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1138. * @type {Cesium3DTileset}
  1139. */
  1140. tileset: {
  1141. get: function () {
  1142. return this._tileset;
  1143. },
  1144. set: function (tileset) {
  1145. this._tileset = tileset;
  1146. this._style = undefined;
  1147. this.styleString = "{}";
  1148. this.feature = undefined;
  1149. this.tile = undefined;
  1150. if (defined(tileset)) {
  1151. const that = this;
  1152. // This is here for backwards compatibility. It can be removed when Cesium3DTileset.readyPromise is fully deprecated.
  1153. tileset._readyPromise.then(function (t) {
  1154. if (!that.isDestroyed()) {
  1155. that._properties(t.properties);
  1156. }
  1157. });
  1158. // update tileset with existing settings
  1159. const settings = [
  1160. "colorize",
  1161. "wireframe",
  1162. "showBoundingVolumes",
  1163. "showContentBoundingVolumes",
  1164. "showRequestVolumes",
  1165. "freezeFrame",
  1166. "showOnlyPickedTileDebugLabel",
  1167. "showGeometricError",
  1168. "showRenderingStatistics",
  1169. "showMemoryUsage",
  1170. "showUrl",
  1171. ];
  1172. const length = settings.length;
  1173. for (let i = 0; i < length; ++i) {
  1174. const setting = settings[i];
  1175. //eslint-disable-next-line no-self-assign
  1176. this[setting] = this[setting];
  1177. }
  1178. // update view model with existing tileset settings
  1179. this.maximumScreenSpaceError = tileset.maximumScreenSpaceError;
  1180. this.dynamicScreenSpaceError = tileset.dynamicScreenSpaceError;
  1181. this.dynamicScreenSpaceErrorDensity =
  1182. tileset.dynamicScreenSpaceErrorDensity;
  1183. this.dynamicScreenSpaceErrorFactor =
  1184. tileset.dynamicScreenSpaceErrorFactor;
  1185. this.colorBlendMode = tileset.colorBlendMode;
  1186. this.skipLevelOfDetail = tileset.skipLevelOfDetail;
  1187. this.skipScreenSpaceErrorFactor = tileset.skipScreenSpaceErrorFactor;
  1188. this.baseScreenSpaceError = tileset.baseScreenSpaceError;
  1189. this.skipLevels = tileset.skipLevels;
  1190. this.immediatelyLoadDesiredLevelOfDetail =
  1191. tileset.immediatelyLoadDesiredLevelOfDetail;
  1192. this.loadSiblings = tileset.loadSiblings;
  1193. this.hasEnabledWireframe = tileset._enableDebugWireframe;
  1194. const pointCloudShading = tileset.pointCloudShading;
  1195. this.pointCloudShading = pointCloudShading.attenuation;
  1196. this.geometricErrorScale = pointCloudShading.geometricErrorScale;
  1197. this.maximumAttenuation = pointCloudShading.maximumAttenuation
  1198. ? pointCloudShading.maximumAttenuation
  1199. : 0.0;
  1200. this.baseResolution = pointCloudShading.baseResolution
  1201. ? pointCloudShading.baseResolution
  1202. : 0.0;
  1203. this.eyeDomeLighting = pointCloudShading.eyeDomeLighting;
  1204. this.eyeDomeLightingStrength =
  1205. pointCloudShading.eyeDomeLightingStrength;
  1206. this.eyeDomeLightingRadius = pointCloudShading.eyeDomeLightingRadius;
  1207. this._scene.requestRender();
  1208. } else {
  1209. this._properties({});
  1210. }
  1211. this._statisticsText = getStatistics(tileset, false);
  1212. this._pickStatisticsText = getStatistics(tileset, true);
  1213. this._resourceCacheStatisticsText = getResourceCacheStatistics();
  1214. selectTilesetOnHover(this, false);
  1215. },
  1216. },
  1217. /**
  1218. * Gets the current feature of the view model.
  1219. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1220. * @type {Cesium3DTileFeature}
  1221. */
  1222. feature: {
  1223. get: function () {
  1224. return this._feature;
  1225. },
  1226. set: function (feature) {
  1227. if (this._feature === feature) {
  1228. return;
  1229. }
  1230. const currentFeature = this._feature;
  1231. if (defined(currentFeature) && !currentFeature.content.isDestroyed()) {
  1232. // Restore original color to feature that is no longer selected
  1233. if (!this.colorize && defined(this._style)) {
  1234. currentFeature.color = defined(this._style.color)
  1235. ? this._style.color.evaluateColor(currentFeature, scratchColor)
  1236. : Color.WHITE;
  1237. } else {
  1238. currentFeature.color = oldColor;
  1239. }
  1240. this._scene.requestRender();
  1241. }
  1242. if (defined(feature)) {
  1243. // Highlight new feature
  1244. Color.clone(feature.color, oldColor);
  1245. feature.color = highlightColor;
  1246. this._scene.requestRender();
  1247. }
  1248. this._feature = feature;
  1249. },
  1250. },
  1251. /**
  1252. * Gets the current tile of the view model
  1253. * @memberof Cesium3DTilesInspectorViewModel.prototype
  1254. * @type {Cesium3DTile}
  1255. */
  1256. tile: {
  1257. get: function () {
  1258. return this._tile;
  1259. },
  1260. set: function (tile) {
  1261. if (this._tile === tile) {
  1262. return;
  1263. }
  1264. const currentTile = this._tile;
  1265. if (
  1266. defined(currentTile) &&
  1267. !currentTile.isDestroyed() &&
  1268. !hasFeatures(currentTile.content)
  1269. ) {
  1270. // Restore original color to tile that is no longer selected
  1271. currentTile.color = oldColor;
  1272. this._scene.requestRender();
  1273. }
  1274. if (defined(tile) && !hasFeatures(tile.content)) {
  1275. // Highlight new tile
  1276. Color.clone(tile.color, oldColor);
  1277. tile.color = highlightColor;
  1278. this._scene.requestRender();
  1279. }
  1280. this._tile = tile;
  1281. },
  1282. },
  1283. });
  1284. function hasFeatures(content) {
  1285. if (!defined(content)) {
  1286. return false;
  1287. }
  1288. if (content.featuresLength > 0) {
  1289. return true;
  1290. }
  1291. const innerContents = content.innerContents;
  1292. if (defined(innerContents)) {
  1293. const length = innerContents.length;
  1294. for (let i = 0; i < length; ++i) {
  1295. if (!hasFeatures(innerContents[i])) {
  1296. return false;
  1297. }
  1298. }
  1299. return true;
  1300. }
  1301. return false;
  1302. }
  1303. /**
  1304. * Toggles the pick tileset mode
  1305. */
  1306. Cesium3DTilesInspectorViewModel.prototype.togglePickTileset = function () {
  1307. this.pickActive = !this.pickActive;
  1308. };
  1309. /**
  1310. * Toggles the inspector visibility
  1311. */
  1312. Cesium3DTilesInspectorViewModel.prototype.toggleInspector = function () {
  1313. this.inspectorVisible = !this.inspectorVisible;
  1314. };
  1315. /**
  1316. * Toggles the visibility of the tileset section
  1317. */
  1318. Cesium3DTilesInspectorViewModel.prototype.toggleTileset = function () {
  1319. this.tilesetVisible = !this.tilesetVisible;
  1320. };
  1321. /**
  1322. * Toggles the visibility of the display section
  1323. */
  1324. Cesium3DTilesInspectorViewModel.prototype.toggleDisplay = function () {
  1325. this.displayVisible = !this.displayVisible;
  1326. };
  1327. /**
  1328. * Toggles the visibility of the update section
  1329. */
  1330. Cesium3DTilesInspectorViewModel.prototype.toggleUpdate = function () {
  1331. this.updateVisible = !this.updateVisible;
  1332. };
  1333. /**
  1334. * Toggles the visibility of the logging section
  1335. */
  1336. Cesium3DTilesInspectorViewModel.prototype.toggleLogging = function () {
  1337. this.loggingVisible = !this.loggingVisible;
  1338. };
  1339. /**
  1340. * Toggles the visibility of the style section
  1341. */
  1342. Cesium3DTilesInspectorViewModel.prototype.toggleStyle = function () {
  1343. this.styleVisible = !this.styleVisible;
  1344. };
  1345. /**
  1346. * Toggles the visibility of the tile Debug Info section
  1347. */
  1348. Cesium3DTilesInspectorViewModel.prototype.toggleTileDebugLabels = function () {
  1349. this.tileDebugLabelsVisible = !this.tileDebugLabelsVisible;
  1350. };
  1351. /**
  1352. * Toggles the visibility of the optimization section
  1353. */
  1354. Cesium3DTilesInspectorViewModel.prototype.toggleOptimization = function () {
  1355. this.optimizationVisible = !this.optimizationVisible;
  1356. };
  1357. /**
  1358. * Trims tile cache
  1359. */
  1360. Cesium3DTilesInspectorViewModel.prototype.trimTilesCache = function () {
  1361. if (defined(this._tileset)) {
  1362. this._tileset.trimLoadedTiles();
  1363. }
  1364. };
  1365. /**
  1366. * Compiles the style in the style editor.
  1367. */
  1368. Cesium3DTilesInspectorViewModel.prototype.compileStyle = function () {
  1369. const tileset = this._tileset;
  1370. if (!defined(tileset) || this.styleString === JSON.stringify(tileset.style)) {
  1371. return;
  1372. }
  1373. this._editorError = "";
  1374. try {
  1375. if (this.styleString.length === 0) {
  1376. this.styleString = "{}";
  1377. }
  1378. this._style = new Cesium3DTileStyle(JSON.parse(this.styleString));
  1379. this._shouldStyle = true;
  1380. this._scene.requestRender();
  1381. } catch (err) {
  1382. this._editorError = err.toString();
  1383. }
  1384. // set feature again so pick coloring is set
  1385. this.feature = this._feature;
  1386. this.tile = this._tile;
  1387. };
  1388. /**
  1389. * Handles key press events on the style editor.
  1390. */
  1391. Cesium3DTilesInspectorViewModel.prototype.styleEditorKeyPress = function (
  1392. sender,
  1393. event
  1394. ) {
  1395. if (event.keyCode === 9) {
  1396. //tab
  1397. event.preventDefault();
  1398. const textArea = event.target;
  1399. const start = textArea.selectionStart;
  1400. const end = textArea.selectionEnd;
  1401. let newEnd = end;
  1402. const selected = textArea.value.slice(start, end);
  1403. const lines = selected.split("\n");
  1404. const length = lines.length;
  1405. let i;
  1406. if (!event.shiftKey) {
  1407. for (i = 0; i < length; ++i) {
  1408. lines[i] = ` ${lines[i]}`;
  1409. newEnd += 2;
  1410. }
  1411. } else {
  1412. for (i = 0; i < length; ++i) {
  1413. if (lines[i][0] === " ") {
  1414. if (lines[i][1] === " ") {
  1415. lines[i] = lines[i].substr(2);
  1416. newEnd -= 2;
  1417. } else {
  1418. lines[i] = lines[i].substr(1);
  1419. newEnd -= 1;
  1420. }
  1421. }
  1422. }
  1423. }
  1424. const newText = lines.join("\n");
  1425. textArea.value =
  1426. textArea.value.slice(0, start) + newText + textArea.value.slice(end);
  1427. textArea.selectionStart = start !== end ? start : newEnd;
  1428. textArea.selectionEnd = newEnd;
  1429. } else if (event.ctrlKey && (event.keyCode === 10 || event.keyCode === 13)) {
  1430. //ctrl + enter
  1431. this.compileStyle();
  1432. }
  1433. return true;
  1434. };
  1435. /**
  1436. * Updates the values of view model
  1437. * @private
  1438. */
  1439. Cesium3DTilesInspectorViewModel.prototype._update = function () {
  1440. const tileset = this._tileset;
  1441. if (this.performance) {
  1442. this._performanceDisplay.update();
  1443. }
  1444. if (defined(tileset)) {
  1445. if (tileset.isDestroyed()) {
  1446. this.tile = undefined;
  1447. this.feature = undefined;
  1448. this.tileset = undefined;
  1449. return;
  1450. }
  1451. const style = tileset.style;
  1452. if (this._style !== tileset.style) {
  1453. if (this._shouldStyle) {
  1454. tileset.style = this._style;
  1455. this._shouldStyle = false;
  1456. } else {
  1457. this._style = style;
  1458. this.styleString = JSON.stringify(style.style, null, " ");
  1459. }
  1460. }
  1461. }
  1462. if (this.showStatistics) {
  1463. this._statisticsText = getStatistics(tileset, false);
  1464. this._pickStatisticsText = getStatistics(tileset, true);
  1465. this._resourceCacheStatisticsText = getResourceCacheStatistics();
  1466. }
  1467. };
  1468. /**
  1469. * @returns {boolean} true if the object has been destroyed, false otherwise.
  1470. */
  1471. Cesium3DTilesInspectorViewModel.prototype.isDestroyed = function () {
  1472. return false;
  1473. };
  1474. /**
  1475. * Destroys the widget. Should be called if permanently
  1476. * removing the widget from layout.
  1477. */
  1478. Cesium3DTilesInspectorViewModel.prototype.destroy = function () {
  1479. this._eventHandler.destroy();
  1480. this._removePostRenderEvent();
  1481. const that = this;
  1482. this._definedProperties.forEach(function (property) {
  1483. knockout.getObservable(that, property).dispose();
  1484. });
  1485. return destroyObject(this);
  1486. };
  1487. /**
  1488. * Generates an HTML string of the statistics
  1489. *
  1490. * @function
  1491. * @param {Cesium3DTileset} tileset The tileset
  1492. * @param {boolean} isPick Whether this is getting the statistics for the pick pass
  1493. * @returns {string} The formatted statistics
  1494. */
  1495. Cesium3DTilesInspectorViewModel.getStatistics = getStatistics;
  1496. export default Cesium3DTilesInspectorViewModel;