Cesium3DTilesInspectorViewModel.js 53 KB

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