Skip to content

Commit e376ea9

Browse files
committed
demo app updates
1 parent 4b97a56 commit e376ea9

File tree

1 file changed

+107
-94
lines changed

1 file changed

+107
-94
lines changed

src/main.js

Lines changed: 107 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -11,39 +11,42 @@ import {
1111
HeadingPitchRoll,
1212
Transforms,
1313
GeoJsonDataSource,
14-
//HeadingPitchRange,
14+
HeadingPitchRange,
1515
VerticalOrigin,
1616
HorizontalOrigin,
1717
HeightReference,
1818
Color,
19+
Ion,
1920
defined,
20-
Cartographic,
2121
ScreenSpaceEventType,
2222
ScreenSpaceEventHandler,
2323
} from "cesium";
2424
import "cesium/Build/Cesium/Widgets/widgets.css";
2525
import "./style.css";
2626

27-
// Step 3: Initialize the Cesium Viewer in the HTML element with the
27+
// Step 1.2: Add you default Cesium ion access token
28+
Ion.defaultAccessToken = "your_ion_token_here";
29+
30+
// Step 1.3: Initialize the Cesium Viewer in the HTML element with the
2831
// `cesiumContainer` ID and visualize terrain
2932
const viewer = new Viewer("cesiumContainer", {
3033
terrain: Terrain.fromWorldTerrain(),
3134
infoBox: false,
3235
});
3336

34-
// Step 4: Add aerial imagery later with labels
37+
// Step 1.4: Add aerial imagery later with labels
3538
viewer.imageryLayers.add(
3639
ImageryLayer.fromWorldImagery({
3740
style: IonWorldImageryStyle.AERIAL_WITH_LABELS,
3841
}),
3942
);
4043

41-
// Step 5: Add Cesium OSM Buildings, a global 3D buildings layer.
44+
// Step 1.5: Add Cesium OSM Buildings, a global 3D buildings layer.
4245
createOsmBuildingsAsync().then((buildingTileset) => {
4346
viewer.scene.primitives.add(buildingTileset);
4447
});
4548

46-
// Step 6: Enable lighting the globe, set time of day, and turn on animation sped up 60x
49+
// Step 1.6: Enable lighting the globe, set time of day, and turn on animation sped up 60x
4750
viewer.scene.globe.enableLighting = true;
4851
const customTime = JulianDate.fromDate(
4952
new Date(Date.UTC(2025, 5, 10, 3, 0, 0)),
@@ -52,19 +55,22 @@ viewer.clock.currentTime = customTime;
5255
viewer.clock.shouldAnimate = true;
5356
viewer.clock.multiplier = 60;
5457

55-
// Step 7: Fly the camera to San Francisco at the given longitude, latitude, and height
58+
// Step 1.7: Fly the camera to San Francisco at the given longitude, latitude, and height
5659
// and orient the camera at the given heading and pitch
57-
viewer.camera.flyTo({
58-
destination: Cartesian3.fromDegrees(-122.4075, 37.655, 400),
59-
orientation: {
60-
heading: CesiumMath.toRadians(310.0),
61-
pitch: CesiumMath.toRadians(-10.0),
62-
},
63-
});
60+
function setCamera() {
61+
const position = Cartesian3.fromDegrees(-122.4075, 37.655, 400);
62+
const heading = CesiumMath.toRadians(310.0);
63+
const pitch = CesiumMath.toRadians(-10.0);
64+
const range = 250;
65+
const hpr = new HeadingPitchRange(heading, pitch, range);
66+
67+
viewer.camera.lookAt(position, hpr);
68+
}
69+
setCamera();
6470

71+
// Step 2.1: Upload 3D model to the scene
6572
const position = Cartesian3.fromDegrees(-122.4875, 37.705, 300);
6673

67-
// add glTF model to the scene
6874
function addModel(position) {
6975
viewer.entities.removeAll();
7076

@@ -85,36 +91,40 @@ function addModel(position) {
8591
},
8692
});
8793
}
94+
addModel(position);
95+
96+
// Step 2.2 Upload a GeoJSON to the scene
97+
let geoJsonDataSourceReference;
8898

8999
function addGeoJson() {
90100
// Geojson url for South San Francisco Parks in public data portal https://data-southcity.opendata.arcgis.com/datasets/5851bfc2d1d445e3ac032b0a5f615313_0/explore
91101
const geojsonUrl =
92102
"https://services5.arcgis.com/inY93B27l4TSbT7h/arcgis/rest/services/SSF_Parks/FeatureServer/0/query?outFields=*&where=1%3D1&f=geojson";
93-
//const geojsonUrl = "./src/SSF_Parks.geojson"
94103

95104
GeoJsonDataSource.load(geojsonUrl, {
96105
clampToGround: true,
97106
}).then((dataSource) => {
98-
console.log(dataSource);
107+
geoJsonDataSourceReference = dataSource;
108+
99109
viewer.dataSources.add(dataSource);
100110
const entities = dataSource.entities.values;
101111
for (let i = 0; i < entities.length; i++) {
102112
const entity = entities[i];
103113

104114
if (defined(entity.polygon)) {
105-
// Style the polygon
106-
const color = Color.fromRandom({
107-
alpha: 1.0,
108-
});
109-
entity.polygon.material = color;
115+
// Step 3.1 Style a polygon
116+
const category = entity.properties.Category.getValue(JulianDate.now());
110117

111-
// Display the label for each polygon
118+
// Step 3.2 Use a color palette
119+
const color = Color.fromCssColorString(getCategoryColor(category));
120+
entity.polygon.material = color.withAlpha(0.6);
112121
const center = getPolygonCenter(entity);
113122

123+
// Step 3.3 Add label for a polygon
114124
viewer.entities.add({
115125
position: center,
116126
point: {
117-
color: Color.CORNFLOWERBLUE,
127+
color: color,
118128
pixelSize: 18,
119129
outlineColor: Color.DARKSLATEGREY,
120130
outlineWidth: 3,
@@ -123,7 +133,7 @@ function addGeoJson() {
123133
},
124134
label: {
125135
text: entity.properties.FACID,
126-
font: "14pt sans-serif",
136+
font: "12pt monospace",
127137
heightReference: HeightReference.CLAMP_TO_GROUND,
128138
horizontalOrigin: HorizontalOrigin.LEFT,
129139
verticalOrigin: VerticalOrigin.BASELINE,
@@ -140,6 +150,19 @@ function addGeoJson() {
140150
});
141151
}
142152

153+
function getCategoryColor(category) {
154+
const colorMap = {
155+
"Parks – City (developed)": "#a6cee3",
156+
"Parks – City (undeveloped/open space)": "#1f78b4",
157+
"Parks – City (trails)": "#b2df8a",
158+
"Parks (SSFUSD-owned sites)": "#33a02c",
159+
"Parks (other, privately owned)": "#fb9a99",
160+
default: "#CCCCCC",
161+
};
162+
163+
return colorMap[category] || colorMap["default"];
164+
}
165+
143166
function getPolygonCenter(entity) {
144167
const hierarchy = entity.polygon.hierarchy.getValue(JulianDate.now());
145168
const positions = hierarchy.positions;
@@ -156,6 +179,7 @@ function getPolygonCenter(entity) {
156179

157180
return Cartesian3.divideByScalar(center, positions.length, new Cartesian3());
158181
}
182+
addGeoJson();
159183

160184
function addEntity() {
161185
viewer.entities.add({
@@ -167,91 +191,80 @@ function addEntity() {
167191
},
168192
});
169193
}
194+
addEntity();
170195

171-
// function rotateCamera() {
172-
// viewer.clock.onTick.addEventListener(function (clock) {
173-
// viewer.scene.camera.rotateRight(0.0000001);
174-
// viewer.scene.camera.rotateDown(0.0000005);
175-
// });
176-
// }
177-
178-
// function orbitPoint(position) {
179-
// const pitch = CesiumMath.toRadians(-15);
180-
// const range = 1000.0; // Distance from the point
181-
// viewer.scene.preRender.addEventListener(function(scene, time) {
182-
// const delta = JulianDate.secondsDifference(time, viewer.clock.startTime);
183-
// const newHeading = CesiumMath.toRadians(delta/5); // degrees/sec
184-
185-
// viewer.camera.lookAt(position, new HeadingPitchRange(newHeading, pitch, range));
186-
// });
187-
// }
196+
// Step 3.5 Handle Custom Picking
188197

189198
function addCustomPicking() {
190199
const entity = viewer.entities.add({
191200
label: {
192201
show: false,
193202
showBackground: true,
194203
font: "14px monospace",
195-
verticalOrigin: VerticalOrigin.BOTTOM,
196204
heightReference: HeightReference.CLAMP_TO_GROUND,
197-
disableDepthTestDistance: Number.POSITIVE_INFINITY,
205+
pixelOffset: new Cartesian2(0, -50),
198206
},
199207
});
200208

201-
// Mouse over the globe to see the cartographic position
202209
const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
210+
211+
// If the mouse is over a geojson entity from the parks dataset, show a label
203212
handler.setInputAction(function (movement) {
204-
const cartesian = viewer.scene.pickPosition(movement.endPosition);
205-
if (cartesian) {
206-
const cartographic = Cartographic.fromCartesian(cartesian);
207-
const longitudeString = CesiumMath.toDegrees(
208-
cartographic.longitude,
209-
).toFixed(2);
210-
const latitudeString = CesiumMath.toDegrees(
211-
cartographic.latitude,
212-
).toFixed(2);
213-
const heightString = cartographic.height.toFixed(2);
214-
215-
entity.position = cartesian;
216-
entity.label.show = true;
217-
entity.label.text =
218-
`Lon: ${` ${longitudeString}`.slice(-7)}\u00B0` +
219-
`\nLat: ${` ${latitudeString}`.slice(-7)}\u00B0` +
220-
`\nAlt: ${` ${heightString}`.slice(-7)}m`;
221-
} else {
222-
entity.label.show = false;
213+
const pickedObject = viewer.scene.pick(movement.endPosition);
214+
215+
if (defined(pickedObject) && defined(pickedObject.id)) {
216+
if (geoJsonDataSourceReference.entities.contains(pickedObject.id)) {
217+
const cartesian = getPolygonCenter(pickedObject.id);
218+
entity.position = cartesian;
219+
entity.label.show = true;
220+
221+
const parkType = pickedObject.id.properties.Class.getValue(
222+
JulianDate.now(),
223+
);
224+
const acreage = pickedObject.id.properties.Acres.getValue(
225+
JulianDate.now(),
226+
);
227+
entity.label.text = `Park Type: ${parkType}` + `\nAcres: ${acreage}`;
228+
return;
229+
}
223230
}
231+
entity.label.show = false;
224232
}, ScreenSpaceEventType.MOUSE_MOVE);
233+
}
234+
addCustomPicking();
225235

226-
// let lastSelectedEntity;
227-
// let lastEntityColor;
228-
229-
// const handler = new ScreenSpaceEventHandler(viewer.scene.canvas);
230-
// handler.setInputAction(function (movement) {
231-
// const pickedObject = viewer.scene.pick(movement.position);
232-
// console.log(pickedObject.id)
233-
// if (defined(pickedObject)) {
234-
235-
// if (pickedObject.id.id !== lastSelectedEntity) {
236-
// //lastSelectedEntity
237-
238-
// }
239-
240-
// pickedObject.id.polygon.material = Color.BLACK
241-
// }
242-
243-
// entity.billboard.scale = 2.0;
244-
// entity.billboard.color = Cesium.Color.YELLOW;
245-
// } else {
246-
// entity.billboard.scale = 1.0;
247-
// entity.billboard.color = Cesium.Color.WHITE;
248-
// }
249-
// }, ScreenSpaceEventType.LEFT_CLICK);
236+
// Step 4.2 Orbit a point when user holds down the Q key
237+
let orbitHandler;
238+
239+
function toggleOrbit(position) {
240+
if (!defined(orbitHandler)) {
241+
orbitHandler = function (scene, time) {
242+
const pitch = CesiumMath.toRadians(-15);
243+
const range = 1000.0; // Distance from the point
244+
const delta = JulianDate.secondsDifference(time, viewer.clock.startTime);
245+
const newHeading = CesiumMath.toRadians(delta / 5); // degrees/sec
246+
247+
viewer.camera.lookAt(
248+
position,
249+
new HeadingPitchRange(newHeading, pitch, range),
250+
);
251+
};
252+
viewer.scene.preRender.addEventListener(orbitHandler);
253+
} else {
254+
viewer.scene.preRender.removeEventListener(orbitHandler);
255+
orbitHandler = undefined;
256+
setCamera();
257+
}
250258
}
251259

252-
addModel(position);
253-
addGeoJson();
254-
addEntity();
255-
//rotateCamera()
256-
//orbitPoint(position)
257-
addCustomPicking();
260+
document.addEventListener(
261+
"keydown",
262+
function (e) {
263+
if (typeof e.code !== "undefined") {
264+
if (e.code === "KeyQ") {
265+
toggleOrbit(position);
266+
}
267+
}
268+
},
269+
false,
270+
);

0 commit comments

Comments
 (0)