Adding two or more layers or geojson data to Google 3D Photorealistic Tiles

Hi Cesium community!

I am relatively new to Cesium. I have gotten a Cesium Map to work using the Google 3D Photorealistic Tileset with a geojson layer of multipolygons on top of it.

Now I want to add a second layer of geojson points (and extrude them into columns) to the same map.

I have tried multiple approaches but cannot find a way to do this.

I am running a Python Flask app that calls in the html code of the map template, and then passes the two layers of geojson data to the html code as variables.

Is there a limitation as to the number of “layers” that can be added to this map, or is it the way I am crafting the code?

Here is Flask app and html code:

Flask app:

from flask import Flask, render_template

app = Flask(__name__, template_folder='/path to template/')

@app.route('/')
def index():
    return render_template('cesium_map.html', dataLayer1 = dataLayer1.to_json(), dataLayer2 = dataLayer2.to_json()) 

if __name__ == '__main__':
    app.run()

html code:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <!-- Include the CesiumJS JavaScript and CSS files -->
  <script src="https://cesium.com/downloads/cesiumjs/releases/1.107.1/Build/Cesium/Cesium.js"></script>
  <link href="https://cesium.com/downloads/cesiumjs/releases/1.107.1/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>
  <div id="cesiumContainer"></div>
  <script type="module">
    // Your access token can be found at: https://ion.cesium.com/tokens.
    // This is the default access token from your ion account

    Cesium.Ion.defaultAccessToken = '__TOKEN__'

    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Cesium.Viewer("cesiumContainer", {
        timeline: false,
        animation: false,
        sceneModePicker: false,
        baseLayerPicker: false,
    });

    // The globe does not need to be displayed,
    // since the Photorealistic 3D Tiles include terrain
    viewer.scene.globe.show = false;

    // Add Photorealistic 3D Tiles
    try {
        const tileset = await Cesium.createGooglePhotorealistic3DTileset();
        viewer.scene.primitives.add(tileset);
    } catch (error) {
        console.log(`Error loading Photorealistic 3D Tiles tileset.
        ${error}`);
    }


    // this part works
    // Parse the JSON data from Flask into Cesium entities
    const geoJsonData = {{ dataLayer1|safe }};
    const dataSource = Cesium.GeoJsonDataSource.load(geoJsonData, {
        stroke: Cesium.Color.YELLOW,
        fill: Cesium.Color.YELLOW.withAlpha(0.1),
        strokeWidth: 50,
      });
    viewer.dataSources.add(dataSource);
    //


   // it doesn't work when I add this part
    const pointData = {{ dataLayer2|safe }};
    var layer2 = new Cesium.GeoJsonDataSource({
      data: pointData,
      extruded: true,
      extrudeHeight: 200
    });

    // Add the second layers to the viewer.
    viewer.dataSources.add(layer2);
    

    // Fly the camera to point at the given longitude, latitude, and height.
    viewer.camera.flyTo({
      destination: Cesium.Cartesian3.fromDegrees(-75.1652, 39.9526, 400),
      orientation: {
        heading: Cesium.Math.toRadians(0.0),
        pitch: Cesium.Math.toRadians(-15.0),
      }
    });


  </script>
 </div>
</body>
</html>

Any help would be greatly appreciated.

UPDATE: I answered my own question.

I needed to add the second layer (“dataLayer2”) as entities, not primitives, and loop through the data points, and the elevation (“height”) of the data points was included in the JSON data, not defined in the script.

Instead of the code that I was using in my original question, which was this:

    const pointData = {{ dataLayer2|safe }};
    var layer2 = new Cesium.GeoJsonDataSource({
      data: pointData,
      extruded: true,
      extrudeHeight: 200
    });

I replaced that original code with the following code:

    const pointData = {{ dataLayer2|safe }};
    const promise = Cesium.GeoJsonDataSource.load(pointData);
    promise
      .then(function (pointSource) {
        viewer.dataSources.add(pointSource);

        //Get the array of entities
        const entities = pointSource.entities.values;

        for (let i = 0; i < entities.length; i++) {
          const entity = entities[i];
          const name = entity.name;
        };
    });

This works as an additional layer on top of the Google Photorealistic 3D tiles.

I hope this helps others that encountered the same obstacle.