Learn to use the Entity API in CesiumJS for drawing spatial data such as points, markers, labels, lines, models, shapes, and volumes. If you are new to CesiumJS, you might want to start with the Getting Started tutorial.
What is the Entity API?
CesiumJS has a rich API for spatial data that can be split into two categories: a low-level
Primitive API geared towards graphics developers, and a high-level
Entity API for data-driven visualization.
The low-level Primitive API exposes the minimal amount of abstraction needed to perform the task at hand. It is structured to provide a flexible implementation for graphics developers, not for API consistency. Loading a model is different from creating a billboard, and both are radically different from creating a polygon. Each type of visualization is its own distinct feature. Furthermore, each has different performance characteristics and requires different best practices. While this approach is powerful and flexible, most applications are better served with a higher level of abstraction.
The Entity API exposes a set of consistently designed high-level objects that aggregate related visualization and information into a unified data structure, which we call an
Entity. It lets us concentrate on the presentation of data rather than worrying about the underlying mechanism of visualization. It also provides constructs for easily building complex, time-dynamic visualization in a way that fits naturally alongside static data. While the Entity API actually uses the Primitive API under the hood, that’s an implementation detail we (almost) never have to concern ourselves with. By applying various heuristics to the data we give it, the Entity API is able to provide flexible, high-performance visualization while exposing a consistent, easy to learn, and easy to use interface.
Our first entity
To start, open the Hello World example in Sandcastle.
Add a polygon for the US state of Wyoming from a list of longitude and latitude degrees.
Hitting the Run button in the toolbar (or F8 on the keyboard) produces the following:
Our first entity. Wyoming has never been this exciting.
The code above creates the
Viewer, which creates the globe and other widgets. We created a new
viewer.entities.add. The object we pass to
add provides initial values for the entity. The return value is the actual
Entity instance. Finally,
viewer.zoomTo zooms the camera to view the entity.
There are many entity options. We specified translucent red for the polygon fill and a black outline.
Shapes and volumes
Here’s a complete list of supported shapes and volumes we can create using the Entity API:
Materials and outlines
All shapes and volumes have a common set of properties that control their appearance. The
fill property specifies if the geometry is filled in, and the
outline property specifies if the geometry is outlined.
material property determines what that fill looks like. The following creates a translucent blue ellipse.
We can also specify a url to an image instead of a color.
In both the above cases, a
ImageMaterialProperty is created for us automatically on assignment. For more complex materials, we need to create a
MaterialProperty instance ourselves. Currently, entity shapes and volumes support colors, images, checkerboard, stripe, and grid materials.
outline relies on the
outlineWidth only works on non-Windows systems, such as Android, iOS, Linux, and OS X. On Windows systems, outlines will always have a width of 1. This is due to a limitation of how WebGL is implemented on Windows.
Polylines are a special case, since they have no fill or outline properties. They rely on specialized materials for anything other than color. Because of these special materials, polylines of varying widths and outline widths will work on all systems.
Heights and extrusions
Surface shapes including
rectangles can be placed at altitude or extruded into a volume. In both cases, the shape or volume will still conform to the curvature of the WGS84 ellipsoid.
Set the height property (in meters) on the corresponding graphics object. The below line of code raises the polygon to 250,000 meters above the earth.
Wyoming at 250,000 meters.
To extrude the shape into a volume, set the
extrudedHeight property. The volume will be created between
undefined, the volume starts at 0. Create a volume that starts at 200,000 meters and extends to 250,000 meters.
We can easily extrude a flat polygon into a volume.
Entity features in the Viewer
Let’s look at the out-of-the-box functionality the
Viewer provides for working with entities.
Selection and description
Clicking on an entity in the Viewer will show the
SelectionIndicator widget at the entity’s location and bring up the
InfoBox to provide more information. We can set a
name, which determines the title of the
InfoBox. We can also provide HTML as the
Setting the entity description allows for HTML formatted information to be displayed in the InfoBox.
All HTML shown in the
viewer.infoBox.frame property. See this article for more information on controlling iframe sandboxing.
viewer.zoomTo command to view a particular entity. There is also a
viewer.flyTo method that performs an animated camera flight to the entity. Both of these methods can be passed to an
DataSource, or an array of entities.
Either method calculates a view of all provided entities. By default, the camera is oriented north and is looking down from a 45 degree angle. Customize this by passing in a
Wyoming viewer from the east.
flyTo are asynchronous functions; that is, they are not guaranteed to have completed before they return. For example, flying to an entity happens over many animation frames. Both of these functions return Promises that can be used to schedule a function to be executed after the flight or zoom is completed. Replace
zoomTo in our example with the snippet below. This flies to Wyoming and selects it after the flight is completed.
The resulting parameter passed to our callback function will be
true if the flight completed successfully or
false if the flight was canceled, i.e., a user initiated another flight or zoom before this one completed, or because the target has no corresponding visualization, i.e., there’s nothing to zoom to.
Sometimes, particularly when working with time-dynamic data, we want the camera to remain centered on an entity rather than on the Earth. This is accomplished by setting
viewer.trackedEntity. Tracking an entity requires
position to be set.
Stop tracking by setting
undefined or by double clicking away from the entity. Calling
flyTo will also cancel tracking.
EntityCollection is an associative array for managing and monitoring a group of entities.
viewer.entities is an
EntityCollection includes methods such as
removeAll for managing entities.
Sometimes we need to update an entity that we previously created. All entity instances have a unique
id that can be used to retrieve an entity from the collection. We can specify an ID, or one will be automatically generated.
Retrieve the entity using
getById. In the event that no entity with the provided ID exists,
undefined is returned.
To fetch an entity or create a new one if it does not exist, use
Create a new entity manually and add it to the collection using
add. This method throws if an entity with the same
id already exists in the collection.
The power of
EntityCollection shines using the
collectionChanged event. This notifies listeners when an entity has been added, removed, or updated in the collection.
Use the Geometry Showcase example in Sandcastle. Paste the following code after the line creating the viewer.
You should see about 65 messages in the console when you run the example, one for every call to
When updating a large amount of entities at once, it’s more performant to queue up changes and send one big event at the end. This way Cesium can process required changes in a single pass. Call viewer.entities.suspendEvents before the
viewer.entities.add and call viewer.entities.resumeEvents at the end of the example. When we run the demo again, we now get a single event containing all 65 entities. These calls are reference counted, so multiple suspend and resume calls can be nested.
Points, billboards, and labels
Citizens Bank Park in Philadelphia, PA, home of the Philadelphia Phillies.
By default, the label is centered horizontally and vertically. Since the label and point share the same position, they overlap on the screen. To avoid this, specify the label origin
VerticalOrigin.BOTTOM and set a pixel offset of
Replace the point with a
billboard, which is a marker that’s always facing the user.
The Philadelphia Phillies logo as a billboard at our entity’s position.
Set a position and a URI to the glTF model to create model entity.
The example truck model that ships with CesiumJS.
By default, the model is oriented upright and facing east. Control the orientation of the model by specifying a
Quaternion for the
Entity.orientation property. This controls the heading, pitch, and roll of the model.
The property system
All values we define for our entities are stored as
Property objects. For example, see the value of our Wyoming outline:
outline is an instance of
ConstantProperty. This tutorial uses a form of shorthand called implicit property conversion, which automatically takes raw values and creates a corresponding
Property under the hood. Without this shorthand, we would have had to write a much longer version of the initial example:
Properties are used because the Entity API is capable of expressing not only constant values, but also values as they change over time. See the Callback Property and Interpolation Sandcastle examples to take a look at some time dynamic properties.
Check out the Cesium Workshop Tutorial for examples of how to style and create entities using