Creating Entities

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.

Copy to clipboard. Data copied clipboard.
var viewer = new Cesium.Viewer('cesiumContainer');

var wyoming = viewer.entities.add({
  polygon : {
    hierarchy : Cesium.Cartesian3.fromDegreesArray([
                              -109.080842,45.002073,
                              -105.91517,45.002073,
                              -104.058488,44.996596,
                              -104.053011,43.002989,
                              -104.053011,41.003906,
                              -105.728954,40.998429,
                              -107.919731,41.003906,
                              -109.04798,40.998429,
                              -111.047063,40.998429,
                              -111.047063,42.000709,
                              -111.047063,44.476286,
                              -111.05254,45.002073]),
    height : 0,
    material : Cesium.Color.RED.withAlpha(0.5),
    outline : true,
    outlineColor : Cesium.Color.BLACK
  }
});

viewer.zoomTo(wyoming);

Hitting the Run button in the toolbar (or F8 on the keyboard) produces the following:

Wyoming 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 Entity via 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:

Ellipse Circles and ellipses
entity.ellipse
Code example
Reference documentation
Corridor Corridor
entity.corridor
Code example
Reference documentation
Cylinder Cylinder and cones
entity.cylinder
Code example
Reference documentation
Polygon Polygons
entity.polygon
Code example
Reference documentation
Polyline Polylines
entity.polyline
Code example
Reference documentation
Volume Polyline volumes
entity.polylineVolume
Code example
Reference documentation
Rectangle Rectangles
entity.rectangle
Code example
Reference documentation
Ellipsoid Spheres and ellipsoids
entity.ellipsoid
Code example
Reference documentation

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.

When fill is true, the material property determines what that fill looks like. The following creates a translucent blue ellipse.

Copy to clipboard. Data copied clipboard.
var entity = viewer.entities.add({
  position: Cesium.Cartesian3.fromDegrees(-103.0, 40.0),
  ellipse : {
    semiMinorAxis : 250000.0,
    semiMajorAxis : 400000.0,
    material : Cesium.Color.BLUE.withAlpha(0.5)
  }
});
viewer.zoomTo(viewer.entities);

var ellipse = entity.ellipse; // For upcoming examples

Material Color

Image

We can also specify a url to an image instead of a color.

Copy to clipboard. Data copied clipboard.
ellipse.material = '/docs/tutorials/creating-entities/images/cats.jpg';

Material Image

In both the above cases, a ColorMaterialProperty or 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.

Checkerboard

Copy to clipboard. Data copied clipboard.
ellipse.material = new Cesium.CheckerboardMaterialProperty({
  evenColor : Cesium.Color.WHITE,
  oddColor : Cesium.Color.BLACK,
  repeat : new Cesium.Cartesian2(4, 4)
});

Checkerboard Material

Stripe

Copy to clipboard. Data copied clipboard.
ellipse.material = new Cesium.StripeMaterialProperty({
  evenColor : Cesium.Color.WHITE,
  oddColor : Cesium.Color.BLACK,
  repeat : 32
});

Striped Material

Grid

Copy to clipboard. Data copied clipboard.
ellipse.material = new Cesium.GridMaterialProperty({
  color : Cesium.Color.YELLOW,
  cellAlpha : 0.2,
  lineCount : new Cesium.Cartesian2(8, 8),
  lineThickness : new Cesium.Cartesian2(2.0, 2.0)
});

Grid Material

Outlines

outline relies on the outlineColor and outlineWidth properties. 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.

Copy to clipboard. Data copied clipboard.
ellipse.fill = false;
ellipse.outline = true;
ellipse.outlineColor = Cesium.Color.YELLOW;
ellipse.outlineWidth = 2.0;

Outlines

Polylines

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.

Copy to clipboard. Data copied clipboard.
var entity = viewer.entities.add({
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArray([-77, 35,
                                                        -77.1, 35]),
    width : 5,
    material : Cesium.Color.RED
}});
viewer.zoomTo(viewer.entities);

var polyline = entity.polyline // For upcoming examples

Polylines

Polyline outline

Copy to clipboard. Data copied clipboard.
polyline.material = new Cesium.PolylineOutlineMaterialProperty({
    color : Cesium.Color.ORANGE,
    outlineWidth : 3,
    outlineColor : Cesium.Color.BLACK
});

Polyline Outline

Polyline glow

Copy to clipboard. Data copied clipboard.
polyline.material = new Cesium.PolylineGlowMaterialProperty({
    glowPower : 0.2,
    color : Cesium.Color.BLUE
});

Polyline Glow

Heights and extrusions

Surface shapes including corridor, ellipse, polygon, and 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.

Copy to clipboard. Data copied clipboard.
wyoming.polygon.height = 250000;

Wyoming at 250,000 meters Wyoming at 250,000 meters.

To extrude the shape into a volume, set the extrudedHeight property. The volume will be created between height and extrudedHeight. If height is undefined, the volume starts at 0. Create a volume that starts at 200,000 meters and extends to 250,000 meters.

Copy to clipboard. Data copied clipboard.
wyoming.polygon.height = 200000;
wyoming.polygon.extrudedHeight = 250000;

Extruded polygon 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 Entity.description property.

Copy to clipboard. Data copied clipboard.
wyoming.name = 'wyoming';
wyoming.description = '\
<img\
  width="50%"\
  style="float:left; margin: 0 1em 1em 0;"\
  src="//cesium.com/docs/tutorials/creating-entities/Flag_of_Wyoming.svg"/>\
<p>\
  Wyoming is a state in the mountain region of the Western \
  United States.\
</p>\
<p>\
  Wyoming is the 10th most extensive, but the least populous \
  and the second least densely populated of the 50 United \
  States. The western two thirds of the state is covered mostly \
  with the mountain ranges and rangelands in the foothills of \
  the eastern Rocky Mountains, while the eastern third of the \
  state is high elevation prairie known as the High Plains. \
  Cheyenne is the capital and the most populous city in Wyoming, \
  with a population estimate of 63,624 in 2017.\
</p>\
<p>\
  Source: \
  <a style="color: WHITE"\
    target="_blank"\
    href="http://en.wikipedia.org/wiki/Wyoming">Wikpedia</a>\
</p>';

Set entity description Setting the entity description allows for HTML formatted information to be displayed in the InfoBox.

All HTML shown in the InfoBox is sandboxed. This prevents external data sources from injecting malicious code into a Cesium application. To run JavaScript or browser plugins inside of a description, access the iframe used for sandboxing via the viewer.infoBox.frame property. See this article for more information on controlling iframe sandboxing.

Camera controls

Use the 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 Entity, EntityCollection, a 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 HeadingPitchRange.

Copy to clipboard. Data copied clipboard.
var heading = Cesium.Math.toRadians(90);
var pitch = Cesium.Math.toRadians(-30);
viewer.zoomTo(wyoming, new Cesium.HeadingPitchRange(heading, pitch));

Zoom offset Wyoming viewer from the east.

Both zoomTo and 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.

Copy to clipboard. Data copied clipboard.
viewer.flyTo(wyoming).then(function(result){
    if (result) {
        viewer.selectedEntity = wyoming;
    }
});

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.

Copy to clipboard. Data copied clipboard.
wyoming.position = Cesium.Cartesian3.fromDegrees(-107.724, 42.68);
viewer.trackedEntity = wyoming;

Stop tracking by setting viewer.trackedEntity to undefined or by double clicking away from the entity. Calling zoomTo or flyTo will also cancel tracking.

Managing entities

EntityCollection is an associative array for managing and monitoring a group of entities. viewer.entities is an EntityCollection. EntityCollection includes methods such as add, remove, and 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.

Copy to clipboard. Data copied clipboard.
viewer.entities.add({
    id : 'uniqueId'
});

Retrieve the entity using getById. In the event that no entity with the provided ID exists, undefined is returned.

Copy to clipboard. Data copied clipboard.
var entity = viewer.entities.getById('uniqueId');

To fetch an entity or create a new one if it does not exist, use getOrCreateEntity.

Copy to clipboard. Data copied clipboard.
var entity = viewer.entities.getOrCreateEntity('uniqueId');

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.

Copy to clipboard. Data copied clipboard.
var entity = new Entity({
    id : 'uniqueId'
});
viewer.entities.add(entity);

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.

Copy to clipboard. Data copied clipboard.
function onChanged(collection, added, removed, changed){
  var msg = 'Added ids';
  for(var i = 0; i < added.length; i++) {
    msg += '\n' + added[i].id;
  }
  console.log(msg);
}
viewer.entities.collectionChanged.addEventListener(onChanged);

You should see about 65 messages in the console when you run the example, one for every call to viewer.entities.add.

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.

Picking

Picking (clicking to select an object) is one of the areas where we need to interface briefly with the Primitive API. Use scene.pick and scene.drillPick to retrieve an entity.

Copy to clipboard. Data copied clipboard.
/**
 * Returns the top-most entity at the provided window coordinates
 * or undefined if no entity is at that location.
 *
 * @param {Cartesian2} windowPosition The window coordinates.
 * @returns {Entity} The picked entity or undefined.
 */
function pickEntity(viewer, windowPosition) {
  var picked = viewer.scene.pick(windowPosition);
  if (defined(picked)) {
    var id = Cesium.defaultValue(picked.id, picked.primitive.id);
    if (id instanceof Cesium.Entity) {
      return id;
    }
  }
  return undefined;
};

/**
 * Returns the list of entities at the provided window coordinates.
 * The entities are sorted front to back by their visual order.
 *
 * @param {Cartesian2} windowPosition The window coordinates.
 * @returns {Entity[]} The picked entities or undefined.
 */
function drillPickEntities(viewer, windowPosition) {
  var i;
  var entity;
  var picked;
  var pickedPrimitives = viewer.scene.drillPick(windowPosition);
  var length = pickedPrimitives.length;
  var result = [];
  var hash = {};

  for (i = 0; i < length; i++) {
    picked = pickedPrimitives[i];
    entity = Cesium.defaultValue(picked.id, picked.primitive.id);
    if (entity instanceof Cesium.Entity &&
        !Cesium.defined(hash[entity.id])) {
      result.push(entity);
      hash[entity.id] = true;
    }
  }
  return result;
};

Points, billboards, and labels

Create a graphical point or label by setting a position , a point, and label. For example, place a point at the home stadium of our favorite sports team.

Copy to clipboard. Data copied clipboard.
var viewer = new Cesium.Viewer('cesiumContainer');

var citizensBankPark = viewer.entities.add({
    name : 'Citizens Bank Park',
    position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
    point : {
        pixelSize : 5,
        color : Cesium.Color.RED,
        outlineColor : Cesium.Color.WHITE,
        outlineWidth : 2
    },
    label : {
        text : 'Citizens Bank Park',
        font : '14pt monospace',
        style: Cesium.LabelStyle.FILL_AND_OUTLINE,
        outlineWidth : 2,
        verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
        pixelOffset : new Cesium.Cartesian2(0, -9)
    }
});

viewer.zoomTo(viewer.entities);

Point label 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 (0, -9).

Replace the point with a billboard, which is a marker that’s always facing the user.

Copy to clipboard. Data copied clipboard.
var citizensBankPark = viewer.entities.add({
  position : Cesium.Cartesian3.fromDegrees(-75.166493, 39.9060534),
  billboard : {
    image : '//cesiumjs.org/tutorials/Visualizing-Spatial-Data/images/Philadelphia_Phillies.png',
    width : 64,
    height : 64
  },
  label : {
    text : 'Citizens Bank Park',
    font : '14pt monospace',
    style: Cesium.LabelStyle.FILL_AND_OUTLINE,
    outlineWidth : 2,
    verticalOrigin : Cesium.VerticalOrigin.TOP,
    pixelOffset : new Cesium.Cartesian2(0, 32)
  }
});

Phillies logo The Philadelphia Phillies logo as a billboard at our entity’s position.

See the Sandcastle Labels and Billboards Sandcastle examples for more customization options.

3D models

CesiumJS supports 3D Models via glTF, the runtime asset format. You can find example models in the 3D models Sandcastle example.

Set a position and a URI to the glTF model to create model entity.

Copy to clipboard. Data copied clipboard.
var viewer = new Cesium.Viewer('cesiumContainer');
var entity = viewer.entities.add({
    position : Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706),
    model : {
        uri : '../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb'
    }
});
viewer.trackedEntity = entity;

Truck model 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.

Copy to clipboard. Data copied clipboard.
var viewer = new Cesium.Viewer('cesiumContainer');
var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706);
var heading = Cesium.Math.toRadians(45.0);
var pitch = Cesium.Math.toRadians(15.0);
var roll = Cesium.Math.toRadians(0.0);
var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, new Cesium.HeadingPitchRoll(heading, pitch, roll));

var entity = viewer.entities.add({
    position : position,
    orientation : orientation,
    model : {
        uri : '../../../../Apps/SampleData/models/GroundVehicle/GroundVehicle.glb'
    }
});
viewer.trackedEntity = entity;

For more advanced model features, see the 3D Model tutorial. If you create your own models, be sure to see our post on glTF Tips for Artists.

The property system

All values we define for our entities are stored as Property objects. For example, see the value of our Wyoming outline:

Copy to clipboard. Data copied clipboard.
console.log(typeof wyoming.polygon.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:

Copy to clipboard. Data copied clipboard.
var wyoming = new Cesium.Entity();
wyoming.name = 'Wyoming';

var polygon = new Cesium.PolygonGraphics();
polygon.material = new Cesium.ColorMaterialProperty(Cesium.Color.RED.withAlpha(0.5));
polygon.outline = new Cesium.ConstantProperty(true);
polygon.outlineColor = new Cesium.ConstantProperty(Cesium.Color.BLACK);
wyoming.polygon = polygon;

viewer.entities.add(wyoming);

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.

Resources

Check out the Cesium Workshop Tutorial for examples of how to style and create entities using GeoJSON and CZML.