Cesium3DTilesInspectorViewModel.js 43 KB

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