How to use CesiumJS to visualize data from a Session

From Tygron Preview Support Wiki
Jump to navigation Jump to search
CesiumJS complete code ran in Cesium Sandcastle

This page contains code and background information to build up a Cesium viewer in html using Tygron web-enpoints and CesiumJS. For the complete code, see CesiumJS complete code. For more information on how to build and install CesiumJS on your webserver, we refer to the CesiumJS github documentation.

If you are interested in all web endpoints of a session in the Tygron Platform, see this how-to.

Constants

The following constants are used by multiple services and are therefore defind on top:

// variables
const dim = 128;
const minLevel = 6;
const maxLevel = 19;
const tilepx = 512;

const TOKEN = "XXX"; // IMPORTANT: Place here the project session token between the ""
const BGCOLOR = "1f1f00"; // ff0000 is red, hexadecimal color
const SHADOW = true; //true ,false
const BASEMAP_INDEX = 0; // SATELLITE=0, TOPOGRAPHIC=1 and GRAY=2.
const STYLE = "COLORED"; // WHITE, COLORED
const SPACING = 10;
const TEXTURE = "MEDIUM"; // SMALL, MEDIUM , LARGE
const FEATURE_ID = "ID";
const BASEURL = "https://engine.tygron.com/web/";

It is important to replace the XXX with your sessions web token. Optionally adjust the BASEURL when your domain is hosted on a different server.

Specific constants

  • TOKEN = API token.
  • BGCOLOR = Hexa-color.
  • BASEMAP_INDEX = nominal; SATELLITE=0, TOPOGRAPHIC=1 and GRAY=2.
  • SHADOW = boolean.
  • SPACING = distance number.
  • TEXTURE = String value. Allowed: "SMALL", "MEDIUM" or "LARGE".
  • STYLE = String value. Allowed: "WHITE", "COLORED".

Heightmap

Most of the time you want to use the heightmap of your project's session, instead of the default digital elevation height that Cesium provides. Use this code for a custom heightmap provider. This terrain provider as an alternative to the cesium terrain provider.

// Construct the default list of terrain sources.
var terrainModels = [];
terrainModels.push(new Cesium.ProviderViewModel({
	name: "Project Terrain",
	category: "Terrain",       
    tooltip: "",
	iconUrl: Cesium.buildModuleUrl('Widgets/Images/TerrainProviders/Ellipsoid.png'),
	creationFunction: function () {
		return new Cesium.CustomHeightmapTerrainProvider({
			width: dim,
			height: dim,
			maximumLevel: maxLevel,
			callback: function (x, y, level) {
				if (level <= 10) { // ignore zoom levels 10 and lower
					return new Float32Array(dim * dim); // all zeros
				}
				const test = Cesium.Resource.fetchArrayBuffer(BASEURL+'terrain/' + level + '/' + x + '/' + y + '.bin?worlddatum=true&token='+TOKEN+'&width=' + dim + '&height=' + dim);
				return test.then(function (buffer) {
					const array = new Float32Array(dim * dim); // all zeros
					const view = new DataView(buffer);
					for (let i = 0; i < dim * dim; i++) {
						array[i] = view.getFloat32(i * 4);
					}
					return array;
				});
			},
		});
	}
}));

Base Map WMS

You can use the following code to add and access your project's WMS. Additionally, you can provide the optional layer parameter: SATELLITE, TOPOGRAPHIC or GRAY. We construct a new ProviderViewModel that creates a WebMapServiceImageryProvider with an url to the Tygron Platform's WMS service and our session's token parameter.

var imageryViewModels = [];
const baseMaps = ["SATELLITE", "TOPOGRAPHIC", "GRAY"];
	for (let i = 0; i < baseMaps.length; i++) {
	imageryViewModels.push(new Cesium.ProviderViewModel({
		name: baseMaps[i],
		category: "Base Map",
             tooltip: "",
      

		iconUrl: Cesium.buildModuleUrl('Widgets/Images/TerrainProviders/Ellipsoid.png'),
		creationFunction: function () {
			return new Cesium.WebMapServiceImageryProvider({
				url: BASEURL+'wms',
				layers: baseMaps[i],
				maximumLevel: maxLevel,
				tileHeight: tilepx,
				tileWidth: tilepx,
				getFeatureInfoFormats: [new Cesium.GetFeatureInfoFormat("json", "application/json")],
				proxy: new Cesium.DefaultProxy('/proxy/'),
				parameters: {
					crs: "4326",
					forcexy: "true",
					bgcolor: BGCOLOR,
					walled: "false",
					token: TOKEN
				},
				getFeatureInfoParameters: {
					crs: "4326",
					forcexy: "true",
					token: TOKEN,
				},
			});
		}
	}));
}

Viewer initialization

The Cesium viewer is initialized as followed:

// Construct the viewer, with a high-res terrain source pre-selected.
var viewer = new Cesium.Viewer('cesiumContainer', {
	terrainProviderViewModels: terrainModels,
	selectedTerrainProviderViewModel: terrainModels[0],
	imageryProviderViewModels: imageryViewModels,
	selectedImageryProviderViewModel: imageryViewModels[BASEMAP_INDEX],
	animation: false,
	timeline: false,
	homeButton: false,
	navigationHelpButton: false,
	navigationInstructionsInitiallyVisible: false,
	fullscreenButton: false,
	shadows: SHADOW,
});

3D Tileset

A Cesium 3D Tileset can be added by activating an asynchronous function and awaiting the tileset call:

const start = async function () {	
    var tileset = await Cesium.Cesium3DTileset.fromUrl(BASEURL+'3dtiles/tileset.json?token='+TOKEN+'&style='+STYLE+'&spacing='+SPACING+'&texture='+TEXTURE);
    viewer.scene.primitives.add(tileset);
}

Fly camera to Tileset

Once loaded, the camera can fly to the tileset by adding this after the tileset has been added to the scene (but before the end bracket of the start function)

boundingSphere = tileset.root.boundingVolume._boundingSphere
viewer.camera.viewBoundingSphere(tileset.root.boundingVolume._boundingSphere);
viewer.camera.flyToBoundingSphere(tileset.root.boundingVolume._boundingSphere);

Updating the Tileset

A tileset can be updated with the following code.

var tileseturl = new Cesium.Resource({
	url: "3dtiles/tileset.json",
	queryParameters: {
		token: TOKEN
	}
});
tileseturl.fetchJson().then(data => {
	if (tilesetversion == null) {
		tilesetversion = data.asset.tilesetVersion;
	} else if (data.asset.tilesetVersion > tilesetversion) {

		tilesetversion = data.asset.tilesetVersion;
		var tilerequest = Cesium.Cesium3DTileset.fromUrl('3dtiles/tileset.json?token='+TOKEN'+&style='+STYLE+'&spacing=+'SPACING'+&texture='+TEXTURE);
		tilerequest.then((newtileset) => {

			viewer.scene.primitives.add(newtileset);
			tileset.show = false;
			viewer.scene.primitives.remove(tileset);
			tileset = newtileset;
		});
	}
});

See Versions to obtain the current version of buildings, such that you know when an update might be required.

Overlays

Overlays are also provided by a project's WMS. The code below allows you to add overlays to the Cesium viewer. Overlay layer is a variable that stores the current overlay layer, such that it can also be destroyed when it should no longer be visible. Parameters "minLevel", "maxLevel" and "tilepx" are defined above in Heightmap.

/* Overlay Variables */
var overlayLayer = null;

const activateOverlay = function(overlayID, timeframe, difference){
    
  const provider = new Cesium.WebMapServiceImageryProvider({
	url: BASEURL+'wms',
	layers: overlayID,
	maximumLevel: maxLevel,
	tileHeight: tilepx,
	tileWidth: tilepx,
	proxy: new Cesium.DefaultProxy('/proxy/'),
	parameters: {
		crs: "4326",
		forcexy: "true",
		token: TOKEN,
		timeframe: timeframe,
		styles: difference ? "DIFFERENCE" : "",
	},
	getFeatureInfoParameters: {
		crs: "4326",
		forcexy: "true",
		token: TOKEN,
		timeframe: timeframe,
		styles: difference ? "DIFFERENCE" : "",
	}
});
    viewer.imageryLayers.remove(overlayLayer);
    var newOverlayLayer = new Cesium.ImageryLayer(provider, { minimumTerrainLevel: minLevel });
    viewer.imageryLayers.add(newOverlayLayer);
    if (overlayLayer !== null) {
	    overlayLayer.destroy();
    }
    overlayLayer = newOverlayLayer;
};

To activate any overlay, add the following code to the start function:

    activateOverlay(1, 0, false);

Net lines

NetLines can be added with Cesium PolyLine Collections. A custom material gives the lines an animation. The lines are obtained using the "lines.geojson" endpoint.

/* Net Lines */
var mainLines = new Cesium.PolylineCollection();
var netLines = new Cesium.PolylineCollection();
const netlinesHeight = 120;
const netlinesOffset = 50;

const materialSource =  `
      uniform vec4 color;
      uniform float lengthfactor;

      czm_material czm_getMaterial(czm_materialInput materialInput)
      {
        czm_material material = czm_getDefaultMaterial(materialInput);

        float time = czm_frameNumber / 20.0;
        float v = fract(time + materialInput.s * lengthfactor) < 0.2 ? 0.0 :1.0;
        material.diffuse = color.rgb * v;
        material.alpha = 1.0;
        return material;
      }
      `;

function updateAndGet(lines, result){
	if (lines) {
		viewer.scene.primitives.remove(lines);
	}	
	lines = new Cesium.PolylineCollection();
	
	updateLines(lines, result);
	viewer.scene.primitives.add(lines);
	
	return lines;	
}

async function updateNetLines() {
	
	var result = await new Cesium.Resource({
		url: BASEURL+ "lines.geojson",
		queryParameters: {
			token: TOKEN,
			maxlength: "10",
			crs: "4326",
			forcexy: "true"
		}
	}).fetchJson();
	
	netLines = updateAndGet(netLines, result);
}

async function updateMainNetLines() {

	var result = await new Cesium.Resource({
		url: BASEURL+"lines.geojson",
		queryParameters: {
			token: TOKEN,
			minlength: "10",
			crs: "4326",
			forcexy: "true"
		}
	}).fetchJson();
	
	mainLines = updateAndGet(mainLines, result);
}


function updateLines(lines, data) {
	
	var netLines = data.features;
	var ellipsoid = viewer.scene.mapProjection.ellipsoid;
	for (i = 0; i < netLines.length; i++) {
		var l = netLines[i];
		var longitude = l.geometry.coordinates[0][0];
		var latitude = l.geometry.coordinates[0][1];
		var height = l.geometry.coordinates[0][2] == null ? netlinesHeight : l.geometry.coordinates[0][2] + netlinesOffset;
		var longitude2 = l.geometry.coordinates[1][0];
		var latitude2 = l.geometry.coordinates[1][1];
		var height2 = l.geometry.coordinates[1][2] == null ? netlinesHeight : l.geometry.coordinates[1][2] + netlinesOffset;
		var lid = l.properties[FEATURE_ID];
		var linecolor = Cesium.Color.YELLOW;
		if (l.properties['color'] != null) {
			linecolor = Cesium.Color.fromCssColorString(l.properties['color']);
		}
		var lwidth = Number(l.properties['width']);
		var lineLength = Number(l.properties['length']);

		lines.add({
			positions: Cesium.Cartesian3.fromDegreesArrayHeights([longitude, latitude, height, longitude2, latitude2, height2]),
			width: lwidth,
			material: new Cesium.Material({
				fabric: {
					type: "netline",
					uniforms: {
						color: linecolor,
						lengthfactor: lineLength/20.0,
					},
					source: materialSource,
				}
			})
		});

	}
}

Net lines as main and minor can be added to the viewer by calling the following functions in the asynchronous start function:

    updateMainNetLines();
    updateNetLines();

Neighborhood labels

Neighborhood labels can be obtained from the neighborhood geojson endpoint, and converting these to Cesium Entities with a longitude and latitude.

var neighborhoodUrl = new Cesium.Resource({
	url: BASEURL+"neighborhoods.geojson",
	queryParameters: {
		token: TOKEN,
		crs: "4326",
		forcexy: "true",
	}
});

var data = await neighborhoodUrl.fetchJson();
var labels = data.features;
for (var i = 0; i < labels.length; ++i) {
	var p = labels[i];
	var longitude = p.geometry.coordinates[0];
	var latitude = p.geometry.coordinates[1];
	var height = p.geometry.coordinates[2] == null ? 200 : p.geometry.coordinates[2] + 200;
	var id = p.properties[FEATURE_ID];
		const entity = viewer.entities.add({
		position: Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
		label: {
			text: p.properties.name,
			font: "12pt arial",
			style: Cesium.LabelStyle.FILL_AND_OUTLINE,
			outlineWidth: 2,
			verticalOrigin: Cesium.VerticalOrigin.TOP,
			fillColor: Cesium.Color.WHITE,
		}
	});
}

Versions

The version of a maplink (specific type of item) can be obtained by using calls to the version web endpoint.

fetch('version.json?token='+TOKEN+'&links=POPUPS,INDICATORS,NET_LINES,OVERLAYS,PANELS,TERRAINS,ACTION_MENUS,BUILDINGS,SETTINGS')
.then((response) => { return response.json(); })
.then((version) => {
    // version[0] = POPUPS version number
    // version[1] = INDICATOR version number
    // etc...
}

You can specify in the links parameter the maplinks that you want to request. If you request links=BUILDINGS,TERRAINS, then version[0] is the buildings version number. You can compare these obtained numbers with stored numbers to check if an update is required, as is stated in the Updating the Tileset chapter.