Merge pull request #12574 from CesiumGS/sandcastle-reborn
Sandcastle Reborn
|
|
@ -22,6 +22,8 @@ jobs:
|
|||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GITHUB_REPO: ${{ github.repository }}
|
||||
GITHUB_SHA: ${{ github.sha }}
|
||||
BASE_URL: /cesium/${{ github.ref_name }}/
|
||||
DEPLOYED_URL: https://ci-builds.cesium.com/cesium/${{ github.ref_name }}/
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: install node 20
|
||||
|
|
@ -40,6 +42,8 @@ jobs:
|
|||
run: npm pack --workspaces &> /dev/null
|
||||
- name: build apps
|
||||
run: npm run build-apps
|
||||
- name: build sandcastle v2
|
||||
run: npm run build-ci -w packages/sandcastle -- -l warn
|
||||
- uses: ./.github/actions/verify-package
|
||||
- name: deploy to s3
|
||||
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ Thumbs.db
|
|||
/Apps/Sandcastle/jsHintOptions.js
|
||||
/Apps/Sandcastle/gallery/gallery-index.js
|
||||
/Apps/Sandcastle/templates/bucket.css
|
||||
/Apps/Sandcastle2
|
||||
|
||||
/Source/Assets/
|
||||
/Source/**/*.d.ts
|
||||
|
|
@ -43,4 +44,4 @@ yarn.lock
|
|||
.idea/shelf
|
||||
|
||||
# Used in the CLA checking GitHub workflow
|
||||
GoogleConfig.json
|
||||
GoogleConfig.json
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/node_modules
|
||||
packages/sandcastle/node_modules
|
||||
/ThirdParty
|
||||
/Tools/**
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
!**/*.html
|
||||
!**/*.md
|
||||
!**/*.ts
|
||||
!**/*.tsx
|
||||
|
||||
# Re-ignore a few things caught above
|
||||
|
||||
|
|
@ -34,6 +35,9 @@ packages/widgets/Build/**
|
|||
packages/widgets/index.js
|
||||
packages/widgets/Source/ThirdParty/**
|
||||
|
||||
packages/sandcastle/node_modules/**
|
||||
Apps/Sandcastle2/**
|
||||
|
||||
Specs/jasmine/**
|
||||
|
||||
Apps/Sandcastle/ThirdParty
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
import globals from "globals";
|
||||
import html from "eslint-plugin-html";
|
||||
import configCesium from "@cesium/eslint-config";
|
||||
import reactHooks from "eslint-plugin-react-hooks";
|
||||
import reactRefresh from "eslint-plugin-react-refresh";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
export default [
|
||||
{
|
||||
|
|
@ -15,6 +18,8 @@ export default [
|
|||
"Apps/HelloWorld.html",
|
||||
"Apps/Sandcastle/jsHintOptions.js",
|
||||
"Apps/Sandcastle/gallery/gallery-index.js",
|
||||
"Apps/Sandcastle2/",
|
||||
"packages/sandcastle/public/",
|
||||
"packages/engine/Source/Scene/GltfPipeline/**/*",
|
||||
"packages/engine/Source/Shaders/**/*",
|
||||
"Specs/jasmine/*",
|
||||
|
|
@ -74,6 +79,31 @@ export default [
|
|||
sourceType: "module",
|
||||
},
|
||||
},
|
||||
...[...tseslint.configs.recommended].map((config) => ({
|
||||
// This is needed to restrict to a specific path unless using the tseslint.config function
|
||||
// https://typescript-eslint.io/packages/typescript-eslint#config
|
||||
...config,
|
||||
files: ["packages/sandcastle/**/*.{ts,tsx}"],
|
||||
})),
|
||||
{
|
||||
// This config came from the vite project generation
|
||||
files: ["packages/sandcastle/**/*.{ts,tsx}"],
|
||||
languageOptions: {
|
||||
ecmaVersion: 2020,
|
||||
globals: globals.browser,
|
||||
},
|
||||
plugins: {
|
||||
"react-hooks": reactHooks,
|
||||
"react-refresh": reactRefresh,
|
||||
},
|
||||
rules: {
|
||||
...reactHooks.configs.recommended.rules,
|
||||
"react-refresh/only-export-components": [
|
||||
"warn",
|
||||
{ allowConstantExport: true },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ["Specs/**/*", "packages/**/Specs/**/*"],
|
||||
languageOptions: {
|
||||
|
|
|
|||
26
gulpfile.js
|
|
@ -43,8 +43,18 @@ if (/\.0$/.test(version)) {
|
|||
version = version.substring(0, version.length - 2);
|
||||
}
|
||||
const karmaConfigFile = resolve("./Specs/karma.conf.cjs");
|
||||
function getWorkspaces(onlyDependencies = false) {
|
||||
const dependencies = Object.keys(packageJson.dependencies);
|
||||
return onlyDependencies
|
||||
? packageJson.workspaces.filter((workspace) => {
|
||||
return dependencies.includes(
|
||||
workspace.replace("packages", `@${scope}`),
|
||||
);
|
||||
})
|
||||
: packageJson.workspaces;
|
||||
}
|
||||
|
||||
const devDeployUrl = "https://ci-builds.cesium.com/cesium/";
|
||||
const devDeployUrl = process.env.DEPLOYED_URL;
|
||||
const isProduction = process.env.PROD;
|
||||
|
||||
//Gulp doesn't seem to have a way to get the currently running tasks for setting
|
||||
|
|
@ -247,7 +257,7 @@ export async function buildTs() {
|
|||
} else if (argv.workspace) {
|
||||
workspaces = argv.workspace;
|
||||
} else {
|
||||
workspaces = packageJson.workspaces;
|
||||
workspaces = getWorkspaces(true);
|
||||
}
|
||||
|
||||
// Generate types for passed packages in order.
|
||||
|
|
@ -396,7 +406,7 @@ export async function buildDocs() {
|
|||
stdio: "inherit",
|
||||
env: Object.assign({}, process.env, {
|
||||
CESIUM_VERSION: version,
|
||||
CESIUM_PACKAGES: packageJson.workspaces,
|
||||
CESIUM_PACKAGES: getWorkspaces(true),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
|
@ -694,12 +704,10 @@ export async function deployStatus() {
|
|||
const status = argv.status;
|
||||
const message = argv.message;
|
||||
|
||||
const deployUrl = `${devDeployUrl + process.env.BRANCH}/`;
|
||||
const deployUrl = `${devDeployUrl}`;
|
||||
const zipUrl = `${deployUrl}Cesium-${version}.zip`;
|
||||
const npmUrl = `${deployUrl}cesium-${version}.tgz`;
|
||||
const coverageUrl = `${
|
||||
devDeployUrl + process.env.BRANCH
|
||||
}/Build/Coverage/index.html`;
|
||||
const coverageUrl = `${devDeployUrl}Build/Coverage/index.html`;
|
||||
|
||||
return Promise.all([
|
||||
setStatus(status, deployUrl, message, "deployment"),
|
||||
|
|
@ -1484,8 +1492,8 @@ async function getLicenseDataFromThirdPartyExtra(path, discoveredDependencies) {
|
|||
return result;
|
||||
}
|
||||
|
||||
// Resursively check the workspaces
|
||||
for (const workspace of packageJson.workspaces) {
|
||||
// Recursively check the workspaces
|
||||
for (const workspace of getWorkspaces(true)) {
|
||||
const workspacePackageJson = require(`./${workspace}/package.json`);
|
||||
result = await getLicenseDataFromPackage(
|
||||
workspacePackageJson,
|
||||
|
|
|
|||
|
|
@ -33,7 +33,12 @@
|
|||
</li>
|
||||
<li>
|
||||
<a href="Apps/Sandcastle/index.html">Sandcastle</a>
|
||||
(<a href="Build/Apps/Sandcastle/index.html">built version</a>)
|
||||
<ul>
|
||||
<li>
|
||||
<a href="Build/Apps/Sandcastle/index.html">Built Sandcastle</a>
|
||||
</li>
|
||||
<li><a href="Apps/Sandcastle2/index.html">Sandcastle v2</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="Apps/CesiumViewer/index.html?inspector=true"
|
||||
|
|
|
|||
11
package.json
|
|
@ -63,6 +63,8 @@
|
|||
"esbuild": "^0.25.0",
|
||||
"eslint": "^9.1.1",
|
||||
"eslint-plugin-html": "^8.1.1",
|
||||
"eslint-plugin-react-hooks": "^5.2.0",
|
||||
"eslint-plugin-react-refresh": "^0.4.19",
|
||||
"express": "^5.1.0",
|
||||
"globals": "^16.0.0",
|
||||
"globby": "^14.0.0",
|
||||
|
|
@ -101,6 +103,7 @@
|
|||
"rimraf": "^5.0.0",
|
||||
"tsd-jsdoc": "^2.5.0",
|
||||
"typescript": "^5.3.2",
|
||||
"typescript-eslint": "^8.30.1",
|
||||
"yargs": "^17.0.1"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
@ -113,12 +116,13 @@
|
|||
"build-ts": "gulp buildTs",
|
||||
"build-third-party": "gulp buildThirdParty",
|
||||
"build-apps": "gulp buildApps",
|
||||
"build-sandcastle": "npm run build-app --workspace packages/sandcastle",
|
||||
"clean": "gulp clean",
|
||||
"cloc": "gulp cloc",
|
||||
"coverage": "gulp coverage",
|
||||
"build-docs": "gulp buildDocs",
|
||||
"build-docs-watch": "gulp buildDocsWatch",
|
||||
"eslint": "eslint \"./**/*.*js\" \"./**/*.html\" --cache --quiet",
|
||||
"eslint": "eslint \"./**/*.*js\" \"./**/*.*ts*\" \"./**/*.html\" --cache --quiet",
|
||||
"make-zip": "gulp makeZip",
|
||||
"markdownlint": "markdownlint \"**/*.md\"",
|
||||
"release": "gulp release",
|
||||
|
|
@ -146,7 +150,7 @@
|
|||
"node": ">=18.18.0"
|
||||
},
|
||||
"lint-staged": {
|
||||
"*.{js,cjs,mjs,css,html}": [
|
||||
"*.{js,cjs,mjs,ts,tsx,css,html}": [
|
||||
"eslint --cache --quiet",
|
||||
"prettier --write"
|
||||
],
|
||||
|
|
@ -157,6 +161,7 @@
|
|||
},
|
||||
"workspaces": [
|
||||
"packages/engine",
|
||||
"packages/widgets"
|
||||
"packages/widgets",
|
||||
"packages/sandcastle"
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,14 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
# CesiumJS Sandcastle
|
||||
|
||||
This package is the application for Sandcastle.
|
||||
|
||||
## Running/Building
|
||||
|
||||
- `npm run dev`: run the development server
|
||||
- `npm run build`: alias for `npm run build-app`
|
||||
- `npm run build-app`: build to static files in `/Apps/Sandcastle2` for hosting/access from the root cesium dev server
|
||||
- `npm run build-ci`: build to static files in `/Apps/Sandcastle2` and configure paths as needed for CI deployment
|
||||
|
||||
Linting and style is managed under the project root's scripts.
|
||||
|
||||
## Expanding the ESLint configuration
|
||||
|
||||
<!-- TODO: this section was auto-generated, should figure out if we want these suggestions then remove this -->
|
||||
|
||||
If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
|
||||
|
||||
```js
|
||||
export default tseslint.config({
|
||||
extends: [
|
||||
// Remove ...tseslint.configs.recommended and replace with this
|
||||
...tseslint.configs.recommendedTypeChecked,
|
||||
// Alternatively, use this for stricter rules
|
||||
...tseslint.configs.strictTypeChecked,
|
||||
// Optionally, add this for stylistic rules
|
||||
...tseslint.configs.stylisticTypeChecked,
|
||||
],
|
||||
languageOptions: {
|
||||
// other options...
|
||||
parserOptions: {
|
||||
project: ["./tsconfig.node.json", "./tsconfig.app.json"],
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
You can also install [eslint-plugin-react-x](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-x) and [eslint-plugin-react-dom](https://github.com/Rel1cx/eslint-react/tree/main/packages/plugins/eslint-plugin-react-dom) for React-specific lint rules:
|
||||
|
||||
```js
|
||||
// eslint.config.js
|
||||
import reactX from "eslint-plugin-react-x";
|
||||
import reactDom from "eslint-plugin-react-dom";
|
||||
|
||||
export default tseslint.config({
|
||||
plugins: {
|
||||
// Add the react-x and react-dom plugins
|
||||
"react-x": reactX,
|
||||
"react-dom": reactDom,
|
||||
},
|
||||
rules: {
|
||||
// other rules...
|
||||
// Enable its recommended typescript rules
|
||||
...reactX.configs["recommended-typescript"].rules,
|
||||
...reactDom.configs.recommended.rules,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Sandcastle Reborn</title>
|
||||
<style>
|
||||
/* Load fonts for itwin-ui */
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: normal;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("/fonts/InterVariable.woff2") format("woff2");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: InterVariable;
|
||||
font-style: italic;
|
||||
font-weight: 100 900;
|
||||
font-display: swap;
|
||||
src: url("/fonts/InterVariable-Italic.woff2") format("woff2");
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app-container"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"name": "@cesium/sandcastle",
|
||||
"private": true,
|
||||
"version": "0.0.1",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --config vite.config.dev.ts",
|
||||
"build": "npm run build-app",
|
||||
"build-app": "tsc -b && vite build --config vite.config.app.ts",
|
||||
"build-ci": "tsc -b && vite build --config vite.config.ci.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@itwin/itwinui-react": "^5.0.0-alpha.14",
|
||||
"@monaco-editor/react": "^4.7.0",
|
||||
"monaco-editor": "^0.52.2",
|
||||
"pako": "^2.1.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/pako": "^2.0.3",
|
||||
"@types/react": "^19.0.10",
|
||||
"@types/react-dom": "^19.0.4",
|
||||
"@vitejs/plugin-react": "^4.3.4",
|
||||
"globals": "^15.15.0",
|
||||
"typescript": "~5.7.2",
|
||||
"vite": "^6.2.0",
|
||||
"vite-plugin-static-copy": "^2.3.1"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
window.parent.postMessage("reload", "*");
|
||||
|
||||
function defined(value) {
|
||||
return value !== undefined;
|
||||
}
|
||||
|
||||
function print(value) {
|
||||
if (value === null) {
|
||||
return "null";
|
||||
} else if (defined(value)) {
|
||||
return value.toString();
|
||||
}
|
||||
return "undefined";
|
||||
}
|
||||
|
||||
console.originalLog = console.log;
|
||||
console.log = function (d1) {
|
||||
console.originalLog.apply(console, arguments);
|
||||
window.parent.postMessage(
|
||||
{
|
||||
log: print(d1),
|
||||
},
|
||||
"*",
|
||||
);
|
||||
};
|
||||
|
||||
console.originalWarn = console.warn;
|
||||
console.warn = function (d1) {
|
||||
console.originalWarn.apply(console, arguments);
|
||||
window.parent.postMessage(
|
||||
{
|
||||
warn: defined(d1) ? d1.toString() : "undefined",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
};
|
||||
|
||||
console.originalError = console.error;
|
||||
console.error = function (d1) {
|
||||
console.originalError.apply(console, arguments);
|
||||
if (!defined(d1)) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
error: "undefined",
|
||||
},
|
||||
"*",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// Look for d1.stack, "bucket.html:line:char"
|
||||
let lineNumber = -1;
|
||||
const errorMsg = d1.toString();
|
||||
if (typeof d1.stack === "string") {
|
||||
const stack = d1.stack;
|
||||
let pos = stack.indexOf(Sandcastle.bucket);
|
||||
if (pos < 0) {
|
||||
pos = stack.indexOf("<anonymous>");
|
||||
}
|
||||
if (pos >= 0) {
|
||||
const lineStart = stack.indexOf(":", pos);
|
||||
if (lineStart > pos) {
|
||||
let lineEnd1 = stack.indexOf(":", lineStart + 1);
|
||||
const lineEnd2 = stack.indexOf("\n", lineStart + 1);
|
||||
if (
|
||||
lineEnd2 > lineStart &&
|
||||
(lineEnd2 < lineEnd1 || lineEnd1 < lineStart)
|
||||
) {
|
||||
lineEnd1 = lineEnd2;
|
||||
}
|
||||
if (lineEnd1 > lineStart) {
|
||||
/*eslint-disable no-empty*/
|
||||
try {
|
||||
lineNumber = parseInt(
|
||||
stack.substring(lineStart + 1, lineEnd1),
|
||||
10,
|
||||
);
|
||||
} catch (ex) {}
|
||||
/*eslint-enable no-empty*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (lineNumber >= 0) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
error: errorMsg,
|
||||
lineNumber: lineNumber,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
} else {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
error: errorMsg,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
window.onerror = function (errorMsg, url, lineNumber) {
|
||||
if (defined(lineNumber)) {
|
||||
if (defined(url) && url.indexOf(Sandcastle.bucket) > -1) {
|
||||
// if the URL is the bucket itself, ignore it
|
||||
url = "";
|
||||
}
|
||||
if (lineNumber < 1) {
|
||||
// Change lineNumber to the local one for highlighting.
|
||||
/*eslint-disable no-empty*/
|
||||
try {
|
||||
let pos = errorMsg.indexOf(`${Sandcastle.bucket}:`);
|
||||
if (pos < 0) {
|
||||
pos = errorMsg.indexOf("<anonymous>");
|
||||
}
|
||||
if (pos >= 0) {
|
||||
pos += 12;
|
||||
lineNumber = parseInt(errorMsg.substring(pos), 10);
|
||||
}
|
||||
} catch (ex) {}
|
||||
/*eslint-enable no-empty*/
|
||||
}
|
||||
window.parent.postMessage(
|
||||
{
|
||||
error: errorMsg,
|
||||
url: url,
|
||||
lineNumber: lineNumber,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
} else {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
error: errorMsg,
|
||||
url: url,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
}
|
||||
console.originalError.apply(console, [errorMsg]);
|
||||
return false;
|
||||
};
|
||||
|
||||
Sandcastle.declare = function (obj) {
|
||||
/*eslint-disable no-empty*/
|
||||
try {
|
||||
//Browsers such as IE don't have a stack property until you actually throw the error.
|
||||
let stack = "";
|
||||
try {
|
||||
throw new Error();
|
||||
} catch (ex) {
|
||||
stack = ex.stack.toString();
|
||||
}
|
||||
let needle = `${Sandcastle.bucket}:`; // Firefox
|
||||
let pos = stack.indexOf(needle);
|
||||
if (pos < 0) {
|
||||
needle = " (<anonymous>:"; // Chrome
|
||||
pos = stack.indexOf(needle);
|
||||
}
|
||||
if (pos < 0) {
|
||||
needle = " (Unknown script code:"; // IE 11
|
||||
pos = stack.indexOf(needle);
|
||||
}
|
||||
if (pos >= 0) {
|
||||
pos += needle.length;
|
||||
const lineNumber = parseInt(stack.substring(pos), 10);
|
||||
Sandcastle.registered.push({
|
||||
obj: obj,
|
||||
lineNumber: lineNumber,
|
||||
});
|
||||
}
|
||||
} catch (ex) {}
|
||||
/*eslint-enable no-empty*/
|
||||
};
|
||||
|
||||
Sandcastle.highlight = function (obj) {
|
||||
if (typeof obj !== "undefined") {
|
||||
for (let i = 0, len = Sandcastle.registered.length; i < len; ++i) {
|
||||
if (
|
||||
obj === Sandcastle.registered[i].obj ||
|
||||
obj.primitive === Sandcastle.registered[i].obj
|
||||
) {
|
||||
window.parent.postMessage(
|
||||
{
|
||||
highlight: Sandcastle.registered[i].lineNumber,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
window.parent.postMessage(
|
||||
{
|
||||
highlight: 0,
|
||||
},
|
||||
"*",
|
||||
);
|
||||
};
|
||||
})();
|
||||
|
|
@ -0,0 +1,111 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
let defaultAction;
|
||||
let bucket = window.location.href;
|
||||
const pos = bucket.lastIndexOf("/");
|
||||
if (pos > 0 && pos < bucket.length - 1) {
|
||||
bucket = bucket.substring(pos + 1);
|
||||
}
|
||||
|
||||
window.Sandcastle = {
|
||||
bucket: bucket,
|
||||
declare: function () {},
|
||||
highlight: function () {},
|
||||
registered: [],
|
||||
finishedLoading: function () {
|
||||
window.Sandcastle.reset();
|
||||
|
||||
if (defaultAction) {
|
||||
window.Sandcastle.highlight(defaultAction);
|
||||
defaultAction();
|
||||
defaultAction = undefined;
|
||||
}
|
||||
|
||||
document.body.className = document.body.className.replace(
|
||||
/(?:\s|^)sandcastle-loading(?:\s|$)/,
|
||||
" ",
|
||||
);
|
||||
},
|
||||
addToggleButton: function (text, checked, onchange, toolbarID) {
|
||||
window.Sandcastle.declare(onchange);
|
||||
const input = document.createElement("input");
|
||||
input.checked = checked;
|
||||
input.type = "checkbox";
|
||||
input.style.pointerEvents = "none";
|
||||
const label = document.createElement("label");
|
||||
label.appendChild(input);
|
||||
label.appendChild(document.createTextNode(text));
|
||||
label.style.pointerEvents = "none";
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "cesium-button";
|
||||
button.appendChild(label);
|
||||
|
||||
button.onclick = function () {
|
||||
window.Sandcastle.reset();
|
||||
window.Sandcastle.highlight(onchange);
|
||||
input.checked = !input.checked;
|
||||
onchange(input.checked);
|
||||
};
|
||||
|
||||
document.getElementById(toolbarID || "toolbar").appendChild(button);
|
||||
},
|
||||
addToolbarButton: function (text, onclick, toolbarID) {
|
||||
window.Sandcastle.declare(onclick);
|
||||
const button = document.createElement("button");
|
||||
button.type = "button";
|
||||
button.className = "cesium-button";
|
||||
button.onclick = function () {
|
||||
window.Sandcastle.reset();
|
||||
window.Sandcastle.highlight(onclick);
|
||||
onclick();
|
||||
};
|
||||
button.textContent = text;
|
||||
document.getElementById(toolbarID || "toolbar").appendChild(button);
|
||||
},
|
||||
addDefaultToolbarButton: function (text, onclick, toolbarID) {
|
||||
window.Sandcastle.addToolbarButton(text, onclick, toolbarID);
|
||||
defaultAction = onclick;
|
||||
},
|
||||
addDefaultToolbarMenu: function (options, toolbarID) {
|
||||
window.Sandcastle.addToolbarMenu(options, toolbarID);
|
||||
defaultAction = options[0].onselect;
|
||||
},
|
||||
addToolbarMenu: function (options, toolbarID) {
|
||||
const menu = document.createElement("select");
|
||||
menu.className = "cesium-button";
|
||||
menu.onchange = function () {
|
||||
window.Sandcastle.reset();
|
||||
const item = options[menu.selectedIndex];
|
||||
if (item && typeof item.onselect === "function") {
|
||||
item.onselect();
|
||||
}
|
||||
};
|
||||
document.getElementById(toolbarID || "toolbar").appendChild(menu);
|
||||
|
||||
if (!defaultAction && typeof options[0].onselect === "function") {
|
||||
defaultAction = options[0].onselect;
|
||||
}
|
||||
|
||||
for (let i = 0, len = options.length; i < len; ++i) {
|
||||
const option = document.createElement("option");
|
||||
option.textContent = options[i].text;
|
||||
option.value = options[i].value;
|
||||
menu.appendChild(option);
|
||||
}
|
||||
},
|
||||
reset: function () {},
|
||||
};
|
||||
|
||||
if (window.location.protocol === "file:") {
|
||||
if (
|
||||
window.confirm(
|
||||
"You must host this app on a web server.\nSee contributor's guide for more info?",
|
||||
)
|
||||
) {
|
||||
window.location =
|
||||
"https://github.com/CesiumGS/cesium/blob/main/Documentation/Contributors/BuildGuide/README.md#quickstart";
|
||||
}
|
||||
}
|
||||
})();
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
window.embedInSandcastleTemplate = function (code, addExtraLine) {
|
||||
return (
|
||||
`${
|
||||
"window.startup = async function (Cesium) {\n" +
|
||||
" 'use strict';\n" +
|
||||
"//Sandcastle_Begin\n"
|
||||
}${addExtraLine ? "\n" : ""}${code}//Sandcastle_End\n` +
|
||||
` Sandcastle.finishedLoading();\n` +
|
||||
`};\n` +
|
||||
`if (typeof Cesium !== 'undefined') {\n` +
|
||||
` window.startupCalled = true;\n` +
|
||||
` window.startup(Cesium).catch((error) => {\n` +
|
||||
` "use strict";\n` +
|
||||
` console.error(error);\n` +
|
||||
` });\n` +
|
||||
`}\n`
|
||||
);
|
||||
};
|
||||
window.decodeBase64Data = function (base64String, pako) {
|
||||
// data stored in the hash as:
|
||||
// Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
|
||||
// restore padding
|
||||
while (base64String.length % 4 !== 0) {
|
||||
base64String += "=";
|
||||
}
|
||||
let jsonString = pako.inflate(atob(base64String), {
|
||||
raw: true,
|
||||
to: "string",
|
||||
});
|
||||
// we save a few bytes by omitting the leading [" and trailing "] since they are always the same
|
||||
jsonString = `["${jsonString}"]`;
|
||||
const json = JSON.parse(jsonString);
|
||||
// index 0 is code, index 1 is html
|
||||
const code = json[0];
|
||||
const html = json[1];
|
||||
const baseHref = json[2];
|
||||
return {
|
||||
code: code,
|
||||
html: html,
|
||||
baseHref: baseHref,
|
||||
};
|
||||
};
|
||||
})();
|
||||
|
After Width: | Height: | Size: 48 KiB |
|
|
@ -0,0 +1,183 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<meta name="description" content="Create 3D models using glTF." />
|
||||
<meta name="cesium-sandcastle-labels" content="Tutorials,Showcases" />
|
||||
<title>Cesium Demo</title>
|
||||
<script type="text/javascript" src="../Sandcastle-header.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../../../Build/CesiumUnminified/Cesium.js"
|
||||
nomodule
|
||||
></script>
|
||||
<script type="module" src="../load-cesium-es6.js"></script>
|
||||
</head>
|
||||
<body
|
||||
class="sandcastle-loading"
|
||||
data-sandcastle-bucket="bucket-requirejs.html"
|
||||
>
|
||||
<style>
|
||||
@import url(../templates/bucket.css);
|
||||
</style>
|
||||
<div id="cesiumContainer" class="fullSize"></div>
|
||||
<div id="loadingOverlay"><h1>Loading...</h1></div>
|
||||
<div id="toolbar"></div>
|
||||
<script id="cesium_sandcastle_script">
|
||||
window.startup = async function (Cesium) {
|
||||
"use strict";
|
||||
//Sandcastle_Begin
|
||||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
infoBox: false,
|
||||
selectionIndicator: false,
|
||||
shadows: true,
|
||||
shouldAnimate: true,
|
||||
});
|
||||
|
||||
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,
|
||||
);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
name: url,
|
||||
position: position,
|
||||
orientation: orientation,
|
||||
model: {
|
||||
uri: url,
|
||||
minimumPixelSize: 128,
|
||||
maximumScale: 20000,
|
||||
},
|
||||
});
|
||||
viewer.trackedEntity = entity;
|
||||
}
|
||||
|
||||
const options = [
|
||||
{
|
||||
text: "Aircraft",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/CesiumAir/Cesium_Air.glb",
|
||||
5000.0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Drone",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/CesiumDrone/CesiumDrone.glb",
|
||||
150.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,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Unlit Box",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/BoxUnlit/BoxUnlit.gltf",
|
||||
10.0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Draco Compressed Model",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/DracoCompressed/CesiumMilkTruck.gltf",
|
||||
0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "KTX2 Compressed Balloon",
|
||||
onselect: function () {
|
||||
if (!Cesium.FeatureDetection.supportsBasis(viewer.scene)) {
|
||||
window.alert(
|
||||
"This browser does not support Basis Universal compressed textures",
|
||||
);
|
||||
}
|
||||
createModel(
|
||||
"../../SampleData/models/CesiumBalloonKTX2/CesiumBalloonKTX2.glb",
|
||||
1000.0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Instanced Box",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/BoxInstanced/BoxInstanced.gltf",
|
||||
15,
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Sandcastle.addToolbarMenu(options);
|
||||
//Sandcastle_End
|
||||
};
|
||||
if (typeof Cesium !== "undefined") {
|
||||
window.startupCalled = true;
|
||||
window.startup(Cesium).catch((error) => {
|
||||
"use strict";
|
||||
console.error(error);
|
||||
});
|
||||
Sandcastle.finishedLoading();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 24 KiB |
|
|
@ -0,0 +1,381 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="Add billboard images and markers to the scene."
|
||||
/>
|
||||
<meta name="cesium-sandcastle-labels" content="Beginner, Showcases" />
|
||||
<title>Cesium Demo</title>
|
||||
<script type="text/javascript" src="../Sandcastle-header.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../../../Build/CesiumUnminified/Cesium.js"
|
||||
nomodule
|
||||
></script>
|
||||
<script type="module" src="../load-cesium-es6.js"></script>
|
||||
</head>
|
||||
<body
|
||||
class="sandcastle-loading"
|
||||
data-sandcastle-bucket="bucket-requirejs.html"
|
||||
>
|
||||
<style>
|
||||
@import url(../templates/bucket.css);
|
||||
</style>
|
||||
<div id="cesiumContainer" class="fullSize"></div>
|
||||
<div id="loadingOverlay"><h1>Loading...</h1></div>
|
||||
<div id="toolbar"></div>
|
||||
<script id="cesium_sandcastle_script">
|
||||
window.startup = async function (Cesium) {
|
||||
"use strict";
|
||||
//Sandcastle_Begin
|
||||
const viewer = new Cesium.Viewer("cesiumContainer");
|
||||
|
||||
function addBillboard() {
|
||||
Sandcastle.declare(addBillboard);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function setBillboardProperties() {
|
||||
Sandcastle.declare(setBillboardProperties);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png", // default: undefined
|
||||
show: true, // default
|
||||
pixelOffset: new Cesium.Cartesian2(0, -50), // default: (0, 0)
|
||||
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
|
||||
scale: 2.0, // default: 1.0
|
||||
color: Cesium.Color.LIME, // default: WHITE
|
||||
rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
|
||||
alignedAxis: Cesium.Cartesian3.ZERO, // default
|
||||
width: 100, // default: undefined
|
||||
height: 25, // default: undefined
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeBillboardProperties() {
|
||||
Sandcastle.declare(changeBillboardProperties);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(
|
||||
-75.59777,
|
||||
40.03883,
|
||||
300000.0,
|
||||
),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
},
|
||||
});
|
||||
|
||||
const billboard = entity.billboard;
|
||||
billboard.scale = 3.0;
|
||||
billboard.color = Cesium.Color.WHITE.withAlpha(0.25);
|
||||
}
|
||||
|
||||
function sizeBillboardInMeters() {
|
||||
Sandcastle.declare(sizeBillboardInMeters);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
sizeInMeters: true,
|
||||
},
|
||||
});
|
||||
|
||||
viewer.zoomTo(entity);
|
||||
}
|
||||
|
||||
function addMultipleBillboards() {
|
||||
Sandcastle.declare(addMultipleBillboards);
|
||||
|
||||
const logoUrl = "../images/Cesium_Logo_overlay.png";
|
||||
const facilityUrl = "../images/facility.gif";
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: logoUrl,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-80.5, 35.14),
|
||||
billboard: {
|
||||
image: facilityUrl,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-80.12, 25.46),
|
||||
billboard: {
|
||||
image: facilityUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function scaleByDistance() {
|
||||
Sandcastle.declare(scaleByDistance);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/facility.gif",
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function fadeByDistance() {
|
||||
Sandcastle.declare(fadeByDistance);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
translucencyByDistance: new Cesium.NearFarScalar(
|
||||
1.5e2,
|
||||
2.0,
|
||||
1.5e7,
|
||||
0.5,
|
||||
),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function offsetByDistance() {
|
||||
Sandcastle.declare(offsetByDistance);
|
||||
Promise.all([
|
||||
Cesium.Resource.fetchImage("../images/Cesium_Logo_overlay.png"),
|
||||
Cesium.Resource.fetchImage("../images/facility.gif"),
|
||||
]).then(function (images) {
|
||||
// As viewer zooms closer to facility billboard,
|
||||
// increase pixelOffset on CesiumLogo billboard to this height
|
||||
const facilityHeight = images[1].height;
|
||||
|
||||
// colocated billboards, separate as viewer gets closer
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: images[1],
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: images[0],
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
pixelOffset: new Cesium.Cartesian2(0.0, -facilityHeight),
|
||||
pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
|
||||
1.0e3,
|
||||
1.0,
|
||||
1.5e6,
|
||||
0.0,
|
||||
),
|
||||
translucencyByDistance: new Cesium.NearFarScalar(
|
||||
1.0e3,
|
||||
1.0,
|
||||
1.5e6,
|
||||
0.1,
|
||||
),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addMarkerBillboards() {
|
||||
Sandcastle.declare(addMarkerBillboards);
|
||||
|
||||
// Add several billboards based on the above image in the atlas.
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(49, 43, 18, 18),
|
||||
color: Cesium.Color.LIME,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-84.0, 39.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(61, 23, 18, 18),
|
||||
color: new Cesium.Color(0, 0.5, 1.0, 1.0),
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-70.0, 41.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(67, 80, 14, 14),
|
||||
color: new Cesium.Color(0.5, 0.9, 1.0, 1.0),
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-73.0, 37.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(27, 103, 22, 22),
|
||||
color: Cesium.Color.RED,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-79.0, 35.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(105, 105, 18, 18),
|
||||
color: Cesium.Color.YELLOW,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function disableDepthTest() {
|
||||
Sandcastle.declare(disableDepthTest);
|
||||
|
||||
viewer.scene.globe.depthTestAgainstTerrain = true;
|
||||
|
||||
try {
|
||||
const worldTerrainProvider = await Cesium.createWorldTerrainAsync();
|
||||
|
||||
// Return early in case a different option has been selected in the meantime
|
||||
if (!viewer.scene.globe.depthTestAgainstTerrain) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewer.terrainProvider = worldTerrainProvider;
|
||||
} catch (error) {
|
||||
window.alert(`Failed to load terrain. ${error}`);
|
||||
}
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-122.1958, 46.1915),
|
||||
billboard: {
|
||||
image: "../images/facility.gif",
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
});
|
||||
viewer.scene.camera.setView({
|
||||
destination: new Cesium.Cartesian3(
|
||||
-2357576.243142461,
|
||||
-3744417.5604860787,
|
||||
4581807.855903771,
|
||||
),
|
||||
orientation: new Cesium.HeadingPitchRoll(
|
||||
5.9920811504170475,
|
||||
-0.6032820429886212,
|
||||
6.28201303164098,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
Sandcastle.addToolbarMenu([
|
||||
{
|
||||
text: "Add billboard",
|
||||
onselect: function () {
|
||||
addBillboard();
|
||||
Sandcastle.highlight(addBillboard);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Set billboard properties at creation",
|
||||
onselect: function () {
|
||||
setBillboardProperties();
|
||||
Sandcastle.highlight(setBillboardProperties);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Change billboard properties",
|
||||
onselect: function () {
|
||||
changeBillboardProperties();
|
||||
Sandcastle.highlight(changeBillboardProperties);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Size billboard in meters",
|
||||
onselect: function () {
|
||||
sizeBillboardInMeters();
|
||||
Sandcastle.highlight(sizeBillboardInMeters);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Add multiple billboards",
|
||||
onselect: function () {
|
||||
addMultipleBillboards();
|
||||
Sandcastle.highlight(addMultipleBillboards);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Scale by viewer distance",
|
||||
onselect: function () {
|
||||
scaleByDistance();
|
||||
Sandcastle.highlight(scaleByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Fade by viewer distance",
|
||||
onselect: function () {
|
||||
fadeByDistance();
|
||||
Sandcastle.highlight(fadeByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Offset by viewer distance",
|
||||
onselect: function () {
|
||||
offsetByDistance();
|
||||
Sandcastle.highlight(offsetByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Add marker billboards",
|
||||
onselect: function () {
|
||||
addMarkerBillboards();
|
||||
Sandcastle.highlight(addMarkerBillboards);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Disable the depth test when clamped to ground",
|
||||
onselect: function () {
|
||||
disableDepthTest();
|
||||
Sandcastle.highlight(disableDepthTest);
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
Sandcastle.reset = async function () {
|
||||
viewer.camera.flyHome(0);
|
||||
viewer.entities.removeAll();
|
||||
viewer.scene.terrainProvider = new Cesium.EllipsoidTerrainProvider();
|
||||
viewer.scene.globe.depthTestAgainstTerrain = false;
|
||||
};
|
||||
//Sandcastle_End
|
||||
};
|
||||
if (typeof Cesium !== "undefined") {
|
||||
window.startupCalled = true;
|
||||
window.startup(Cesium).catch((error) => {
|
||||
"use strict";
|
||||
console.error(error);
|
||||
});
|
||||
Sandcastle.finishedLoading();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 26 KiB |
|
|
@ -0,0 +1,381 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<meta
|
||||
name="description"
|
||||
content="Moon terrain visualized using 3D Tiles, tiled and hosted by Cesium ion, and shown with points of interest and additional data layers."
|
||||
/>
|
||||
<meta
|
||||
name="cesium-sandcastle-labels"
|
||||
content="Showcases, ion Assets, 3D Tiles"
|
||||
/>
|
||||
<title>Cesium Moon Terrain</title>
|
||||
<script type="text/javascript" src="../Sandcastle-header.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../../../Build/CesiumUnminified/Cesium.js"
|
||||
nomodule
|
||||
></script>
|
||||
<script type="module" src="../load-cesium-es6.js"></script>
|
||||
</head>
|
||||
<body
|
||||
class="sandcastle-loading"
|
||||
data-sandcastle-bucket="bucket-requirejs.html"
|
||||
>
|
||||
<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"></div>
|
||||
<script id="cesium_sandcastle_script">
|
||||
window.startup = async function (Cesium) {
|
||||
"use strict";
|
||||
//Sandcastle_Begin
|
||||
// Set the ellipsoid to be the moon before creating the viewer
|
||||
Cesium.Ellipsoid.default = Cesium.Ellipsoid.MOON;
|
||||
|
||||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
terrainProvider: false,
|
||||
baseLayer: false,
|
||||
timeline: false,
|
||||
animation: false,
|
||||
baseLayerPicker: false,
|
||||
geocoder: false,
|
||||
shadows: true,
|
||||
});
|
||||
|
||||
const scene = viewer.scene;
|
||||
|
||||
// Add Moon Terrain 3D Tiles
|
||||
try {
|
||||
const tileset1 = await Cesium.Cesium3DTileset.fromIonAssetId(
|
||||
2684829,
|
||||
{
|
||||
// Allow clamp to 3D Tiles
|
||||
enableCollision: true,
|
||||
},
|
||||
);
|
||||
viewer.scene.primitives.add(tileset1);
|
||||
} catch (error) {
|
||||
console.log(`Error loading tileset: ${error}`);
|
||||
}
|
||||
|
||||
// Boundary data from https://wms.lroc.asu.edu/lroc/view_rdr/SHAPEFILE_LROC_GLOBAL_MARE
|
||||
const boundariesResource =
|
||||
await Cesium.IonResource.fromAssetId(2683530);
|
||||
const boundarySource = await Cesium.GeoJsonDataSource.load(
|
||||
boundariesResource,
|
||||
{
|
||||
clampToGround: true,
|
||||
fill: Cesium.Color.fromBytes(26, 106, 113).withAlpha(0.6),
|
||||
},
|
||||
);
|
||||
boundarySource.show = false;
|
||||
viewer.dataSources.add(boundarySource);
|
||||
|
||||
// Possible Artemis 3 landing locations. data from https://files.actgate.com/lunar/A3_Named_regions.geojson
|
||||
const artemis3resource = await Cesium.IonResource.fromAssetId(2683531);
|
||||
const artemis3Source = await Cesium.GeoJsonDataSource.load(
|
||||
artemis3resource,
|
||||
{
|
||||
clampToGround: true,
|
||||
fill: Cesium.Color.fromBytes(243, 242, 99).withAlpha(0.6),
|
||||
},
|
||||
);
|
||||
artemis3Source.show = false;
|
||||
viewer.dataSources.add(artemis3Source);
|
||||
|
||||
// Positions courtesy of https://www.sciencedirect.com/science/article/abs/pii/S0019103516301518?via%3Dihub
|
||||
const pointsOfInterest = [
|
||||
{
|
||||
text: "Apollo 11",
|
||||
latitude: 0.67416,
|
||||
longitude: 23.47315,
|
||||
},
|
||||
{
|
||||
text: "Apollo 14",
|
||||
latitude: -3.64417,
|
||||
longitude: 342.52135,
|
||||
},
|
||||
{
|
||||
text: "Apollo 15",
|
||||
latitude: 26.13341,
|
||||
longitude: 3.6285,
|
||||
},
|
||||
{
|
||||
text: "Lunokhod 1",
|
||||
latitude: 38.2378,
|
||||
longitude: -35.0017,
|
||||
},
|
||||
{
|
||||
text: "Lunokhod 2",
|
||||
latitude: 25.83232,
|
||||
longitude: 30.92215,
|
||||
},
|
||||
];
|
||||
|
||||
for (const poi of pointsOfInterest) {
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(
|
||||
poi.longitude,
|
||||
poi.latitude,
|
||||
),
|
||||
label: {
|
||||
text: poi.text,
|
||||
font: "14pt Verdana",
|
||||
outlineColor: Cesium.Color.DARKSLATEGREY,
|
||||
outlineWidth: 2,
|
||||
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||||
pixelOffset: new Cesium.Cartesian2(0, -22),
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5),
|
||||
translucencyByDistance: new Cesium.NearFarScalar(
|
||||
2.5e7,
|
||||
1.0,
|
||||
4.0e7,
|
||||
0.0,
|
||||
),
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.magnitude(scene.camera.positionWC);
|
||||
}, false),
|
||||
},
|
||||
point: {
|
||||
pixelSize: 10,
|
||||
color: Cesium.Color.fromBytes(243, 242, 99),
|
||||
outlineColor: Cesium.Color.fromBytes(219, 218, 111),
|
||||
outlineWidth: 2,
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1.0, 4.0e7, 0.1),
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.magnitude(scene.camera.positionWC);
|
||||
}, false),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const seaOfTranquility = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
2134594.9298812235,
|
||||
1256488.0678322134,
|
||||
379606.9284823841,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.8518395698371783,
|
||||
-0.5014189063342804,
|
||||
-0.1514873843927112,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
-0.13054959630640847,
|
||||
-0.07684549781463353,
|
||||
0.9884591910493093,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const apollo11 = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1609100.311044896,
|
||||
733266.0643925276,
|
||||
53608.976740262646,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.41704286323660256,
|
||||
-0.7222280712427744,
|
||||
-0.5517806297183315,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.8621189850799429,
|
||||
-0.12210806245903304,
|
||||
-0.49177278965720556,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const copernicus = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1613572.8201475781,
|
||||
-677039.3827805589,
|
||||
339559.7958496013,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.10007925201262617,
|
||||
0.8771366500325052,
|
||||
-0.4696971795597116,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.9948921707513932,
|
||||
0.08196514973381885,
|
||||
-0.058917593354560566,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const tycho = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1368413.3560818078,
|
||||
-166198.00035620513,
|
||||
-1203576.7397013502,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.8601315724135887,
|
||||
-0.5073902275496569,
|
||||
0.05223825345888711,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.2639103814694499,
|
||||
-0.5303301783281616,
|
||||
-0.8056681776681204,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const shackleton = {
|
||||
destination: Cesium.Rectangle.fromBoundingSphere(
|
||||
new Cesium.BoundingSphere(
|
||||
new Cesium.Cartesian3(
|
||||
-17505.087036391753,
|
||||
38147.40236305639,
|
||||
-1769721.5748224584,
|
||||
),
|
||||
40000.0,
|
||||
),
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
0.2568703591904826,
|
||||
-0.6405212914728244,
|
||||
0.7237058060699372,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.26770932874967773,
|
||||
-0.6723714327527822,
|
||||
-0.6901075073627064,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const camera = viewer.scene.camera;
|
||||
const rotationSpeed = Cesium.Math.toRadians(0.1);
|
||||
const removeRotation = viewer.scene.postRender.addEventListener(
|
||||
function (scene, time) {
|
||||
viewer.scene.camera.rotateRight(rotationSpeed);
|
||||
},
|
||||
);
|
||||
|
||||
const options1 = [
|
||||
{
|
||||
text: "Fly to...",
|
||||
onselect: () => {},
|
||||
},
|
||||
{
|
||||
text: "Sea of Tranquility",
|
||||
onselect: function () {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(seaOfTranquility);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Apollo 11 Landing Site",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(apollo11);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Copernicus Crater",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(copernicus);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Tycho Crater",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(tycho);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Shackleton Crater (South Pole) and Artemis 3 landing options",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(shackleton);
|
||||
artemis3Source.show = true;
|
||||
},
|
||||
},
|
||||
];
|
||||
Sandcastle.addToolbarMenu(options1);
|
||||
|
||||
Sandcastle.addToggleButton(
|
||||
"Show Mare Boundaries",
|
||||
false,
|
||||
function (checked) {
|
||||
boundarySource.show = checked;
|
||||
},
|
||||
);
|
||||
|
||||
// Spin the moon on first load but disable the spinning upon any input
|
||||
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.LEFT_DOWN,
|
||||
);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.RIGHT_DOWN,
|
||||
);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.MIDDLE_DOWN,
|
||||
);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.WHEEL,
|
||||
);
|
||||
|
||||
//Sandcastle_End
|
||||
};
|
||||
if (typeof Cesium !== "undefined") {
|
||||
window.startupCalled = true;
|
||||
window.startup(Cesium).catch((error) => {
|
||||
"use strict";
|
||||
console.error(error);
|
||||
});
|
||||
Sandcastle.finishedLoading();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 29 KiB |
|
|
@ -0,0 +1,206 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<meta name="description" content="Exaggerate terrain." />
|
||||
<meta name="cesium-sandcastle-labels" content="Showcases" />
|
||||
<title>Cesium Demo</title>
|
||||
<script type="text/javascript" src="../Sandcastle-header.js"></script>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../../../Build/CesiumUnminified/Cesium.js"
|
||||
nomodule
|
||||
></script>
|
||||
<script type="module" src="../load-cesium-es6.js"></script>
|
||||
</head>
|
||||
<body
|
||||
class="sandcastle-loading"
|
||||
data-sandcastle-bucket="bucket-requirejs.html"
|
||||
>
|
||||
<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>Exaggeration</td>
|
||||
<td>
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="10"
|
||||
step="0.01"
|
||||
data-bind="value: exaggeration, valueUpdate: 'input'"
|
||||
/>
|
||||
<input type="text" size="5" data-bind="value: exaggeration" />
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Relative Height</td>
|
||||
<td>
|
||||
<input
|
||||
type="range"
|
||||
min="-1000"
|
||||
max="9000"
|
||||
step="1"
|
||||
data-bind="value: relativeHeight, valueUpdate: 'input'"
|
||||
/>
|
||||
<input type="text" size="5" data-bind="value: relativeHeight" />
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script id="cesium_sandcastle_script">
|
||||
window.startup = async function (Cesium) {
|
||||
"use strict";
|
||||
//Sandcastle_Begin
|
||||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
terrain: Cesium.Terrain.fromWorldTerrain(),
|
||||
});
|
||||
|
||||
const scene = viewer.scene;
|
||||
const globe = scene.globe;
|
||||
scene.verticalExaggeration = 2.0;
|
||||
scene.verticalExaggerationRelativeHeight = 2400.0;
|
||||
|
||||
scene.camera.setView({
|
||||
destination: new Cesium.Cartesian3(
|
||||
336567.0354790703,
|
||||
5664688.047602498,
|
||||
2923204.3566963132,
|
||||
),
|
||||
orientation: new Cesium.HeadingPitchRoll(
|
||||
1.2273281382639265,
|
||||
-0.32239612370237514,
|
||||
0.0027207329018610338,
|
||||
),
|
||||
});
|
||||
|
||||
viewer.entities.add({
|
||||
position: new Cesium.Cartesian3(
|
||||
314557.3531714575,
|
||||
5659723.771882165,
|
||||
2923538.5417330978,
|
||||
),
|
||||
ellipsoid: {
|
||||
radii: new Cesium.Cartesian3(400.0, 400.0, 400.0),
|
||||
material: Cesium.Color.RED,
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
},
|
||||
});
|
||||
|
||||
let visualizeRelativeHeight = true;
|
||||
|
||||
function updateMaterial() {
|
||||
if (visualizeRelativeHeight) {
|
||||
const height = scene.verticalExaggerationRelativeHeight;
|
||||
const exaggeration = scene.verticalExaggeration;
|
||||
const alpha = Math.min(1.0, exaggeration * 0.25);
|
||||
const layer = {
|
||||
extendUpwards: true,
|
||||
extendDownwards: true,
|
||||
entries: [
|
||||
{
|
||||
height: height + 100.0,
|
||||
color: new Cesium.Color(0.0, 1.0, 0.0, alpha * 0.25),
|
||||
},
|
||||
{
|
||||
height: height + 50.0,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha * 0.5),
|
||||
},
|
||||
{
|
||||
height: height,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha),
|
||||
},
|
||||
{
|
||||
height: height - 50.0,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha * 0.5),
|
||||
},
|
||||
{
|
||||
height: height - 100.0,
|
||||
color: new Cesium.Color(1.0, 0.0, 0.0, alpha * 0.25),
|
||||
},
|
||||
],
|
||||
};
|
||||
scene.globe.material = Cesium.createElevationBandMaterial({
|
||||
scene: scene,
|
||||
layers: [layer],
|
||||
});
|
||||
} else {
|
||||
scene.globe.material = undefined;
|
||||
}
|
||||
}
|
||||
updateMaterial();
|
||||
|
||||
const viewModel = {
|
||||
exaggeration: scene.verticalExaggeration,
|
||||
relativeHeight: scene.verticalExaggerationRelativeHeight,
|
||||
};
|
||||
|
||||
function updateExaggeration() {
|
||||
scene.verticalExaggeration = Number(viewModel.exaggeration);
|
||||
scene.verticalExaggerationRelativeHeight = Number(
|
||||
viewModel.relativeHeight,
|
||||
);
|
||||
updateMaterial();
|
||||
}
|
||||
|
||||
Cesium.knockout.track(viewModel);
|
||||
const toolbar = document.getElementById("toolbar");
|
||||
Cesium.knockout.applyBindings(viewModel, toolbar);
|
||||
for (const name in viewModel) {
|
||||
if (viewModel.hasOwnProperty(name)) {
|
||||
Cesium.knockout
|
||||
.getObservable(viewModel, name)
|
||||
.subscribe(updateExaggeration);
|
||||
}
|
||||
}
|
||||
|
||||
Sandcastle.addToggleButton(
|
||||
"Visualize Relative Height",
|
||||
visualizeRelativeHeight,
|
||||
function (checked) {
|
||||
visualizeRelativeHeight = checked;
|
||||
updateMaterial();
|
||||
},
|
||||
);
|
||||
|
||||
Sandcastle.addToolbarButton("Remove Exaggeration", function () {
|
||||
viewModel.exaggeration = 1.0;
|
||||
viewModel.relativeHeight = 0.0;
|
||||
});
|
||||
//Sandcastle_End
|
||||
};
|
||||
if (typeof Cesium !== "undefined") {
|
||||
window.startupCalled = true;
|
||||
window.startup(Cesium).catch((error) => {
|
||||
"use strict";
|
||||
console.error(error);
|
||||
});
|
||||
Sandcastle.finishedLoading();
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
After Width: | Height: | Size: 63 KiB |
|
After Width: | Height: | Size: 49 KiB |
|
After Width: | Height: | Size: 23 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
|
@ -0,0 +1,5 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="512" height="512" viewBox="0 0 512 512">
|
||||
<circle cx="256" cy="256" r="256" fill="#fff"/>
|
||||
<path d="M256 32C132.288 32 32 132.286 32 256a224 224 0 0 0 7.41 56.564c.127.114.26.237.379.336 4.128 3.41 8.94 5.16 13.8 5.16 7.43 0 14.595-4.094 20.2-11.5l70.601-93.301c11.682-15.438 28.3-24.299 45.5-24.299s33.74 8.895 45.5 24.299c10.428 13.659 45.073 59.665 67.799 89.701.932 1.232 1.947 2.4 2.92 3.6 6.16 7.594 12.7 11.5 20 11.5 7.591 0 13.505-3.656 20-11.5.993-1.2 2.038-2.36 2.98-3.6 22.922-30.159 57.355-75.935 67.801-89.701 11.703-15.422 28.3-24.299 45.5-24.299 2.437 0 4.878.3 7.287.62C440.608 95.952 354.034 32.107 256 32zm75.05 95.05a23.525 23.525 0 0 1 23.526 23.527 23.525 23.525 0 0 1-23.526 23.526 23.525 23.525 0 0 1-23.525-23.526 23.525 23.525 0 0 1 23.525-23.527z" fill="#6dabe4"/>
|
||||
<path d="M478.011 228.398c-4.666-4.399-10.09-6.538-16.158-6.538-9.114 0-15.027 4.79-20.953 11.64l-70.4 93.3c-11.698 15.502-28.2 24.299-45.4 24.299h-.268c-17.2 0-33.762-8.877-45.399-24.3l-70.4-93.3c-5.596-7.416-12.7-11.5-20.1-11.5-7.36 0-14.553 4.146-20.101 11.5l-70.399 93.3c-11.56 15.32-27.885 24.329-44.976 24.3C90.3 429.673 169.216 479.895 256 479.999c123.711 0 224-100.288 224-224a224.007 224.007 0 0 0-1.989-27.601z" fill="#709c49"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
<PAMDataset>
|
||||
<GeoTransform> -1.2000000000000000e+02, 5.0462573591253154e-02, 0.0000000000000000e+00, 4.0000000000000000e+01, 0.0000000000000000e+00, -6.6666666666666666e-02</GeoTransform>
|
||||
<Metadata domain="IMAGE_STRUCTURE">
|
||||
<MDI key="COMPRESSION">JPEG</MDI>
|
||||
<MDI key="INTERLEAVE">PIXEL</MDI>
|
||||
<MDI key="SOURCE_COLOR_SPACE">YCbCr</MDI>
|
||||
</Metadata>
|
||||
<Metadata />
|
||||
</PAMDataset>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 406 B |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 397 B |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 397 B |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 416 B |
|
After Width: | Height: | Size: 2.7 KiB |
|
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<TileMap version="1.0.0" tilemapservice="http://tms.osgeo.org/1.0.0">
|
||||
<Title>Cesium_Logo_Color.jpg</Title>
|
||||
<Abstract></Abstract>
|
||||
<SRS>EPSG:900913</SRS>
|
||||
<BoundingBox miny="19.98909517812623" minx="-119.99999999999991" maxy="39.99999999999996" maxx="-60.00762865915187"/>
|
||||
<Origin y="19.98909517812623" x="-119.99999999999991"/>
|
||||
<TileFormat width="256" height="256" mime-type="image/png" extension="png"/>
|
||||
<TileSets profile="mercator">
|
||||
<TileSet href="0" units-per-pixel="156543.03390000000945" order="0"/>
|
||||
<TileSet href="1" units-per-pixel="78271.51695000000473" order="1"/>
|
||||
<TileSet href="2" units-per-pixel="39135.75847500000236" order="2"/>
|
||||
<TileSet href="3" units-per-pixel="19567.87923750000118" order="3"/>
|
||||
<TileSet href="4" units-per-pixel="9783.93961875000059" order="4"/>
|
||||
</TileSets>
|
||||
</TileMap>
|
||||
|
||||
|
After Width: | Height: | Size: 751 B |
|
After Width: | Height: | Size: 89 KiB |
|
After Width: | Height: | Size: 114 KiB |
|
After Width: | Height: | Size: 179 B |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -0,0 +1,66 @@
|
|||
/* @import url(/Build/CesiumUnminified/Widgets/widgets.css);
|
||||
@import url(/Build/CesiumUnminified/Widgets/lighter.css); */
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #000;
|
||||
color: #eee;
|
||||
font-family: sans-serif;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fullSize {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#loadingOverlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0.9;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#loadingOverlay h1 {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
margin-top: -0.5em;
|
||||
}
|
||||
|
||||
.sandcastle-loading #loadingOverlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sandcastle-loading #toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#toolbar {
|
||||
margin: 5px;
|
||||
padding: 2px 5px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.infoPanel {
|
||||
background: rgba(42, 42, 42, 0.8);
|
||||
padding: 4px;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
@import url(../../../Source/Widgets/widgets.css);
|
||||
@import url(../../../Source/Widgets/lighter.css);
|
||||
|
||||
html {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
background: #000;
|
||||
color: #eee;
|
||||
font-family: sans-serif;
|
||||
font-size: 9pt;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.fullSize {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#loadingOverlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0.9;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#loadingOverlay h1 {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
top: 50%;
|
||||
margin-top: -0.5em;
|
||||
}
|
||||
|
||||
.sandcastle-loading #loadingOverlay {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.sandcastle-loading #toolbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#toolbar {
|
||||
margin: 5px;
|
||||
padding: 2px 5px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.infoPanel {
|
||||
background: rgba(42, 42, 42, 0.8);
|
||||
padding: 4px;
|
||||
border: 1px solid #444;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
#root {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
display: grid;
|
||||
grid-template:
|
||||
"toolbar toolbar"
|
||||
"code viewer"
|
||||
"gallery gallery";
|
||||
grid-template-columns: 50% 50%;
|
||||
grid-template-rows: max-content auto 150px;
|
||||
/* TODO: this shouldn't be needed but it works for hacky code */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
grid-area: toolbar;
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 0.5rem;
|
||||
background: var(--ids-color-bg-page-base);
|
||||
|
||||
.spacer {
|
||||
flex-grow: 10;
|
||||
}
|
||||
}
|
||||
|
||||
.editor-container {
|
||||
grid-area: code;
|
||||
|
||||
section {
|
||||
border-top: 1px solid grey;
|
||||
}
|
||||
}
|
||||
|
||||
.viewer-bucket {
|
||||
grid-area: viewer;
|
||||
width: 50vw;
|
||||
background-color: white;
|
||||
background-image: var(--_rings), var(--_gradient);
|
||||
--_rings: repeating-radial-gradient(
|
||||
circle at center,
|
||||
var(--ids-color-border-neutral-muted) 1px,
|
||||
var(--ids-color-border-neutral-muted) 3px,
|
||||
transparent 3px,
|
||||
transparent 10px
|
||||
);
|
||||
--_gradient: linear-gradient(
|
||||
180deg,
|
||||
var(--ids-color-bg-page-base) 0%,
|
||||
var(--ids-color-bg-page-depth) 100%
|
||||
);
|
||||
|
||||
.fullFrame {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.gallery {
|
||||
grid-area: gallery;
|
||||
border-top: 1px solid grey;
|
||||
background: var(--ids-color-bg-page-depth);
|
||||
}
|
||||
|
|
@ -0,0 +1,741 @@
|
|||
import { useEffect, useRef, useState } from "react";
|
||||
import "./App.css";
|
||||
|
||||
import Editor, { Monaco } from "@monaco-editor/react";
|
||||
import { editor, KeyCode } from "monaco-editor";
|
||||
import pako from "pako";
|
||||
import Gallery, { GalleryDemo } from "./Gallery.js";
|
||||
import gallery_demos from "./gallery-index.ts";
|
||||
import { Button, Root } from "@itwin/itwinui-react/bricks";
|
||||
|
||||
const local = {
|
||||
docTypes: [],
|
||||
headers: "<html><head></head><body>",
|
||||
bucketName: "starter bucket",
|
||||
emptyBucket: "",
|
||||
};
|
||||
|
||||
const defaultJsCode = 'const viewer = new Cesium.Viewer("cesiumContainer");\n';
|
||||
const defaultHtmlCode = `<style>
|
||||
@import url(bucket.css);
|
||||
</style>
|
||||
<div id="cesiumContainer" class="fullSize"></div>
|
||||
<div id="loadingOverlay"><h1>Loading...</h1></div>
|
||||
<div id="toolbar"></div>
|
||||
`;
|
||||
|
||||
function embedInSandcastleTemplate(code: string, addExtraLine: boolean) {
|
||||
console.log("embedSandcastle");
|
||||
return (
|
||||
`${
|
||||
"window.startup = async function (Cesium) {\n" +
|
||||
" 'use strict';\n" +
|
||||
"//Sandcastle_Begin\n"
|
||||
}${addExtraLine ? "\n" : ""}${code}//Sandcastle_End\n` +
|
||||
` Sandcastle.finishedLoading();\n` +
|
||||
`};\n` +
|
||||
`if (typeof Cesium !== 'undefined') {\n` +
|
||||
` window.startupCalled = true;\n` +
|
||||
` window.startup(Cesium).catch((error) => {\n` +
|
||||
` "use strict";\n` +
|
||||
` console.error(error);\n` +
|
||||
` });\n` +
|
||||
`}\n`
|
||||
);
|
||||
}
|
||||
|
||||
function activateBucketScripts(
|
||||
bucketDoc: Document,
|
||||
bucketFrame: HTMLIFrameElement,
|
||||
jsEditor: editor.IStandaloneCodeEditor,
|
||||
htmlEditor: editor.IStandaloneCodeEditor,
|
||||
) {
|
||||
console.log("activateBucketScripts");
|
||||
const headNodes = bucketDoc.head.childNodes;
|
||||
let node;
|
||||
const nodes: HTMLScriptElement[] = [];
|
||||
let i, len;
|
||||
for (i = 0, len = headNodes.length; i < len; ++i) {
|
||||
node = headNodes[i];
|
||||
// header is included in blank frame.
|
||||
if (
|
||||
node instanceof HTMLScriptElement &&
|
||||
node.src.indexOf("Sandcastle-header.js") < 0 &&
|
||||
node.src.indexOf("Cesium.js") < 0
|
||||
) {
|
||||
nodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, len = nodes.length; i < len; ++i) {
|
||||
bucketDoc.head.removeChild(nodes[i]);
|
||||
}
|
||||
|
||||
// Apply user HTML to bucket.
|
||||
const htmlElement = bucketDoc.createElement("div");
|
||||
htmlElement.innerHTML = htmlEditor.getValue();
|
||||
bucketDoc.body.appendChild(htmlElement);
|
||||
|
||||
const onScriptTagError = function () {
|
||||
if (bucketFrame.contentDocument === bucketDoc) {
|
||||
// @ts-expect-error this has type any because it's from anywhere inside the bucket
|
||||
appendConsole("consoleError", `Error loading ${this.src}`, true);
|
||||
appendConsole(
|
||||
"consoleError",
|
||||
"Make sure Cesium is built, see the Contributor's Guide for details.",
|
||||
true,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
console.log("nodes", nodes);
|
||||
|
||||
// Load each script after the previous one has loaded.
|
||||
const loadScript = function () {
|
||||
if (bucketFrame.contentDocument !== bucketDoc) {
|
||||
// A newer reload has happened, abort this.
|
||||
return;
|
||||
}
|
||||
if (nodes.length > 0) {
|
||||
while (nodes.length > 0) {
|
||||
node = nodes.shift();
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
const scriptElement = bucketDoc.createElement("script");
|
||||
let hasSrc = false;
|
||||
for (let j = 0, numAttrs = node.attributes.length; j < numAttrs; ++j) {
|
||||
const name = node.attributes[j].name;
|
||||
const val = node.attributes[j].value;
|
||||
scriptElement.setAttribute(name, val);
|
||||
if (name === "src" && val) {
|
||||
hasSrc = true;
|
||||
}
|
||||
}
|
||||
scriptElement.innerHTML = node.innerHTML;
|
||||
if (hasSrc) {
|
||||
scriptElement.onload = loadScript;
|
||||
scriptElement.onerror = onScriptTagError;
|
||||
bucketDoc.head.appendChild(scriptElement);
|
||||
} else {
|
||||
bucketDoc.head.appendChild(scriptElement);
|
||||
loadScript();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Apply user JS to bucket
|
||||
const element = bucketDoc.createElement("script");
|
||||
|
||||
// Firefox line numbers are zero-based, not one-based.
|
||||
const isFirefox = navigator.userAgent.indexOf("Firefox/") >= 0;
|
||||
|
||||
element.textContent = embedInSandcastleTemplate(
|
||||
jsEditor.getValue(),
|
||||
isFirefox,
|
||||
);
|
||||
bucketDoc.body.appendChild(element);
|
||||
}
|
||||
};
|
||||
|
||||
loadScript();
|
||||
}
|
||||
|
||||
function appendConsole(
|
||||
type: "consoleError" | "",
|
||||
message: string,
|
||||
focusPanel: boolean,
|
||||
) {
|
||||
// TODO:
|
||||
if (type === "consoleError") {
|
||||
console.error(message);
|
||||
return;
|
||||
}
|
||||
console.log(message);
|
||||
if (focusPanel) {
|
||||
// TODO:
|
||||
}
|
||||
}
|
||||
|
||||
// let bucketWaiting = false;
|
||||
|
||||
function applyBucket(
|
||||
bucketFrame: HTMLIFrameElement,
|
||||
jsEditor: editor.IStandaloneCodeEditor,
|
||||
htmlEditor: editor.IStandaloneCodeEditor,
|
||||
) {
|
||||
console.log("applyBucket");
|
||||
if (
|
||||
// local.emptyBucket &&
|
||||
// local.bucketName &&
|
||||
// typeof bucketTypes[local.bucketName] === "string"
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
true
|
||||
) {
|
||||
// bucketWaiting = false;
|
||||
const bucketDoc = bucketFrame.contentDocument;
|
||||
if (!bucketDoc) {
|
||||
console.warn(
|
||||
"tried to applyBucket before the bucket content document existed",
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (
|
||||
local.headers.substring(0, local.emptyBucket.length) !== local.emptyBucket
|
||||
) {
|
||||
appendConsole(
|
||||
"consoleError",
|
||||
`Error, first part of ${local.bucketName} must match first part of bucket.html exactly.`,
|
||||
true,
|
||||
);
|
||||
} else {
|
||||
const bodyAttributes = local.headers.match(/<body([^>]*?)>/)?.[1] ?? "";
|
||||
const attributeRegex = /([-a-z_]+)\s*="([^"]*?)"/gi;
|
||||
//group 1 attribute name, group 2 attribute value. Assumes double-quoted attributes.
|
||||
let attributeMatch;
|
||||
while ((attributeMatch = attributeRegex.exec(bodyAttributes)) !== null) {
|
||||
const attributeName = attributeMatch[1];
|
||||
const attributeValue = attributeMatch[2];
|
||||
if (attributeName === "class") {
|
||||
bucketDoc.body.className = attributeValue;
|
||||
} else {
|
||||
bucketDoc.body.setAttribute(attributeName, attributeValue);
|
||||
}
|
||||
}
|
||||
|
||||
const pos = local.headers.indexOf("</head>");
|
||||
const extraHeaders = local.headers.substring(
|
||||
local.emptyBucket.length,
|
||||
pos,
|
||||
);
|
||||
bucketDoc.head.innerHTML += extraHeaders;
|
||||
activateBucketScripts(bucketDoc, bucketFrame, jsEditor, htmlEditor);
|
||||
}
|
||||
} else {
|
||||
// bucketWaiting = true;
|
||||
}
|
||||
}
|
||||
|
||||
// window.addEventListener(
|
||||
// "message",
|
||||
// function (e) {
|
||||
// let line;
|
||||
// // The iframe (bucket.html) sends this message on load.
|
||||
// // This triggers the code to be injected into the iframe.
|
||||
// if (e.data === "reload") {
|
||||
// console.log("message reload");
|
||||
// const bucketDoc = bucketFrame.contentDocument;
|
||||
// if (!local.bucketName) {
|
||||
// // Reload fired, bucket not specified yet.
|
||||
// return;
|
||||
// }
|
||||
// if (bucketDoc.body.getAttribute("data-sandcastle-loaded") !== "yes") {
|
||||
// bucketDoc.body.setAttribute("data-sandcastle-loaded", "yes");
|
||||
// logOutput.innerHTML = "";
|
||||
// numberOfNewConsoleMessages = 0;
|
||||
// registry.byId("logContainer").set("title", "Console");
|
||||
// // This happens after a Run (F8) reloads bucket.html, to inject the editor code
|
||||
// // into the iframe, causing the demo to run there.
|
||||
// applyBucket();
|
||||
// // if (docError) {
|
||||
// // appendConsole(
|
||||
// // "consoleError",
|
||||
// // 'Documentation not available. Please run the "build-docs" build script to generate Cesium documentation.',
|
||||
// // true,
|
||||
// // );
|
||||
// // // showGallery();
|
||||
// // }
|
||||
// // if (galleryError) {
|
||||
// // appendConsole(
|
||||
// // "consoleError",
|
||||
// // "Error loading gallery, please run the build script.",
|
||||
// // true,
|
||||
// // );
|
||||
// // }
|
||||
// // if (deferredLoadError) {
|
||||
// // appendConsole(
|
||||
// // "consoleLog",
|
||||
// // `Unable to load demo named ${queryObject.src.replace(
|
||||
// // ".html",
|
||||
// // "",
|
||||
// // )}. Redirecting to HelloWorld.\n`,
|
||||
// // true,
|
||||
// // );
|
||||
// // }
|
||||
// }
|
||||
// // } else if (defined(e.data.log)) {
|
||||
// // // Console log messages from the iframe display in Sandcastle.
|
||||
// // appendConsole("consoleLog", e.data.log, false);
|
||||
// // } else if (defined(e.data.error)) {
|
||||
// // // Console error messages from the iframe display in Sandcastle
|
||||
// // let errorMsg = e.data.error;
|
||||
// // let lineNumber = e.data.lineNumber;
|
||||
// // if (defined(lineNumber)) {
|
||||
// // errorMsg += " (on line ";
|
||||
|
||||
// // if (e.data.url) {
|
||||
// // errorMsg += `${lineNumber} of ${e.data.url})`;
|
||||
// // } else {
|
||||
// // lineNumber = scriptLineToEditorLine(lineNumber);
|
||||
// // errorMsg += `${lineNumber + 1})`;
|
||||
// // line = jsEditor.setGutterMarker(
|
||||
// // lineNumber,
|
||||
// // "errorGutter",
|
||||
// // makeLineLabel(e.data.error, "errorMarker"),
|
||||
// // );
|
||||
// // jsEditor.addLineClass(line, "text", "errorLine");
|
||||
// // errorLines.push(line);
|
||||
// // scrollToLine(lineNumber);
|
||||
// // }
|
||||
// // }
|
||||
// // appendConsole("consoleError", errorMsg, true);
|
||||
// // } else if (defined(e.data.warn)) {
|
||||
// // // Console warning messages from the iframe display in Sandcastle.
|
||||
// // appendConsole("consoleWarn", e.data.warn, true);
|
||||
// // } else if (defined(e.data.highlight)) {
|
||||
// // // Hovering objects in the embedded Cesium window.
|
||||
// // highlightLine(e.data.highlight);
|
||||
// }
|
||||
// },
|
||||
// true,
|
||||
// );
|
||||
|
||||
const TYPES_URL = `${__PAGE_BASE_URL__}Source/Cesium.d.ts`;
|
||||
|
||||
// function appendCode(code, run = true) {
|
||||
// const codeMirror = getJsCodeMirror();
|
||||
// codeMirror.setValue(`${codeMirror.getValue()}\n${code}`);
|
||||
// if (run) {
|
||||
// runCesium();
|
||||
// }
|
||||
// }
|
||||
|
||||
// function appendCodeOnce(code, run = true) {
|
||||
// const codeMirror = getJsCodeMirror();
|
||||
// if (!codeMirror.getValue().includes(code)) {
|
||||
// appendCode(code, run);
|
||||
// }
|
||||
// }
|
||||
|
||||
// function prependCode(code, run = true) {
|
||||
// const codeMirror = getJsCodeMirror();
|
||||
// codeMirror.setValue(`${code}\n${codeMirror.getValue()}`);
|
||||
// if (run) {
|
||||
// runCesium();
|
||||
// }
|
||||
// }
|
||||
|
||||
// function prependCodeOnce(code, run = true) {
|
||||
// const codeMirror = getJsCodeMirror();
|
||||
// if (!codeMirror.getValue().includes(code)) {
|
||||
// prependCode(code, run);
|
||||
// }
|
||||
// }
|
||||
|
||||
type SandcastleSaveData = {
|
||||
code: string;
|
||||
html: string;
|
||||
baseHref?: string;
|
||||
};
|
||||
|
||||
function makeCompressedBase64String(data: [code: string, html: string]) {
|
||||
// data stored in the hash as:
|
||||
// Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
|
||||
let jsonString = JSON.stringify(data);
|
||||
// we save a few bytes by omitting the leading [" and trailing "] since they are always the same
|
||||
jsonString = jsonString.slice(2, 2 + jsonString.length - 4);
|
||||
const pakoString = pako.deflate(jsonString, {
|
||||
raw: true,
|
||||
level: 9,
|
||||
});
|
||||
let base64String = btoa(
|
||||
// TODO: not 100% sure why I have to do this conversion manually anymore but it works
|
||||
// https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string
|
||||
String.fromCharCode(...new Uint8Array(pakoString)),
|
||||
);
|
||||
base64String = base64String.replace(/=+$/, ""); // remove padding
|
||||
|
||||
return base64String;
|
||||
}
|
||||
|
||||
function decodeBase64Data(base64String: string): SandcastleSaveData {
|
||||
// data stored in the hash as:
|
||||
// Base64 encoded, raw DEFLATE compressed JSON array where index 0 is code, index 1 is html
|
||||
// restore padding
|
||||
while (base64String.length % 4 !== 0) {
|
||||
base64String += "=";
|
||||
}
|
||||
// https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string
|
||||
const dataArray = new Uint8Array(
|
||||
atob(base64String)
|
||||
.split("")
|
||||
.map(function (c) {
|
||||
return c.charCodeAt(0);
|
||||
}),
|
||||
);
|
||||
let jsonString = pako.inflate(dataArray, {
|
||||
raw: true,
|
||||
to: "string",
|
||||
});
|
||||
// we save a few bytes by omitting the leading [" and trailing "] since they are always the same
|
||||
jsonString = `["${jsonString}"]`;
|
||||
const json = JSON.parse(jsonString);
|
||||
// index 0 is code, index 1 is html
|
||||
const code = json[0];
|
||||
const html = json[1];
|
||||
const baseHref = json[2];
|
||||
return {
|
||||
code: code,
|
||||
html: html,
|
||||
baseHref: baseHref,
|
||||
};
|
||||
}
|
||||
|
||||
function App() {
|
||||
const jsEditorRef = useRef<editor.IStandaloneCodeEditor>(null);
|
||||
const htmlEditorRef = useRef<editor.IStandaloneCodeEditor>(null);
|
||||
const bucket = useRef<HTMLIFrameElement>(null);
|
||||
|
||||
function loadFromUrl() {
|
||||
// TODO: I don't think this is the "correct" way to do on mount/load logic but it's working
|
||||
if (
|
||||
window.location.hash.indexOf("#c=") === 0 &&
|
||||
jsEditorRef.current &&
|
||||
htmlEditorRef.current
|
||||
) {
|
||||
const base64String = window.location.hash.substr(3);
|
||||
const data = decodeBase64Data(base64String);
|
||||
|
||||
jsEditorRef.current.setValue(data.code);
|
||||
htmlEditorRef.current.setValue(data.html);
|
||||
// applyLoadedDemo(code, html);
|
||||
console.log("loadFromUrl", data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {IStandaloneCodeEditor} editor
|
||||
*/
|
||||
function handleEditorDidMount(
|
||||
editor: editor.IStandaloneCodeEditor,
|
||||
monaco: Monaco,
|
||||
) {
|
||||
jsEditorRef.current = editor;
|
||||
|
||||
monaco.editor.addCommand({
|
||||
id: "run-cesium",
|
||||
run: () => {
|
||||
runCode();
|
||||
},
|
||||
});
|
||||
|
||||
// Remove some default keybindings that get in the way
|
||||
// https://github.com/microsoft/monaco-editor/issues/102
|
||||
monaco.editor.addKeybindingRules([
|
||||
{
|
||||
// disable show command center
|
||||
keybinding: KeyCode.F1,
|
||||
command: null,
|
||||
},
|
||||
{
|
||||
// disable show error command
|
||||
keybinding: KeyCode.F8,
|
||||
command: null,
|
||||
},
|
||||
{
|
||||
// disable toggle debugger breakpoint
|
||||
keybinding: KeyCode.F9,
|
||||
command: null,
|
||||
},
|
||||
{
|
||||
// disable go to definition to allow opening dev console
|
||||
keybinding: KeyCode.F12,
|
||||
command: null,
|
||||
},
|
||||
{
|
||||
keybinding: KeyCode.F8,
|
||||
command: "run-cesium",
|
||||
},
|
||||
]);
|
||||
|
||||
loadFromUrl();
|
||||
}
|
||||
|
||||
function handleEditorWillMount(monaco: Monaco) {
|
||||
// here is the monaco instance
|
||||
// do something before editor is mounted
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.setCompilerOptions({
|
||||
// TODO: pick what target we want, probably newer than ES2020 but TS was upset with that
|
||||
target: monaco.languages.typescript.ScriptTarget.ES2020,
|
||||
allowNonTsExtensions: true,
|
||||
});
|
||||
|
||||
setTypes(monaco);
|
||||
}
|
||||
|
||||
function runCode() {
|
||||
if (!bucket.current || !bucket.current.contentWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for a race condition in some browsers where the iframe hasn't loaded yet.
|
||||
if (bucket.current.contentWindow.location.href.indexOf("bucket.html") > 0) {
|
||||
bucket.current.contentWindow.location.reload();
|
||||
}
|
||||
// applyBucket(bucket.current, jsEditorRef.current, htmlEditorRef.current);
|
||||
}
|
||||
|
||||
async function setTypes(monaco: Monaco) {
|
||||
console.log("setTypes");
|
||||
// https://microsoft.github.io/monaco-editor/playground.html?source=v0.52.2#example-extending-language-services-configure-javascript-defaults
|
||||
const cesiumTypes = await (await fetch(TYPES_URL)).text();
|
||||
// TODO: I don't know 100% why this declaration works for global module variable but it "does"
|
||||
const cesiumTypesSource = `${cesiumTypes}\nvar Cesium: typeof import('cesium');`;
|
||||
const cesiumTypesUri = "ts:filename/cesium.d.ts";
|
||||
|
||||
monaco.languages.typescript.javascriptDefaults.addExtraLib(
|
||||
cesiumTypesSource,
|
||||
cesiumTypesUri,
|
||||
);
|
||||
|
||||
monaco.editor.createModel(
|
||||
cesiumTypesSource,
|
||||
"typescript",
|
||||
monaco.Uri.parse(cesiumTypesUri),
|
||||
);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", function (e) {
|
||||
// The iframe (bucket.html) sends this message on load.
|
||||
// This triggers the code to be injected into the iframe.
|
||||
if (e.data === "reload") {
|
||||
console.log("message reload");
|
||||
if (!local.bucketName || !bucket.current) {
|
||||
// Reload fired, bucket not specified yet.
|
||||
return;
|
||||
}
|
||||
const bucketDoc = bucket.current.contentDocument;
|
||||
if (!bucketDoc) {
|
||||
// TODO: this whole handler probably needs to be set up better for things like this
|
||||
console.warn("bucket not set up yet");
|
||||
return;
|
||||
}
|
||||
if (!jsEditorRef.current || !htmlEditorRef.current) {
|
||||
console.warn("editors not set up yet");
|
||||
return;
|
||||
}
|
||||
if (bucketDoc.body.getAttribute("data-sandcastle-loaded") !== "yes") {
|
||||
bucketDoc.body.setAttribute("data-sandcastle-loaded", "yes");
|
||||
// logOutput.innerHTML = "";
|
||||
// numberOfNewConsoleMessages = 0;
|
||||
// registry.byId("logContainer").set("title", "Console");
|
||||
// This happens after a Run (F8) reloads bucket.html, to inject the editor code
|
||||
// into the iframe, causing the demo to run there.
|
||||
applyBucket(
|
||||
bucket.current,
|
||||
jsEditorRef.current,
|
||||
htmlEditorRef.current,
|
||||
);
|
||||
// if (docError) {
|
||||
// appendConsole(
|
||||
// "consoleError",
|
||||
// 'Documentation not available. Please run the "build-docs" build script to generate Cesium documentation.',
|
||||
// true,
|
||||
// );
|
||||
// // showGallery();
|
||||
// }
|
||||
// if (galleryError) {
|
||||
// appendConsole(
|
||||
// "consoleError",
|
||||
// "Error loading gallery, please run the build script.",
|
||||
// true,
|
||||
// );
|
||||
// }
|
||||
// if (deferredLoadError) {
|
||||
// appendConsole(
|
||||
// "consoleLog",
|
||||
// `Unable to load demo named ${queryObject.src.replace(
|
||||
// ".html",
|
||||
// "",
|
||||
// )}. Redirecting to HelloWorld.\n`,
|
||||
// true,
|
||||
// );
|
||||
// }
|
||||
}
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
function formatJs() {
|
||||
jsEditorRef.current?.getAction("editor.action.formatDocument")?.run();
|
||||
}
|
||||
|
||||
function nextHighestVariableName(name: string) {
|
||||
if (!jsEditorRef.current) {
|
||||
// can't find next highest if there's no code yet
|
||||
return;
|
||||
}
|
||||
const codeMirror = jsEditorRef.current;
|
||||
const code = codeMirror.getValue();
|
||||
const otherDeclarations = [
|
||||
...code.matchAll(new RegExp(`(const|let|var)\\s+${name}\\d*\\s=`, "g")),
|
||||
].length;
|
||||
const variableName = `${name}${otherDeclarations + 1}`;
|
||||
return variableName;
|
||||
}
|
||||
|
||||
function appendCode(code: string, run = false) {
|
||||
if (!jsEditorRef.current) {
|
||||
// can't append if there's no editor
|
||||
return;
|
||||
}
|
||||
jsEditorRef.current.setValue(`${jsEditorRef.current.getValue()}\n${code}`);
|
||||
if (run) {
|
||||
runCode();
|
||||
}
|
||||
}
|
||||
|
||||
function addButton() {
|
||||
appendCode(
|
||||
`
|
||||
Sandcastle.addToolbarButton("New Button", function () {
|
||||
// your code here
|
||||
});`,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function addToggle() {
|
||||
const variableName = nextHighestVariableName("toggleValue");
|
||||
|
||||
appendCode(
|
||||
`
|
||||
let ${variableName} = true;
|
||||
Sandcastle.addToggleButton("Toggle", ${variableName}, function (checked) {
|
||||
${variableName} = checked;
|
||||
});`,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function addMenu() {
|
||||
const variableName = nextHighestVariableName("options");
|
||||
|
||||
appendCode(
|
||||
`
|
||||
const ${variableName} = [
|
||||
{
|
||||
text: "Option 1",
|
||||
onselect: function () {
|
||||
// your code here, the first option is always run at load
|
||||
},
|
||||
},
|
||||
];
|
||||
Sandcastle.addToolbarMenu(${variableName});`,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
function setCode(js: string, html: string) {
|
||||
if (!jsEditorRef.current || !htmlEditorRef.current) {
|
||||
// can't find next highest if there's no code yet
|
||||
return;
|
||||
}
|
||||
jsEditorRef.current.setValue(js);
|
||||
htmlEditorRef.current.setValue(html);
|
||||
|
||||
runCode();
|
||||
}
|
||||
|
||||
function resetCode() {
|
||||
if (!jsEditorRef.current || !htmlEditorRef.current) {
|
||||
// can't find next highest if there's no code yet
|
||||
return;
|
||||
}
|
||||
jsEditorRef.current.setValue(defaultJsCode);
|
||||
htmlEditorRef.current.setValue(defaultHtmlCode);
|
||||
|
||||
window.history.replaceState({}, "", "/");
|
||||
runCode();
|
||||
}
|
||||
|
||||
function share() {
|
||||
if (!jsEditorRef.current || !htmlEditorRef.current) {
|
||||
// can't find next highest if there's no code yet
|
||||
return;
|
||||
}
|
||||
const code = jsEditorRef.current.getValue();
|
||||
const html = htmlEditorRef.current.getValue();
|
||||
console.log([code, html]);
|
||||
|
||||
const base64String = makeCompressedBase64String([code, html]);
|
||||
|
||||
// const shareUrl = `${getBaseUrl()}#c=${base64String}`;
|
||||
const shareUrl = `#c=${base64String}`;
|
||||
window.history.replaceState({}, "", shareUrl);
|
||||
}
|
||||
|
||||
function loadDemo(demo: GalleryDemo) {
|
||||
// do stuff
|
||||
setCode(demo.js ?? defaultJsCode, demo.html ?? defaultHtmlCode);
|
||||
|
||||
// format to account for any bad template strings, not ideal but better than not doing it
|
||||
formatJs();
|
||||
|
||||
// TODO: this is not the right way to save these, should be able to reference by name but this works for the demo
|
||||
share();
|
||||
}
|
||||
|
||||
const [darkTheme, setDarkTheme] = useState(false);
|
||||
|
||||
return (
|
||||
<Root colorScheme={darkTheme ? "dark" : "light"} density="dense" id="root">
|
||||
<div className="toolbar">
|
||||
<Button onClick={resetCode}>New</Button>
|
||||
<Button onClick={runCode}>Run (F8)</Button>
|
||||
<Button onClick={formatJs}>Format</Button>
|
||||
<Button onClick={addButton}>Add button</Button>
|
||||
<Button onClick={addToggle}>Add toggle</Button>
|
||||
<Button onClick={addMenu}>Add menu</Button>
|
||||
<Button onClick={share}>Share</Button>
|
||||
<div className="spacer"></div>
|
||||
<Button onClick={() => setDarkTheme(!darkTheme)}>Swap Theme</Button>
|
||||
</div>
|
||||
<div className="editor-container">
|
||||
<Editor
|
||||
height="70%"
|
||||
defaultLanguage="javascript"
|
||||
theme={darkTheme ? "vs-dark" : "light"}
|
||||
defaultValue={defaultJsCode}
|
||||
onMount={handleEditorDidMount}
|
||||
beforeMount={handleEditorWillMount}
|
||||
/>
|
||||
<Editor
|
||||
height="30%"
|
||||
defaultLanguage="html"
|
||||
theme={darkTheme ? "vs-dark" : "light"}
|
||||
defaultValue={defaultHtmlCode}
|
||||
onMount={(editor) => {
|
||||
htmlEditorRef.current = editor;
|
||||
loadFromUrl();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="viewer-bucket">
|
||||
<iframe
|
||||
ref={bucket}
|
||||
id="bucketFrame"
|
||||
src="templates/bucket.html"
|
||||
className="fullFrame"
|
||||
allowFullScreen
|
||||
></iframe>
|
||||
</div>
|
||||
<div className="gallery">
|
||||
<Gallery demos={gallery_demos} loadDemo={(demo) => loadDemo(demo)} />
|
||||
</div>
|
||||
</Root>
|
||||
);
|
||||
}
|
||||
|
||||
export default App;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
.gallery {
|
||||
grid-area: gallery;
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
padding: 0.5rem;
|
||||
|
||||
.card {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: var(--ids-color-bg-info-muted);
|
||||
padding: 0.5rem;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
height: 80%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
import { MouseEventHandler } from "react";
|
||||
import "./Gallery.css";
|
||||
|
||||
export type GalleryDemo = {
|
||||
name: string;
|
||||
isNew: boolean;
|
||||
img: string;
|
||||
js: string;
|
||||
html?: string;
|
||||
};
|
||||
|
||||
type GalleryCardProps = {
|
||||
demo: GalleryDemo;
|
||||
cardClickHandler: MouseEventHandler<HTMLDivElement>;
|
||||
};
|
||||
|
||||
function GalleryCard({ demo, cardClickHandler }: GalleryCardProps) {
|
||||
return (
|
||||
<div className="card" onClick={cardClickHandler}>
|
||||
<div>{demo.name}</div>
|
||||
<img src={`gallery/${demo.img}`} alt="" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
type GalleryProps = {
|
||||
demos: GalleryDemo[];
|
||||
loadDemo: (demo: GalleryDemo) => void;
|
||||
};
|
||||
|
||||
function Gallery({ demos, loadDemo }: GalleryProps) {
|
||||
return (
|
||||
<>
|
||||
{demos.map((demo) => {
|
||||
return (
|
||||
<GalleryCard
|
||||
key={demo.name}
|
||||
demo={demo}
|
||||
cardClickHandler={() => loadDemo(demo)}
|
||||
></GalleryCard>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default Gallery;
|
||||
|
|
@ -0,0 +1,921 @@
|
|||
import { GalleryDemo } from "./Gallery";
|
||||
|
||||
const gallery_demos: GalleryDemo[] = [
|
||||
{
|
||||
name: "3D Models",
|
||||
isNew: false,
|
||||
img: "3D Models.jpg",
|
||||
js: `const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
infoBox: false,
|
||||
selectionIndicator: false,
|
||||
shadows: true,
|
||||
shouldAnimate: true,
|
||||
});
|
||||
|
||||
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);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
name: url,
|
||||
position: position,
|
||||
orientation: orientation,
|
||||
model: {
|
||||
uri: url,
|
||||
minimumPixelSize: 128,
|
||||
maximumScale: 20000,
|
||||
},
|
||||
});
|
||||
viewer.trackedEntity = entity;
|
||||
}
|
||||
|
||||
const options = [
|
||||
{
|
||||
text: "Aircraft",
|
||||
onselect: function () {
|
||||
createModel("../../SampleData/models/CesiumAir/Cesium_Air.glb", 5000.0);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Drone",
|
||||
onselect: function () {
|
||||
createModel("../../SampleData/models/CesiumDrone/CesiumDrone.glb", 150.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);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Unlit Box",
|
||||
onselect: function () {
|
||||
createModel("../../SampleData/models/BoxUnlit/BoxUnlit.gltf", 10.0);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Draco Compressed Model",
|
||||
onselect: function () {
|
||||
createModel(
|
||||
"../../SampleData/models/DracoCompressed/CesiumMilkTruck.gltf",
|
||||
0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "KTX2 Compressed Balloon",
|
||||
onselect: function () {
|
||||
if (!Cesium.FeatureDetection.supportsBasis(viewer.scene)) {
|
||||
window.alert(
|
||||
"This browser does not support Basis Universal compressed textures",
|
||||
);
|
||||
}
|
||||
createModel(
|
||||
"../../SampleData/models/CesiumBalloonKTX2/CesiumBalloonKTX2.glb",
|
||||
1000.0,
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Instanced Box",
|
||||
onselect: function () {
|
||||
createModel("../../SampleData/models/BoxInstanced/BoxInstanced.gltf", 15);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
Sandcastle.addToolbarMenu(options);`,
|
||||
},
|
||||
{
|
||||
name: "Billboards",
|
||||
isNew: false,
|
||||
img: "Billboards.jpg",
|
||||
js: `const viewer = new Cesium.Viewer("cesiumContainer");
|
||||
|
||||
function addBillboard() {
|
||||
Sandcastle.declare(addBillboard);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function setBillboardProperties() {
|
||||
Sandcastle.declare(setBillboardProperties);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png", // default: undefined
|
||||
show: true, // default
|
||||
pixelOffset: new Cesium.Cartesian2(0, -50), // default: (0, 0)
|
||||
eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER, // default
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM, // default: CENTER
|
||||
scale: 2.0, // default: 1.0
|
||||
color: Cesium.Color.LIME, // default: WHITE
|
||||
rotation: Cesium.Math.PI_OVER_FOUR, // default: 0.0
|
||||
alignedAxis: Cesium.Cartesian3.ZERO, // default
|
||||
width: 100, // default: undefined
|
||||
height: 25, // default: undefined
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function changeBillboardProperties() {
|
||||
Sandcastle.declare(changeBillboardProperties);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883, 300000.0),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
},
|
||||
});
|
||||
|
||||
const billboard = entity.billboard;
|
||||
billboard.scale = 3.0;
|
||||
billboard.color = Cesium.Color.WHITE.withAlpha(0.25);
|
||||
}
|
||||
|
||||
function sizeBillboardInMeters() {
|
||||
Sandcastle.declare(sizeBillboardInMeters);
|
||||
|
||||
const entity = viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
sizeInMeters: true,
|
||||
},
|
||||
});
|
||||
|
||||
viewer.zoomTo(entity);
|
||||
}
|
||||
|
||||
function addMultipleBillboards() {
|
||||
Sandcastle.declare(addMultipleBillboards);
|
||||
|
||||
const logoUrl = "../images/Cesium_Logo_overlay.png";
|
||||
const facilityUrl = "../images/facility.gif";
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: logoUrl,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-80.5, 35.14),
|
||||
billboard: {
|
||||
image: facilityUrl,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-80.12, 25.46),
|
||||
billboard: {
|
||||
image: facilityUrl,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function scaleByDistance() {
|
||||
Sandcastle.declare(scaleByDistance);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/facility.gif",
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function fadeByDistance() {
|
||||
Sandcastle.declare(fadeByDistance);
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/Cesium_Logo_overlay.png",
|
||||
translucencyByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function offsetByDistance() {
|
||||
Sandcastle.declare(offsetByDistance);
|
||||
Promise.all([
|
||||
Cesium.Resource.fetchImage("../images/Cesium_Logo_overlay.png"),
|
||||
Cesium.Resource.fetchImage("../images/facility.gif"),
|
||||
]).then(function (images) {
|
||||
// As viewer zooms closer to facility billboard,
|
||||
// increase pixelOffset on CesiumLogo billboard to this height
|
||||
const facilityHeight = images[1].height;
|
||||
|
||||
// colocated billboards, separate as viewer gets closer
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: images[1],
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: images[0],
|
||||
horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
|
||||
verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
|
||||
pixelOffset: new Cesium.Cartesian2(0.0, -facilityHeight),
|
||||
pixelOffsetScaleByDistance: new Cesium.NearFarScalar(
|
||||
1.0e3,
|
||||
1.0,
|
||||
1.5e6,
|
||||
0.0,
|
||||
),
|
||||
translucencyByDistance: new Cesium.NearFarScalar(1.0e3, 1.0, 1.5e6, 0.1),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addMarkerBillboards() {
|
||||
Sandcastle.declare(addMarkerBillboards);
|
||||
|
||||
// Add several billboards based on the above image in the atlas.
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(49, 43, 18, 18),
|
||||
color: Cesium.Color.LIME,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-84.0, 39.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(61, 23, 18, 18),
|
||||
color: new Cesium.Color(0, 0.5, 1.0, 1.0),
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-70.0, 41.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(67, 80, 14, 14),
|
||||
color: new Cesium.Color(0.5, 0.9, 1.0, 1.0),
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-73.0, 37.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(27, 103, 22, 22),
|
||||
color: Cesium.Color.RED,
|
||||
},
|
||||
});
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-79.0, 35.0),
|
||||
billboard: {
|
||||
image: "../images/whiteShapes.png",
|
||||
imageSubRegion: new Cesium.BoundingRectangle(105, 105, 18, 18),
|
||||
color: Cesium.Color.YELLOW,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async function disableDepthTest() {
|
||||
Sandcastle.declare(disableDepthTest);
|
||||
|
||||
viewer.scene.globe.depthTestAgainstTerrain = true;
|
||||
|
||||
try {
|
||||
const worldTerrainProvider = await Cesium.createWorldTerrainAsync();
|
||||
|
||||
// Return early in case a different option has been selected in the meantime
|
||||
if (!viewer.scene.globe.depthTestAgainstTerrain) {
|
||||
return;
|
||||
}
|
||||
|
||||
viewer.terrainProvider = worldTerrainProvider;
|
||||
} catch (error) {
|
||||
window.alert(\`Failed to load terrain. \${error}\`);
|
||||
}
|
||||
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(-122.1958, 46.1915),
|
||||
billboard: {
|
||||
image: "../images/facility.gif",
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: Number.POSITIVE_INFINITY,
|
||||
},
|
||||
});
|
||||
viewer.scene.camera.setView({
|
||||
destination: new Cesium.Cartesian3(
|
||||
-2357576.243142461,
|
||||
-3744417.5604860787,
|
||||
4581807.855903771,
|
||||
),
|
||||
orientation: new Cesium.HeadingPitchRoll(
|
||||
5.9920811504170475,
|
||||
-0.6032820429886212,
|
||||
6.28201303164098,
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
Sandcastle.addToolbarMenu([
|
||||
{
|
||||
text: "Add billboard",
|
||||
onselect: function () {
|
||||
addBillboard();
|
||||
Sandcastle.highlight(addBillboard);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Set billboard properties at creation",
|
||||
onselect: function () {
|
||||
setBillboardProperties();
|
||||
Sandcastle.highlight(setBillboardProperties);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Change billboard properties",
|
||||
onselect: function () {
|
||||
changeBillboardProperties();
|
||||
Sandcastle.highlight(changeBillboardProperties);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Size billboard in meters",
|
||||
onselect: function () {
|
||||
sizeBillboardInMeters();
|
||||
Sandcastle.highlight(sizeBillboardInMeters);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Add multiple billboards",
|
||||
onselect: function () {
|
||||
addMultipleBillboards();
|
||||
Sandcastle.highlight(addMultipleBillboards);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Scale by viewer distance",
|
||||
onselect: function () {
|
||||
scaleByDistance();
|
||||
Sandcastle.highlight(scaleByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Fade by viewer distance",
|
||||
onselect: function () {
|
||||
fadeByDistance();
|
||||
Sandcastle.highlight(fadeByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Offset by viewer distance",
|
||||
onselect: function () {
|
||||
offsetByDistance();
|
||||
Sandcastle.highlight(offsetByDistance);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Add marker billboards",
|
||||
onselect: function () {
|
||||
addMarkerBillboards();
|
||||
Sandcastle.highlight(addMarkerBillboards);
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Disable the depth test when clamped to ground",
|
||||
onselect: function () {
|
||||
disableDepthTest();
|
||||
Sandcastle.highlight(disableDepthTest);
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
Sandcastle.reset = async function () {
|
||||
viewer.camera.flyHome(0);
|
||||
viewer.entities.removeAll();
|
||||
viewer.scene.terrainProvider = new Cesium.EllipsoidTerrainProvider();
|
||||
viewer.scene.globe.depthTestAgainstTerrain = false;
|
||||
};
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "Moon",
|
||||
isNew: false,
|
||||
img: "Moon.jpg",
|
||||
js: `// Set the ellipsoid to be the moon before creating the viewer
|
||||
Cesium.Ellipsoid.default = Cesium.Ellipsoid.MOON;
|
||||
|
||||
const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
terrainProvider: false,
|
||||
baseLayer: false,
|
||||
timeline: false,
|
||||
animation: false,
|
||||
baseLayerPicker: false,
|
||||
geocoder: false,
|
||||
shadows: true,
|
||||
});
|
||||
|
||||
const scene = viewer.scene;
|
||||
|
||||
// Add Moon Terrain 3D Tiles
|
||||
try {
|
||||
const tileset1 = await Cesium.Cesium3DTileset.fromIonAssetId(2684829, {
|
||||
// Allow clamp to 3D Tiles
|
||||
enableCollision: true,
|
||||
});
|
||||
viewer.scene.primitives.add(tileset1);
|
||||
} catch (error) {
|
||||
console.log(\`Error loading tileset: \${error}\`);
|
||||
}
|
||||
|
||||
// Boundary data from https://wms.lroc.asu.edu/lroc/view_rdr/SHAPEFILE_LROC_GLOBAL_MARE
|
||||
const boundariesResource = await Cesium.IonResource.fromAssetId(2683530);
|
||||
const boundarySource = await Cesium.GeoJsonDataSource.load(boundariesResource, {
|
||||
clampToGround: true,
|
||||
fill: Cesium.Color.fromBytes(26, 106, 113).withAlpha(0.6),
|
||||
});
|
||||
boundarySource.show = false;
|
||||
viewer.dataSources.add(boundarySource);
|
||||
|
||||
// Possible Artemis 3 landing locations. data from https://files.actgate.com/lunar/A3_Named_regions.geojson
|
||||
const artemis3resource = await Cesium.IonResource.fromAssetId(2683531);
|
||||
const artemis3Source = await Cesium.GeoJsonDataSource.load(artemis3resource, {
|
||||
clampToGround: true,
|
||||
fill: Cesium.Color.fromBytes(243, 242, 99).withAlpha(0.6),
|
||||
});
|
||||
artemis3Source.show = false;
|
||||
viewer.dataSources.add(artemis3Source);
|
||||
|
||||
// Positions courtesy of https://www.sciencedirect.com/science/article/abs/pii/S0019103516301518?via%3Dihub
|
||||
const pointsOfInterest = [
|
||||
{
|
||||
text: "Apollo 11",
|
||||
latitude: 0.67416,
|
||||
longitude: 23.47315,
|
||||
},
|
||||
{
|
||||
text: "Apollo 14",
|
||||
latitude: -3.64417,
|
||||
longitude: 342.52135,
|
||||
},
|
||||
{
|
||||
text: "Apollo 15",
|
||||
latitude: 26.13341,
|
||||
longitude: 3.6285,
|
||||
},
|
||||
{
|
||||
text: "Lunokhod 1",
|
||||
latitude: 38.2378,
|
||||
longitude: -35.0017,
|
||||
},
|
||||
{
|
||||
text: "Lunokhod 2",
|
||||
latitude: 25.83232,
|
||||
longitude: 30.92215,
|
||||
},
|
||||
];
|
||||
|
||||
for (const poi of pointsOfInterest) {
|
||||
viewer.entities.add({
|
||||
position: Cesium.Cartesian3.fromDegrees(poi.longitude, poi.latitude),
|
||||
label: {
|
||||
text: poi.text,
|
||||
font: "14pt Verdana",
|
||||
outlineColor: Cesium.Color.DARKSLATEGREY,
|
||||
outlineWidth: 2,
|
||||
style: Cesium.LabelStyle.FILL_AND_OUTLINE,
|
||||
pixelOffset: new Cesium.Cartesian2(0, -22),
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e2, 1.0, 1.5e7, 0.5),
|
||||
translucencyByDistance: new Cesium.NearFarScalar(2.5e7, 1.0, 4.0e7, 0.0),
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.magnitude(scene.camera.positionWC);
|
||||
}, false),
|
||||
},
|
||||
point: {
|
||||
pixelSize: 10,
|
||||
color: Cesium.Color.fromBytes(243, 242, 99),
|
||||
outlineColor: Cesium.Color.fromBytes(219, 218, 111),
|
||||
outlineWidth: 2,
|
||||
scaleByDistance: new Cesium.NearFarScalar(1.5e3, 1.0, 4.0e7, 0.1),
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
disableDepthTestDistance: new Cesium.CallbackProperty(() => {
|
||||
return Cesium.Cartesian3.magnitude(scene.camera.positionWC);
|
||||
}, false),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
const seaOfTranquility = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
2134594.9298812235,
|
||||
1256488.0678322134,
|
||||
379606.9284823841,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.8518395698371783,
|
||||
-0.5014189063342804,
|
||||
-0.1514873843927112,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
-0.13054959630640847,
|
||||
-0.07684549781463353,
|
||||
0.9884591910493093,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const apollo11 = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1609100.311044896,
|
||||
733266.0643925276,
|
||||
53608.976740262646,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.41704286323660256,
|
||||
-0.7222280712427744,
|
||||
-0.5517806297183315,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.8621189850799429,
|
||||
-0.12210806245903304,
|
||||
-0.49177278965720556,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const copernicus = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1613572.8201475781,
|
||||
-677039.3827805589,
|
||||
339559.7958496013,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.10007925201262617,
|
||||
0.8771366500325052,
|
||||
-0.4696971795597116,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.9948921707513932,
|
||||
0.08196514973381885,
|
||||
-0.058917593354560566,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const tycho = {
|
||||
destination: new Cesium.Cartesian3(
|
||||
1368413.3560818078,
|
||||
-166198.00035620513,
|
||||
-1203576.7397013502,
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
-0.8601315724135887,
|
||||
-0.5073902275496569,
|
||||
0.05223825345888711,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.2639103814694499,
|
||||
-0.5303301783281616,
|
||||
-0.8056681776681204,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const shackleton = {
|
||||
destination: Cesium.Rectangle.fromBoundingSphere(
|
||||
new Cesium.BoundingSphere(
|
||||
new Cesium.Cartesian3(
|
||||
-17505.087036391753,
|
||||
38147.40236305639,
|
||||
-1769721.5748224584,
|
||||
),
|
||||
40000.0,
|
||||
),
|
||||
),
|
||||
orientation: {
|
||||
direction: new Cesium.Cartesian3(
|
||||
0.2568703591904826,
|
||||
-0.6405212914728244,
|
||||
0.7237058060699372,
|
||||
),
|
||||
up: new Cesium.Cartesian3(
|
||||
0.26770932874967773,
|
||||
-0.6723714327527822,
|
||||
-0.6901075073627064,
|
||||
),
|
||||
},
|
||||
easingFunction: Cesium.EasingFunction.LINEAR_NONE,
|
||||
};
|
||||
|
||||
const camera = viewer.scene.camera;
|
||||
const rotationSpeed = Cesium.Math.toRadians(0.1);
|
||||
const removeRotation = viewer.scene.postRender.addEventListener(
|
||||
function (scene, time) {
|
||||
viewer.scene.camera.rotateRight(rotationSpeed);
|
||||
},
|
||||
);
|
||||
|
||||
const options1 = [
|
||||
{
|
||||
text: "Fly to...",
|
||||
onselect: () => {},
|
||||
},
|
||||
{
|
||||
text: "Sea of Tranquility",
|
||||
onselect: function () {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(seaOfTranquility);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Apollo 11 Landing Site",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(apollo11);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Copernicus Crater",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(copernicus);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Tycho Crater",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(tycho);
|
||||
artemis3Source.show = false;
|
||||
},
|
||||
},
|
||||
{
|
||||
text: "Shackleton Crater (South Pole) and Artemis 3 landing options",
|
||||
onselect: () => {
|
||||
removeRotation();
|
||||
scene.camera.flyTo(shackleton);
|
||||
artemis3Source.show = true;
|
||||
},
|
||||
},
|
||||
];
|
||||
Sandcastle.addToolbarMenu(options1);
|
||||
|
||||
Sandcastle.addToggleButton("Show Mare Boundaries", false, function (checked) {
|
||||
boundarySource.show = checked;
|
||||
});
|
||||
|
||||
// Spin the moon on first load but disable the spinning upon any input
|
||||
const handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.LEFT_DOWN,
|
||||
);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.RIGHT_DOWN,
|
||||
);
|
||||
handler.setInputAction(
|
||||
() => removeRotation(),
|
||||
Cesium.ScreenSpaceEventType.MIDDLE_DOWN,
|
||||
);
|
||||
handler.setInputAction(() => removeRotation(), Cesium.ScreenSpaceEventType.WHEEL);
|
||||
|
||||
`,
|
||||
html: `<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"></div>
|
||||
`,
|
||||
},
|
||||
{
|
||||
name: "Terrain Exaggeration",
|
||||
isNew: false,
|
||||
img: "Terrain Exaggeration.jpg",
|
||||
js: `const viewer = new Cesium.Viewer("cesiumContainer", {
|
||||
terrain: Cesium.Terrain.fromWorldTerrain(),
|
||||
});
|
||||
|
||||
const scene = viewer.scene;
|
||||
const globe = scene.globe;
|
||||
scene.verticalExaggeration = 2.0;
|
||||
scene.verticalExaggerationRelativeHeight = 2400.0;
|
||||
|
||||
scene.camera.setView({
|
||||
destination: new Cesium.Cartesian3(
|
||||
336567.0354790703,
|
||||
5664688.047602498,
|
||||
2923204.3566963132,
|
||||
),
|
||||
orientation: new Cesium.HeadingPitchRoll(
|
||||
1.2273281382639265,
|
||||
-0.32239612370237514,
|
||||
0.0027207329018610338,
|
||||
),
|
||||
});
|
||||
|
||||
viewer.entities.add({
|
||||
position: new Cesium.Cartesian3(
|
||||
314557.3531714575,
|
||||
5659723.771882165,
|
||||
2923538.5417330978,
|
||||
),
|
||||
ellipsoid: {
|
||||
radii: new Cesium.Cartesian3(400.0, 400.0, 400.0),
|
||||
material: Cesium.Color.RED,
|
||||
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
|
||||
},
|
||||
});
|
||||
|
||||
let visualizeRelativeHeight = true;
|
||||
|
||||
function updateMaterial() {
|
||||
if (visualizeRelativeHeight) {
|
||||
const height = scene.verticalExaggerationRelativeHeight;
|
||||
const exaggeration = scene.verticalExaggeration;
|
||||
const alpha = Math.min(1.0, exaggeration * 0.25);
|
||||
const layer = {
|
||||
extendUpwards: true,
|
||||
extendDownwards: true,
|
||||
entries: [
|
||||
{
|
||||
height: height + 100.0,
|
||||
color: new Cesium.Color(0.0, 1.0, 0.0, alpha * 0.25),
|
||||
},
|
||||
{
|
||||
height: height + 50.0,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha * 0.5),
|
||||
},
|
||||
{
|
||||
height: height,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha),
|
||||
},
|
||||
{
|
||||
height: height - 50.0,
|
||||
color: new Cesium.Color(1.0, 1.0, 1.0, alpha * 0.5),
|
||||
},
|
||||
{
|
||||
height: height - 100.0,
|
||||
color: new Cesium.Color(1.0, 0.0, 0.0, alpha * 0.25),
|
||||
},
|
||||
],
|
||||
};
|
||||
scene.globe.material = Cesium.createElevationBandMaterial({
|
||||
scene: scene,
|
||||
layers: [layer],
|
||||
});
|
||||
} else {
|
||||
scene.globe.material = undefined;
|
||||
}
|
||||
}
|
||||
updateMaterial();
|
||||
|
||||
const viewModel = {
|
||||
exaggeration: scene.verticalExaggeration,
|
||||
relativeHeight: scene.verticalExaggerationRelativeHeight,
|
||||
};
|
||||
|
||||
function updateExaggeration() {
|
||||
scene.verticalExaggeration = Number(viewModel.exaggeration);
|
||||
scene.verticalExaggerationRelativeHeight = Number(viewModel.relativeHeight);
|
||||
updateMaterial();
|
||||
}
|
||||
|
||||
Cesium.knockout.track(viewModel);
|
||||
const toolbar = document.getElementById("toolbar");
|
||||
Cesium.knockout.applyBindings(viewModel, toolbar);
|
||||
for (const name in viewModel) {
|
||||
if (viewModel.hasOwnProperty(name)) {
|
||||
Cesium.knockout.getObservable(viewModel, name).subscribe(updateExaggeration);
|
||||
}
|
||||
}
|
||||
|
||||
Sandcastle.addToggleButton(
|
||||
"Visualize Relative Height",
|
||||
visualizeRelativeHeight,
|
||||
function (checked) {
|
||||
visualizeRelativeHeight = checked;
|
||||
updateMaterial();
|
||||
},
|
||||
);
|
||||
|
||||
Sandcastle.addToolbarButton("Remove Exaggeration", function () {
|
||||
viewModel.exaggeration = 1.0;
|
||||
viewModel.relativeHeight = 0.0;
|
||||
});
|
||||
`,
|
||||
html: `<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>Exaggeration</td>
|
||||
<td>
|
||||
<input type="range" min="0" max="10" step="0.01" data-bind="value: exaggeration, valueUpdate: 'input'">
|
||||
<input type="text" size="5" data-bind="value: exaggeration">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Relative Height</td>
|
||||
<td>
|
||||
<input type="range" min="-1000" max="9000" step="1" data-bind="value: relativeHeight, valueUpdate: 'input'">
|
||||
<input type="text" size="5" data-bind="value: relativeHeight">
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
`,
|
||||
},
|
||||
];
|
||||
|
||||
export default gallery_demos;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import { StrictMode } from "react";
|
||||
import { createRoot } from "react-dom/client";
|
||||
import "./reset.css"; // TODO: this may not be needed with itwin-ui
|
||||
import App from "./App.tsx";
|
||||
|
||||
createRoot(document.getElementById("app-container")!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
);
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/* https://www.joshwcomeau.com/css/custom-css-reset/ */
|
||||
|
||||
/* 1. Use a more-intuitive box-sizing model */
|
||||
*,
|
||||
*::before,
|
||||
*::after {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
/* 2. Remove default margin */
|
||||
* {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* 3. Enable keyword animations */
|
||||
html {
|
||||
interpolate-size: allow-keywords;
|
||||
}
|
||||
|
||||
body {
|
||||
/* 4. Add accessible line-height */
|
||||
line-height: 1.5;
|
||||
/* 5. Improve text rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
/* 6. Improve media defaults */
|
||||
img,
|
||||
picture,
|
||||
video,
|
||||
canvas,
|
||||
svg {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* 7. Inherit fonts for form controls */
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
/* 8. Avoid text overflows */
|
||||
p,
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
/* 9. Improve line wrapping */
|
||||
p {
|
||||
text-wrap: pretty;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
text-wrap: balance;
|
||||
}
|
||||
|
||||
/*
|
||||
10. Create a root stacking context
|
||||
*/
|
||||
#root,
|
||||
#__next {
|
||||
isolation: isolate;
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
/// <reference types="vite/client" />
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta
|
||||
name="viewport"
|
||||
content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
|
||||
/>
|
||||
<title>Cesium Demo</title>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../Sandcastle-header.js"
|
||||
vite-ignore
|
||||
></script>
|
||||
<script src="__CESIUM_BASE_URL__/Cesium.js" vite-ignore></script>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="__CESIUM_BASE_URL__/Widgets/widgets.css"
|
||||
vite-ignore
|
||||
/>
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="__CESIUM_BASE_URL__/Widgets/lighter.css"
|
||||
vite-ignore
|
||||
/>
|
||||
<script>
|
||||
window.CESIUM_BASE_URL = "__CESIUM_BASE_URL__";
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script
|
||||
type="text/javascript"
|
||||
src="../Sandcastle-client.js"
|
||||
vite-ignore
|
||||
></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
||||
"target": "ES2020",
|
||||
"useDefineForClassFields": true,
|
||||
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
"jsx": "react-jsx",
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["src", "vite-env.d.ts"]
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"files": [],
|
||||
"references": [
|
||||
{ "path": "./tsconfig.app.json" },
|
||||
{ "path": "./tsconfig.node.json" }
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
||||
"target": "ES2022",
|
||||
"lib": ["ES2023"],
|
||||
"module": "ESNext",
|
||||
"skipLibCheck": true,
|
||||
|
||||
/* Bundler mode */
|
||||
"moduleResolution": "bundler",
|
||||
"allowImportingTsExtensions": true,
|
||||
"isolatedModules": true,
|
||||
"moduleDetection": "force",
|
||||
"noEmit": true,
|
||||
|
||||
/* Linting */
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"noUncheckedSideEffectImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
// <reference types="vite/client" />
|
||||
|
||||
const __PAGE_BASE_URL__: string;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { defineConfig, UserConfig } from "vite";
|
||||
|
||||
import baseConfig, { cesiumPathReplace } from "./vite.config.ts";
|
||||
|
||||
export default defineConfig(() => {
|
||||
const cesiumBaseUrl = "/Build/CesiumUnminified";
|
||||
|
||||
const config: UserConfig = baseConfig;
|
||||
// This will make the built files point to routes in the correct nested path
|
||||
// for the normal local server.js to work correctly
|
||||
config.base = "/Apps/Sandcastle2";
|
||||
|
||||
config.build = {
|
||||
...config.build,
|
||||
outDir: "../../Apps/Sandcastle2",
|
||||
};
|
||||
|
||||
config.define = {
|
||||
...config.define,
|
||||
__PAGE_BASE_URL__: JSON.stringify("/"),
|
||||
};
|
||||
|
||||
const plugins = config.plugins ?? [];
|
||||
config.plugins = [...plugins, cesiumPathReplace(cesiumBaseUrl)];
|
||||
|
||||
return config;
|
||||
});
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import { defineConfig, UserConfig } from "vite";
|
||||
|
||||
import baseConfig, { cesiumPathReplace } from "./vite.config.ts";
|
||||
|
||||
export default defineConfig(() => {
|
||||
const cesiumBaseUrl = `${process.env.BASE_URL}Build/CesiumUnminified`;
|
||||
|
||||
console.log("Building Sandcastle with base url:", cesiumBaseUrl);
|
||||
|
||||
const config: UserConfig = baseConfig;
|
||||
// This will make the built files point to routes in the correct nested path
|
||||
// based on the ci branch path
|
||||
config.base = `${process.env.BASE_URL}Apps/Sandcastle2`;
|
||||
|
||||
config.define = {
|
||||
...config.define,
|
||||
__PAGE_BASE_URL__: JSON.stringify(process.env.BASE_URL),
|
||||
};
|
||||
|
||||
config.build = {
|
||||
...config.build,
|
||||
outDir: "../../Apps/Sandcastle2",
|
||||
};
|
||||
|
||||
const plugins = config.plugins ?? [];
|
||||
config.plugins = [...plugins, cesiumPathReplace(cesiumBaseUrl)];
|
||||
|
||||
return config;
|
||||
});
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
import { defineConfig, UserConfig } from "vite";
|
||||
import { viteStaticCopy } from "vite-plugin-static-copy";
|
||||
import baseConfig, { cesiumPathReplace } from "./vite.config.ts";
|
||||
|
||||
export default defineConfig(() => {
|
||||
const config: UserConfig = baseConfig;
|
||||
|
||||
const cesiumSource = "../../Build/CesiumUnminified";
|
||||
const cesiumBaseUrl = "Build/CesiumUnminified";
|
||||
|
||||
const copyPlugin = viteStaticCopy({
|
||||
targets: [
|
||||
{ src: `${cesiumSource}/ThirdParty`, dest: cesiumBaseUrl },
|
||||
{ src: `${cesiumSource}/Workers`, dest: cesiumBaseUrl },
|
||||
{ src: `${cesiumSource}/Assets`, dest: cesiumBaseUrl },
|
||||
{ src: `${cesiumSource}/Widgets`, dest: cesiumBaseUrl },
|
||||
{ src: `${cesiumSource}/Cesium.js`, dest: cesiumBaseUrl },
|
||||
{ src: `../../Source/Cesium.d.ts`, dest: "Source" },
|
||||
{ src: "../../Apps/SampleData", dest: "Apps" },
|
||||
{ src: "../../Apps/SampleData", dest: "" },
|
||||
],
|
||||
});
|
||||
|
||||
config.define = {
|
||||
...config.define,
|
||||
__PAGE_BASE_URL__: JSON.stringify("/"),
|
||||
};
|
||||
|
||||
const plugins = config.plugins ?? [];
|
||||
config.plugins = [
|
||||
...plugins,
|
||||
copyPlugin,
|
||||
cesiumPathReplace(`/${cesiumBaseUrl}`),
|
||||
];
|
||||
|
||||
return config;
|
||||
});
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
import { fileURLToPath } from "url";
|
||||
import react from "@vitejs/plugin-react";
|
||||
import { PluginOption, UserConfig } from "vite";
|
||||
|
||||
// https://vite.dev/config/
|
||||
const baseConfig: UserConfig = {
|
||||
plugins: [react()],
|
||||
server: {
|
||||
// Given the nature of loading and constructing a CesiumJS Viewer on startup HMR can get memory intensive
|
||||
// The state of the editor could also be lost when developing if the page refreshes unexpectedly
|
||||
hmr: false,
|
||||
},
|
||||
build: {
|
||||
// "the outDir may not be inside project root and will not be emptied without this setting
|
||||
emptyOutDir: true,
|
||||
rollupOptions: {
|
||||
input: {
|
||||
index: fileURLToPath(new URL("./index.html", import.meta.url)),
|
||||
bucket: fileURLToPath(
|
||||
new URL("./templates/bucket.html", import.meta.url),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
export default baseConfig;
|
||||
|
||||
/**
|
||||
* Replace path values in
|
||||
* @param cesiumBaseUrl Path to use for replacement
|
||||
*/
|
||||
export const cesiumPathReplace = (cesiumBaseUrl: string): PluginOption => {
|
||||
return {
|
||||
name: "custom-cesium-path-plugin",
|
||||
config(config) {
|
||||
config.define = {
|
||||
...config.define,
|
||||
__CESIUM_BASE_URL__: JSON.stringify(cesiumBaseUrl),
|
||||
};
|
||||
},
|
||||
transformIndexHtml(html) {
|
||||
return html.replaceAll("__CESIUM_BASE_URL__", `${cesiumBaseUrl}`);
|
||||
},
|
||||
};
|
||||
};
|
||||