Comparative Analysis of Web-Based Point Cloud Visualization Tools: Cesium versus Deck.gl
2023-11-28
#cesium
#deck.gl
#3d-globes
#javascript

Comparative Analysis of Web-Based Point Cloud Visualization Tools: Cesium versus Deck.gl

Introduction

Cesium and deck.gl are both open-source Javascript frameworks that provide powerful features for creating interactive client-side applications for visualizing 3D datasets. While both have their unique strengths and weaknesses, choosing between them can be a challenge, especially when considering specific project requirements.

This article is designed to offer an in-depth comparison between Cesium and deck.gl, with a focus on their proficiency in displaying tiled point cloud data on a globe representation of the Earth and how well they work with React.We're diving into a range of key areas including globe projection, dynamic styling, coordinate systems, integration with React, the nuances of asset rendering, and the comprehensiveness of documentation. Additionally, the article considers aspects like support for various data types, user interaction capabilities, choices of map providers, and their respective pricing models. By thoroughly comparing and analyzing the features and strengths of each framework, this article aims to equip developers and decision-makers with the insights needed to choose the most suitable framework for their specific 3D data visualization projects.

Feature comparison

In this section, we will closely examine and contrast the distinct functionalities and capabilities of Cesium and deck.gl frameworks. Our research covers essential components of web-based 3D data visualization, with information to help you choose the best framework for your project.

Globe projection

Globe projection is a way to represent the Earth’s surface in three dimensions and is a key feature of both Cesium and deck.gl frameworks. This technique is pivotal in precisely portraying geographic data on a global scale. Although both frameworks use global projection, they do so in different ways, leading to differences in complexity and realism.

As globe projection is the default for Cesium, it offers two modes of terrain:

  • A basic WGS84 system, which renders a perfectly even sphere whose surface matches the average world water level line.

  • “Cesium World Terrain”, a projection of the Earth that attempts to portray the actual elevation of the terrain. If using this projection mode, all geolocated assets will either need to be properly placed on the “height” axis as well or programmatically clamped to the surface. React integration, asset rendering,

An asset geolocated 184 meters above the sea level.
Left: Cesium World Terrain, Right: Mean Water Level

Image 1. An asset located 184 meters above sea level. Left: Cesium World Terrain, Right: Mean Water Level

deck.gl’s globe projection only has a single mode - an even sphere projection. While you may optionally add “terrain features” to the map, it only seems to be models of notable mountains on top of the flat terrain. Globe projection is still considered an “experimental” feature and the documentation lists that a bunch of features may not work as expected, some of which may impact specific applications, particularly those requiring advanced globe projection capabilities. These limitations include:

  • No support for rotation (pitch or bearing). The camera always points towards the center of the earth, with north up.

  • No high-precision rendering at high zoom levels (> 12). Features at the city-block scale may not be rendered accurately.

  • Only supports COORDINATE_SYSTEM.LNGLAT (default of the coordinateSystem prop).

  • Known rendering issues when using multiple views mixing GlobeView and MapView, or switching between the two.

  • Support for TileLayer and MVTLayer is experimental. [1]

The attached demo mixes GlobeView with MapView, which seems to give the user full control of the camera. Meanwhile, rendering is accurate at high zoom levels (i.e. 19) but, at low zoom levels, points might look off their intended location on the map.

Dynamic styling

Dynamic styling is a powerful feature that enables real-time adjustment of visual elements based on specific criteria or data values. This capability is particularly valuable in applications where the visual representation of the data needs to be dynamically adjusted based on user interactions or changing data scenarios.

Cesium has a rich and well-documented specification for dynamically styling assets on the client. While it doesn’t directly support processing arrays of data for calculating dynamic styling values, it is possible to change values by manipulating JavaScript object prototypes. However, this way is not recommended as it accesses and changes object behavior directly. [2]

Examples of distance based dynamic styling.

Image 2. Examples of distance-based dynamic styling.

javascript
tileset.style = new Cesium.Cesium3DTileStyle({
  defines: {
    distance:
      "clamp(distance(${POSITION_ABSOLUTE}, vec3" +
      newPosition.toString() +
    ") / 12.0, 0.0, 1.0)",
  },
  color: 'mix(color("red"), ${COLOR}, ${distance})',
  pointSize: 2,
});

Style code from the demo dynamically styles every point by its distance to newPosition (a Cesium.Cartesian3 object)

deck.gl does not support dynamic styling for tiled data unless it’s in a specific format and the point cloud does not have inherent color data. [3]

Coordinate systems

Managing and converting coordinate systems is crucial for accurately mapping data to a 3D representation of the Earth. Both Cesium and deck.gl provide robust solutions for working with coordinates, but they differ in their primary coordinate systems and conversion methods.

Both frameworks can:

  • Accurately return coordinates of the point the cursor is on.

  • Convert between cartographic and cartesian coordinates.

  • Place non-geolocated assets at the given coordinates.

However, for cursor and placement positions, Cesium seems to only work with cartesian coordinates, while deck.gl only works with cartographic coordinates while using globe view.

javascript
const convertCartographicToCartesian = (longitude, latitude, altitude) => {
  const cartographicCoordinates = new Cesium.Cartographic(
    Cesium.Math.toRadians(longitude),
    Cesium.Math.toRadians(latitude),
    altitude
  );
  // Returns a Cesium.Cartesian3 object
  return viewer.scene.globe.ellipsoid.cartographicToCartesian(cartographicCoordinates);
};
javascript
const convertCartesianToCartographic = (x, y, z) => {
  const cartesianCoordinates = new Cesium.Cartesian3(x, y, z);
  // Returns a Cesium.Cartographic object
  return viewer.scene.globe.ellipsoid.cartesianToCartographic(cartesianCoordinates);
};

Examples of coordinate conversion in Cesium.

javascript
const convertCartographicToCartesian = (longitude, latitude, altitude) => {
  const cartographicCoordinates = [Cesium.Math.toRadians(longitude), Cesium.Math.toRadians(latitude), altitude];
  // Returns an array
  return Cesium.Ellipsoid.WGS84.cartographicToCartesian(cartographicCoordinates);
};
javascript
const convertCartesianToCartographic = (x, y, z) => {
  const cartesianCoordinates = [x, y, z];
  const cartographicRadians = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesianCoordinates);
  const cartographicDegrees = [Cesium.Math.toDegrees(cartographicRadians[0]),
                               Cesium.Math.toDegrees(cartographicRadians[1]),
                               cartographicRadians[2]];
  // Returns an array [longitude (degrees), latitude (degrees), altitude]
  return cartographicDegrees;
};

Examples of coordinate conversion in deck.gl

React integration

React, often referred to as React.js or ReactJS, is an open-source JavaScript library used for building user interfaces, particularly for single-page applications. It's maintained by Facebook (now Meta Platforms) and a community of individual developers and companies. React has gained widespread popularity in the web development community for its efficiency and flexibility. In this section, we compare how Cesium and deck.gl work with React, focusing on the ease of integration and fluid interaction between the React ecosystem and these frameworks.

Cesium only has a third-party package to turn Cesium objects into React components. As there is no first-party React implementation of Cesium, you will have to take extra care in making sure that React properly updates its hooks, as interacting with the vanilla JS implementation of the Cesium viewer does not cause React to trigger a render, leaving some hooks like useState with stale values. On the other hand, deck.gl has a first-party React wrapper called DeckGL. The DeckGL library still allows you to make a ref to the deck object as you had initiated it in Vanilla JS in case you want to access its methods.

jsx
export default function Viewer() {
  const deckRef = useRef(null);
  // call deck.gl methods using deckRef.current, i.e deckRef.current.pickObject()
  return (
    <DeckGL ref={deckRef}></DeckGL>
  );
};

Example of using React’s UseRef hook to call deck methods from the DeckGL wrapper.

Despite being interlinked, the <DeckGL> and <Map> components do not share camera control settings, such as maxPitch, and need to be set separately to avoid a desync scenario.

Asset rendering

Asset rendering is a critical feature that influences how a framework can efficiently render and manage 3D objects within a scene. It plays a vital role in creating immersive and dynamic visualizations, directly impacting the visual representation and interaction with data and models.

Cesium adds assets to the rendering engine by using the viewer object’s methods.

javascript
const viewer = new Cesium.Viewer("cesiumContainer");
// Add 3D Tiles to scene
const tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
  url: "/tiles/tileset.json",
}));
// Remove 3D tiles from scene
viewer.scene.primitives.remove(tileset);

Example of a 3D tiles object being added and removed in Cesium.

DeckGL reads a Javascript array and renders layer objects contained. No methods need to be called to render newly placed objects, as the DeckGL wrapper constantly performs shallow comparisons of the array’s status. [4]

jsx
const layers = [];
// Add 3D Tiles to scene
layers.push(new Tile3DLayer({
  id: "tile-layer",
  data: importedData,
  loader: Tiles3DLoader,
}));
// Remove 3D tiles from scene
layers.splice(0, 1);
return (
  <DeckGL
    layers={layers}
    // ...
  />
)

Example of a 3D tiles object being added and removed in DeckGL

Documentation and other reference materials

The availability and quality of documentation and support material are crucial for both learning and troubleshooting. This aspect becomes even more important when developers have to choose between frameworks such as Cesium and deck.gl, where the depth and accessibility of these resources can alter their decision-making process and overall development experience. Below we will compare the two frameworks in terms of documentation, community support, and usability.

Cesium:

Deck.gl:

  • Complete but fragmented documentation across multiple sites (requiring navigation through various websites like loaders.gl for data loader parameters and math.gl for conversion methods).

  • Limited tutorial example pool (also, tutorials are not conveniently placed with some hyperlinks on the homepage)

  • Fewer official code examples compared to Cesium's Sandcastle.

  • Limited online discussion.

  • Code is actively monitored and worked on GitHub.

Compilation and runtime

In web development, how smoothly and simply frameworks compile and run can hugely impact both the development process and the final app's performance. This is particularly vital for frameworks like deck.gl and Cesium, known for their complex 3D visualizations and geodata handling.

With deck.gl, you can expect a hassle-free experience in both running and compiling, while working with vanilla Cesium requires you to build scripts that refer to assets in the Cesium package directory or for you to manually copy the assets over to the public directory. There is a lightweight third-party library that bundles scripts into the vite compile configuration that manages this for you.

Data type support

A 3D visualization framework's prowess is often gauged by its ability to handle and process a diverse range of data types. This versatility is pivotal, as it dictates how well the tool can adapt to different use cases and data sources. Both Cesium and deck.gl showcase a lot of flexibility. They can effortlessly handle Cesium 3D Tiles, gITF Tiles and support Draco compression. However, Cesium draws a line at the Potree tile format, preferring that you convert point cloud data like LAS/LAZ into 3D Tiles using its service, Cesium Ion. [5] On the flip side, deck.gl offers a more direct approach. It can natively display these point cloud data formats without the need for conversion. However, to work with various data formats in deck.gl, you'll have to install and import loaders.gl, an open-source Javascript module by the same developers, made for loading various data formats, including popular geospatial formats.

User interaction

Let’s take a closer look at how Cesium and deck.gl handle user interactions, focusing on their methods for click events, hover details, tooltips, and drag-and-drop actions — all vital for an engaging user experience.

Both frameworks have the ability to process click events and return either a reference to the object being moused over or the spatial coordinates of the point being moused over, depending on the use case. Although deck.gl onClick events only return two coordinate arrays of a point projected onto the base map by default, meaning that you will have to call the picking method using the same mouse coordinates if you also want to obtain the height of the clicked point, or if you want to project clicks onto displayed assets. deck.gl allows you to set properties for every single asset on whether it can be clicked on and whether there should be functionality when hovering over it. You may also assign a custom function for displaying tooltips, allowing you to display any custom HTML element of your choice, giving strong customizability.

javascript
const mousePosition  = new Cesium.Cartesian2(mouseX, mouseY);
// Returns a Cesium.Cartesian3 object with XYZ coordinates of the point being hovered over
const selectedLocation = viewer.scene.pickPosition(mousePosition);
// Returns reference to object being hovered over (if any)
const pickedObject = viewer.scene.pick(mousePosition);

Examples of Cesium picking methods.

javascript
const deckInstance = new Deck({
  // ... other properties like initialViewState, layers, etc.
});
// Create a new Tile3DLayer
const tileLayer = new Tile3DLayer({
  id: "tile-layer",
  data: "/path/to/tiles/tileset.json",
  loader: Tiles3DLoader,
  pickable: true,
  onClick: (info, event) => {
    // Only works when pickable=true
    // Array [lng (degrees), lat (degrees)]
    console.log(info.coordinate);
  },
});
// Add the new layer to the deck instance
deckInstance.setProps({
  layers: [...deckInstance.props.layers, tileLayer],
});

Example of a deck.gl layer with interaction

javascript
document.addEventListener("mousemove", (event) => {
  const hoverObj = deckInstance.pickObject({
    x: event.clientX,
    y: event.clientY,
    // Pixels of leniency
    radius: 0,
    // List of IDs to pick from. This allows optimization for each use-case.
    // Layers will be ignored if they were initialized with pickable=false
    layerIds: ["tile-layer"],
    // Return 3D coordinates rather than 2D, also including height
    unproject3D: true,
  });
  if (hoverObj) {
    // Array [lng (degrees), lat (degrees), height]
    console.log(hoverObj.coordinate);
  }
});

deck.gl example of finding the world coordinates of the point the cursor is pointing at.

javascript
document.addEventListener("mousemove", (event) => {
  const info = deckInstance.pickObject({
    x: event.clientX,
    y: event.clientY,
    radius: 50, // Adjust as needed
    layerIds: ["tile-layer"],
  });
  const tooltip = document.getElementById("tooltip");
  if (info && info.layer) {
    // Return text string or HTML element to render near cursor
    tooltip.innerHTML = `Hovering over layer with ID: ${info.layer.id}`;
    tooltip.style.left = `${event.clientX}px`;
    tooltip.style.top = `${event.clientY}px`;
    tooltip.style.display = "block";
  } else {
    // Return display none to not render a tooltip
    tooltip.style.display = "none";
  }
});

DeckGL example of a tooltip implementation.

Screenshot of above code in action.

Image 3. Screenshot of the above code in action.

For both frameworks, implementing drag-and-drop functionality for in-viewer objects is very similar. Both frameworks allow you to bind functions to drag events (starting drag, dragging, ending drag). Dragging functionality can be implemented by turning off the viewer’s camera controls at the start of dragging and saving a reference/pointer to the object being dragged. Drag events are called every time the cursor is moved and update the object’s position by running the picking method with cursor coordinates from the drag event and end drag events just restore the default camera functionality.

Map providers

Cesium and deck.gl each have their unique approaches to integrating map providers for 3D globe visualization:

  • Cesium uses its own service, Cesium Ion, to provide high-resolution globe textures and terrain information to enable the creation of detailed and realistic earth models.

  • deck.gl integrates primarily with Mapbox GL JS, and the deck.gl developers have created react-map-gl, their own React wrapper for Mapbox that allows seamless integration with both vanilla JavaScript and DeckGL-based applications. Mapbox offers a diverse selection of styles that cover various visualization requirements.

Image 4. Cesium tile providers

Pricing and Licenses

While both frameworks’ licenses allow you to create commercial applications, the map-providing services are only free up to a certain point. Cesium Ion is available to be used for commercial purposes on a free account if the company makes less than $50K in annual gross revenue and has limitations on monthly request count. The pricing specifics for Cesium Ion may be checked here

Deck.gl’s Mapbox pricing is based on the number of monthly requests, the pricing specifics may be checked here. As of writing, it’s unsure if calls using react-map-gl would be considered under the Mapbox GL JS (since it technically is a wrapper for the Map object of Mapbox) or one of the specific tiles APIs, such as Raster Tiles API if using the satellite style.

If you opt not to use Cesium Ion for Cesium, the client allows you to use local textures to render on the globe. The Cesium library provides a low-resolution copy of “Natural Earth II” as an offline texture. 

Quality comparison at lower zoom level.
Left: Cesium Ion Asset (Bing Aerial Maps), Right: Offline texture (Natural Earth II)

Image 5. Quality comparison at a lower zoom level. Left: Cesium Ion Asset (Bing Aerial Maps), Right: Offline texture (Natural Earth II)

Quality comparison at higher zoom level.
Left: Cesium Ion Asset (Bing Aerial Maps), Right: Offline texture (Natural Earth II)

Image 6. Quality comparison at a higher zoom level. Left: Cesium Ion Asset (Bing Aerial Maps), Right: Offline texture (Natural Earth II)

The documentation provides various other implementations of formats and services to render the base terrain to your liking.

javascript
// Cesium World Terrain
const viewer = new Cesium.Viewer("cesiumContainer", {
  terrainProvider: Cesium.createWorldTerrain(),
});
// OpenStreetMap
const viewer = new Cesium.Viewer("cesiumContainer", {
  imageryProvider: new Cesium.OpenStreetMapImageryProvider({
    url: "https://a.tile.openstreetmap.org/",
  }),
});
// Local resource (Cesium-bundled Natural Earth II)
const viewer = new Cesium.Viewer("cesiumContainer", {
  imageryProvider: new Cesium.TileMapServiceImageryProvider({
    url: Cesium.buildModuleUrl("Assets/Textures/NaturalEarthII"),
  }),
});

Examples of ways to load various terrain providers in Cesium.

If you opt not to use Mapbox for deck.gl, you may create an MVTLayer, which holds 2D map data in MVT format (Mapbox Vector Tiles), designed to store 2D image data using the tiling philosophy. [6]

A self-reliant alternative for both frameworks might be finding some royalty-free earth textures, however, these require running a separate server to serve the 2D tiles to the client, as neither of the clients seems to be able to parse this particular raster map format.

Summary

In this comprehensive comparison of Cesium and deck.gl, two leading open-source JavaScript frameworks for 3D data visualization, we examined their capabilities in several critical aspects. Here is a brief summary of our findings:

  • Globe projection: Cesium offers a more advanced globe projection with its "Cesium World Terrain" mode, which provides realistic terrain elevations compared to deck.gl's simpler, flat sphere projection. This makes Cesium a better choice for applications that require detailed geographic representations.

  • Dynamic styling: Cesium leads the way with a rich, well-documented specification for dynamic styling, although it requires some workarounds for processing arrays of data. deck.gl does offer some dynamic styling capabilities, but is limited by the data format and has no inherent support for color data.

  • Coordinate systems: Both systems are capable of handling coordinate systems, but differ in their preferences - Cesium prefers Cartesian coordinates, while deck.gl is more oriented towards cartographic coordinates in the globe view.

  • React integration: deck.gl has a clear advantage with its own React wrapper DeckGL and offers a more seamless integration than Cesium, which relies on a third-party package to convert React components.

  • Asset rendering: Cesium uses viewer object methods for asset rendering, providing a direct and detailed control mechanism. In contrast, deck.gl uses a JavaScript array-based approach, which simplifies the process but offers less direct control.

  • Documentation and community support: Cesium is characterized by extensive documentation and a supportive community, which makes it more accessible to new users and complex use cases. deck.gl has full documentation, but offers navigation issues and has a comparatively smaller community.

  • Data type support: Both frameworks are competent in handling common data formats such as Cesium 3D Tiles and glTF Tiles. However, Cesium does not provide support for the Potree tile format and requires data conversion for point cloud data.

  • User interaction: Both Cesium and deck.gl offer robust user interaction features, but deck.gl offers greater customization with properties for clickable assets and custom tooltips.

  • Map providers & pricing: Cesium Ion from Cesium and the integration of deck.gl into Mapbox GL JS each offer high-quality textures and styles, but come with limitations for non-paying users. Alternative solutions are available but may require additional settings and compromise on quality.

To summarize, Cesium and deck.gl solve the same problem as being an engine for showing 3D globes and 2D maps in a web browser. Deck.gl is more accessible, especially for React developers, and offers simpler asset management. Cesium, on the other hand, features detailed geographic representations and extensive documentation, making it better suited for complex visualization requirements. Ultimately, the choice between these two tools should be based on specific project requirements.

References

[1] deck.gl | GlobeView (Experimental)

[2] Cesium | Styling

[3] deck.gl | Tile3DLayer (Experimental)

[4] deck.gl | The Reactive Programming Paradigm

[5] Cesium | Cesium tyler data types and formats

[6] deck.gl | MVTLayer

Other insights