Add existing to tracked

This commit is contained in:
Jay
2026-08-11 09:53:42 -04:00
parent afe07f3055
commit ffd6e3d73c
8531 changed files with 4396230 additions and 0 deletions
@@ -0,0 +1,31 @@
.cesium-viewer-i3s-explorer ul {
list-style-type: none;
}
.cesium-viewer-i3s-explorer .layersList {
padding: 0;
}
.cesium-viewer-i3s-explorer input {
margin: 0 3px 0 0;
}
.cesium-viewer-i3s-explorer .expandItem {
cursor: pointer;
user-select: none;
width: 20px;
}
.cesium-viewer-i3s-explorer .nested,
.cesium-viewer-i3s-explorer #bsl-wrapper {
display: none;
}
.cesium-viewer-i3s-explorer .active {
display: block;
}
.cesium-viewer-i3s-explorer .li-wrapper {
display: flex;
flex-direction: row;
align-content: center;
}
@@ -0,0 +1,81 @@
import { Check, defined } from "@cesium/engine";
import knockout from "../ThirdParty/knockout.js";
import I3SBuildingSceneLayerExplorerViewModel from "./I3SBuildingSceneLayerExplorerViewModel.js";
/**
* I3S Building Scene Layer widget
*
* @alias I3SBuildingSceneLayerExplorer
* @constructor
*
* @param {string} containerId The DOM element ID that will contain the widget.
* @param {I3SDataProvider} i3sProvider I3S Data provider instance.
*
* @demo {@link https://sandcastle.cesium.com/index.html?id=i3s-building-scene-layer|I3S Building Scene Layer}
*/
function I3SBuildingSceneLayerExplorer(containerId, i3sProvider) {
const container = document.getElementById(containerId);
//>>includeStart('debug', pragmas.debug);
Check.defined("container", container);
Check.defined("i3sProvider", i3sProvider);
//>>includeEnd('debug');
const htmlWrapper = document.createElement("div");
htmlWrapper.classList.add("cesium-viewer-i3s-explorer");
htmlWrapper.innerHTML = `
<h3>Building explorer</h3>
<select
data-bind="options: topLayers, optionsText: 'name', optionsAfterRender: setOptionDisable, value: currentLayer"
></select>
<div id="bsl-wrapper">
<h3>Select Level</h3>
<select data-bind="options: levels, value: currentLevel"></select>
<h3>Disciplines & Categories</h3>
<ul class="layersList" data-bind="foreach: sublayers">
<ul class="layersList" data-bind="foreach: sublayers.sort(function (l, r) { return l.name.localeCompare(r.name) })">
<li>
<div class="li-wrapper">
<span
class="expandItem"
data-bind="click: $root.expandClickHandler"
>+</span
>
<input
type="checkbox"
data-bind="checked: visibility, valueUpdate: 'input', attr: { id: name}"
/>
<label data-bind="attr: { for: name}">
<span data-bind="text: name"></span>
</label>
</div>
<ul class="nested" data-bind="attr: { id: name + '-expander'}">
<li data-bind="foreach: sublayers.sort(function (l, r) { return l.name.localeCompare(r.name) })">
<div class="li-wrapper">
<input
type="checkbox"
data-bind="checked: visibility, valueUpdate: 'input', attr: { id: name}"
/>
<label data-bind="attr: { for: name}">
<span data-bind="text: name"></span>
</label>
</div>
</li>
</ul>
</li>
</ul>
</ul>
</div>`;
container.appendChild(htmlWrapper);
const viewModel = new I3SBuildingSceneLayerExplorerViewModel(i3sProvider);
knockout.track(viewModel);
knockout.applyBindings(viewModel, container);
if (defined(viewModel.defaultLayer)) {
// Select a model by default
viewModel.currentLayer = viewModel.defaultLayer;
}
}
export default I3SBuildingSceneLayerExplorer;
@@ -0,0 +1,173 @@
import { defined } from "@cesium/engine";
import knockout from "../ThirdParty/knockout.js";
function expandItemsHandler(data, event) {
const nestedList =
event.currentTarget.parentElement.parentElement.querySelector(
`#${data.name}-expander`,
);
nestedList.classList.toggle("active");
event.currentTarget.textContent =
event.currentTarget.textContent === "+" ? "-" : "+";
}
function trackSublayer(sublayer, viewModel) {
knockout.track(sublayer);
for (let i = 0; i < sublayer.sublayers.length; i++) {
trackSublayer(sublayer.sublayers[i], viewModel);
}
}
function isFullModel(layer) {
return layer.modelName === "FullModel";
}
function isOverview(layer) {
return layer.modelName === "Overview";
}
function isTopLayer(layer) {
return isOverview(layer) || isFullModel(layer);
}
function addTopLayer(layer, viewModel) {
if (isTopLayer(layer)) {
layer.visibility = false;
for (let i = 0; i < layer.sublayers.length; i++) {
layer.sublayers[i].visibility = true;
}
const topLayer = {
name: layer.name,
modelName: layer.modelName,
disable: knockout.observable(false),
index: viewModel.sublayers.length,
};
viewModel.topLayers.push(topLayer);
viewModel.sublayers.push(layer);
return topLayer;
}
}
function handleTopLayerSelector(layer, viewModel) {
if (isTopLayer(layer)) {
viewModel.sublayers.forEach((elem) => (elem.visibility = false));
viewModel.sublayers[layer.index].visibility = true;
const bsl = document.getElementById("bsl-wrapper");
if (isFullModel(layer)) {
viewModel.currentLevel = viewModel.selectedLevel;
bsl.style.display = "block";
} else {
viewModel.selectedLevel = viewModel.currentLevel;
viewModel.currentLevel = "All";
bsl.style.display = "none";
}
}
}
async function setLevels(i3sProvider, levels) {
try {
const attributes = i3sProvider.getAttributeNames();
for (let index = 0; index < attributes.length; index++) {
if (attributes[index] === "BldgLevel") {
const values = i3sProvider.getAttributeValues(attributes[index]);
for (let i = 0; i < values.length; i++) {
levels.push(values[i]);
}
}
}
levels.sort((a, b) => a - b);
levels.unshift("All");
} catch (error) {
console.log(`There was an error getting attributes: ${error}`);
}
}
/**
* The view model for {@link I3SBuildingSceneLayerExplorer}.
* @alias I3sBslExplorerViewModel
* @constructor
*
* @param {I3SDataProvider} i3sProvider I3S Data provider instance.
*/
function I3SBuildingSceneLayerExplorerViewModel(i3sProvider) {
const that = this;
this.levels = [];
this.viewModel = {
sublayers: [],
levels: this.levels,
currentLevel: knockout.observable(),
selectedLevel: "All",
topLayers: [
{
name: "Select a layer to explore...",
disable: knockout.observable(true),
index: -1,
},
],
currentLayer: knockout.observable(),
expandClickHandler: expandItemsHandler,
setOptionDisable: function (option, item) {
knockout.applyBindingsToNode(option, { disable: item.disable }, item);
},
defaultLayer: undefined,
};
// Handling change of a layer for exploring
this.viewModel.currentLayer.subscribe(function (layer) {
handleTopLayerSelector(layer, that.viewModel);
});
// Setting a sublayers tree to the viewModel
const sublayers = i3sProvider.sublayers;
for (let i = 0; i < sublayers.length; i++) {
trackSublayer(sublayers[i], this.viewModel);
const topLayer = addTopLayer(sublayers[i], this.viewModel);
if (
defined(topLayer) &&
(isOverview(topLayer) ||
(!defined(this.viewModel.defaultLayer) && isFullModel(topLayer)))
) {
this.viewModel.defaultLayer = topLayer;
}
}
// There is no Full Model and/or Overview
if (this.viewModel.topLayers.length === 1 && sublayers.length > 0) {
i3sProvider.show = false;
const fullModel = {
name: "Full Model",
modelName: "FullModel",
visibility: i3sProvider.show,
sublayers: i3sProvider.sublayers,
};
this.viewModel.defaultLayer = addTopLayer(fullModel, this.viewModel);
this.viewModel.currentLayer.subscribe(function (layer) {
i3sProvider.show = isFullModel(layer);
});
} else if (this.viewModel.topLayers.length === 1) {
this.viewModel.topLayers[0].name = "Building layers not found";
}
// Setting levels to the viewModel
setLevels(i3sProvider, this.levels);
// Filtering by levels
this.viewModel.currentLevel.subscribe(function (newValue) {
if (newValue !== "All") {
i3sProvider.filterByAttributes([
{
name: "BldgLevel",
values: [newValue],
},
]);
} else {
i3sProvider.filterByAttributes();
}
});
return this.viewModel;
}
export default I3SBuildingSceneLayerExplorerViewModel;