Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,16 @@ export default [
],
},
},
{
files: ["packages/sandcastle/gallery/**/*.js"],
languageOptions: {
ecmaVersion: 2022,
sourceType: "module",
},
rules: {
"no-alert": "off",
},
},
{
files: ["Specs/**/*", "packages/**/Specs/**/*"],
languageOptions: {
Expand Down
5 changes: 4 additions & 1 deletion packages/sandcastle/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,8 @@ node_modules
dist
dist-ssr
*.local
*.tsbuildinfo

public/templates/Sandcastle.d.ts
gallery/list.json
templates/Sandcastle.d.ts
templates/Sandcastle.js
37 changes: 37 additions & 0 deletions packages/sandcastle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,43 @@ This package is the application for Sandcastle.

Linting and style is managed under the project root's scripts.

## Gallery structure

The gallery for Sandcastle is located in the `gallery` directory. A "single sandcastle" consists of 4 files which should be contained in a sub-directory that matches the id of the sandcastle.

```text
gallery
├── 3d-models <-- "slug" id
│   ├── index.html <-- Code that goes into the HTML tab
│   ├── main.js <-- Code that goes into the JS tab (the main code of a Sandcastle)
│   ├── sandcastle.yaml <-- Metadata file containing title, description, labels, etc.
│   └── thumbnail.jpg <-- Optional thumbnail file
└── gallery-list.json <-- "entry point" for a gallery, generated with `scripts/buildGallery.js`
```

### `sandcastle.yaml`

Below is a sample metadata yaml file. This data is used in the `scripts/buildGallery.js` file to create the full `gallery-list.json` information. That script also does some validation on these values.

```yaml
# The id of this sandcastle. Should match the sub-directory name and not contain spaces
id: 3d-models-coloring
# Used to map this sandcastle to a legacy html identifier. New sandcastles should NOT include this
legacyId: 3D Models Coloring.html
# Title for this sandcastle
title: 3D Models Coloring
# Description for this sandcastle
description: Change color of 3D models.
# Labels for this Sandcastle to help with filtering
labels:
- Showcases
- Beginner
# Optional thumbnail file. If set the file should be in the same directory
thumbnail: thumbnail.jpg
# Identify this as a development only Sandcastle. Will not be included in production builds if true
development: false
```

## Expanding the ESLint configuration

<!-- TODO: this section was auto-generated, should figure out if we want these suggestions then remove this -->
Expand Down
108 changes: 108 additions & 0 deletions packages/sandcastle/gallery/3d-models-coloring/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<style>
@import url(../templates/bucket.css);
#toolbar {
background: rgba(42, 42, 42, 0.8);
padding: 4px;
border-radius: 4px;
}
#toolbar input {
vertical-align: middle;
padding-top: 2px;
padding-bottom: 2px;
}
#toolbar .header {
font-weight: bold;
}
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar">
<table>
<tbody>
<tr>
<td class="header">Model Color</td>
</tr>
<tr>
<td>Mode</td>
<td>
<select
data-bind="options: colorBlendModes, value: colorBlendMode"
></select>
</td>
</tr>
<tr>
<td>Color</td>
<td><select data-bind="options: colors, value: color"></select></td>
</tr>
<tr>
<td>Alpha</td>
<td>
<input
type="range"
min="0.0"
max="1.0"
step="0.01"
data-bind="value: alpha, valueUpdate: 'input'"
/>
<input type="text" size="5" data-bind="value: alpha" />
</td>
</tr>
<tr>
<td data-bind="style: { color: colorBlendAmountEnabled ? '' : 'gray'}">
Mix
</td>
<td>
<input
type="range"
min="0.0"
max="1.0"
step="0.01"
data-bind="value: colorBlendAmount, valueUpdate: 'input', enable: colorBlendAmountEnabled"
/>
<input
type="text"
size="5"
data-bind="value: colorBlendAmount, enable: colorBlendAmountEnabled"
/>
</td>
</tr>
<tr>
<td class="header">Model Silhouette</td>
</tr>
<tr>
<td>Color</td>
<td>
<select
data-bind="options: silhouetteColors, value: silhouetteColor"
></select>
</td>
</tr>
<tr>
<td>Alpha</td>
<td>
<input
type="range"
min="0.0"
max="1.0"
step="0.01"
data-bind="value: silhouetteAlpha, valueUpdate: 'input'"
/>
<input type="text" size="5" data-bind="value: silhouetteAlpha" />
</td>
</tr>
<tr>
<td>Size</td>
<td>
<input
type="range"
min="0.0"
max="10.0"
step="0.01"
data-bind="value: silhouetteSize, valueUpdate: 'input'"
/>
<input type="text" size="5" data-bind="value: silhouetteSize" />
</td>
</tr>
</tbody>
</table>
</div>
176 changes: 176 additions & 0 deletions packages/sandcastle/gallery/3d-models-coloring/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import * as Cesium from "cesium";
import Sandcastle from "Sandcastle";

const viewer = new Cesium.Viewer("cesiumContainer", {
infoBox: false,
selectionIndicator: false,
shadows: true,
shouldAnimate: true,
});

let entity;

function getColorBlendMode(colorBlendMode) {
return Cesium.ColorBlendMode[colorBlendMode.toUpperCase()];
}

function getColor(colorName, alpha) {
const color = Cesium.Color[colorName.toUpperCase()];
return Cesium.Color.fromAlpha(color, parseFloat(alpha));
}

// The viewModel tracks the state of our mini application.
const viewModel = {
color: "Red",
colors: ["White", "Red", "Green", "Blue", "Yellow", "Gray"],
alpha: 1.0,
colorBlendMode: "Highlight",
colorBlendModes: ["Highlight", "Replace", "Mix"],
colorBlendAmount: 0.5,
colorBlendAmountEnabled: false,
silhouetteColor: "Red",
silhouetteColors: ["Red", "Green", "Blue", "Yellow", "Gray"],
silhouetteAlpha: 1.0,
silhouetteSize: 2.0,
};

// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Totally out of scope of this PR, but we should really make a pass at getting rid of knockout from our examples. It leads to users depending on it, and ideally we want to move away from depending on it. Could you please write up an issue to take a content pass to get rid of the knockout bindings from Sandcastle examples?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think most of the places it's used in sandcastles right now are to set up sliders and more complex toolbar inputs. I was thinking this could be handled by expanding the Sandcastle "API" with more features. It's been in the back of my mind but I'll make sure it's written up somewhere

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I think it'll be good to write up an issue just in case we don't cover all the cases. If we end up doing so, then 🎉, we can close that issue.


// Bind the viewModel to the DOM elements of the UI that call for it.
const toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);

Cesium.knockout
.getObservable(viewModel, "color")
.subscribe(function (newValue) {
entity.model.color = getColor(newValue, viewModel.alpha);
});

Cesium.knockout
.getObservable(viewModel, "alpha")
.subscribe(function (newValue) {
entity.model.color = getColor(viewModel.color, newValue);
});

Cesium.knockout
.getObservable(viewModel, "colorBlendMode")
.subscribe(function (newValue) {
const colorBlendMode = getColorBlendMode(newValue);
entity.model.colorBlendMode = colorBlendMode;
viewModel.colorBlendAmountEnabled =
colorBlendMode === Cesium.ColorBlendMode.MIX;
});

Cesium.knockout
.getObservable(viewModel, "colorBlendAmount")
.subscribe(function (newValue) {
entity.model.colorBlendAmount = parseFloat(newValue);
});

Cesium.knockout
.getObservable(viewModel, "silhouetteColor")
.subscribe(function (newValue) {
entity.model.silhouetteColor = getColor(
newValue,
viewModel.silhouetteAlpha,
);
});

Cesium.knockout
.getObservable(viewModel, "silhouetteAlpha")
.subscribe(function (newValue) {
entity.model.silhouetteColor = getColor(
viewModel.silhouetteColor,
newValue,
);
});

Cesium.knockout
.getObservable(viewModel, "silhouetteSize")
.subscribe(function (newValue) {
entity.model.silhouetteSize = parseFloat(newValue);
});

function createModel(url, height) {
viewer.entities.removeAll();

const position = Cesium.Cartesian3.fromDegrees(
-123.0744619,
44.0503706,
height,
);
const heading = Cesium.Math.toRadians(135);
const pitch = 0;
const roll = 0;
const hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
const orientation = Cesium.Transforms.headingPitchRollQuaternion(
position,
hpr,
);

entity = viewer.entities.add({
name: url,
position: position,
orientation: orientation,
model: {
uri: url,
minimumPixelSize: 128,
maximumScale: 20000,
color: getColor(viewModel.color, viewModel.alpha),
colorBlendMode: getColorBlendMode(viewModel.colorBlendMode),
colorBlendAmount: parseFloat(viewModel.colorBlendAmount),
silhouetteColor: getColor(
viewModel.silhouetteColor,
viewModel.silhouetteAlpha,
),
silhouetteSize: parseFloat(viewModel.silhouetteSize),
},
});
viewer.trackedEntity = entity;
}

const options = [
{
text: "Aircraft",
onselect: function () {
createModel("../../SampleData/models/CesiumAir/Cesium_Air.glb", 5000.0);
},
},
{
text: "Ground Vehicle",
onselect: function () {
createModel("../../SampleData/models/GroundVehicle/GroundVehicle.glb", 0);
},
},
{
text: "Hot Air Balloon",
onselect: function () {
createModel(
"../../SampleData/models/CesiumBalloon/CesiumBalloon.glb",
1000.0,
);
},
},
{
text: "Milk Truck",
onselect: function () {
createModel(
"../../SampleData/models/CesiumMilkTruck/CesiumMilkTruck.glb",
0,
);
},
},
{
text: "Skinned Character",
onselect: function () {
createModel("../../SampleData/models/CesiumMan/Cesium_Man.glb", 0);
},
},
];

Sandcastle.addToolbarMenu(options);

Sandcastle.addToggleButton("Shadows", viewer.shadows, function (checked) {
viewer.shadows = checked;
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
legacyId: 3D Models Coloring.html
title: 3D Models Coloring
description: Change color of 3D models.
labels:
- Showcases
thumbnail: ./thumbnail.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions packages/sandcastle/gallery/3d-models/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<style>
@import url(../templates/bucket.css);
</style>
<div id="cesiumContainer" class="fullSize"></div>
<div id="loadingOverlay"><h1>Loading...</h1></div>
<div id="toolbar"></div>
Loading