The camera in Cesium controls the view in the scene. There are many ways to manipulate the camera, such as rotate, zoom, pan, and fly to a destination. Cesium has default mouse and touch event handlers to interact with the camera, and an API to programmatically manipulate the camera. This tutorial introduces camera concepts and the related Cesium APIs.

Quick start

Let’s start with an example. Open the Hello World example in Sandcastle. By default, the scene handles mouse and touch input for the camera. The defaults are:

  • Left click and drag - Rotates the camera around the globe in 3D and translates the camera over the map surface in 2D and Columbus view.
  • Right click and drag - Zooms the camera in and out.
  • Middle wheel scrolling - Also zooms the camera in and out.
  • Middle click and drag - Rotates the camera around the point on the surface of the globe.

We can set the camera position and orientation programatically with the setView function. The arguments are destination and orentation. The position can be either an instance of Cartesian3 or Rectangle, and orientation can either be heading/pitch/roll or direction/up. The heading, pitch and roll angles are required to be in radians. Heading is the rotation from the local north direction where a positive angle is increasing eastward. Pitch is the rotation from the local east-north plane. Positive pitch angles are above the plane. Negative pitch angles are below the plane. Roll is the first rotation applied about the local east axis. For example, setting the view with a cartesian position looks like:

camera.setView({
    destination : new Cesium.Cartesian3(x, y, z),
    orientation: {
        heading : headingAngle,
        pitch : pitchAngle,
        roll : rollAngle
    }
});

An example setting the position using a rectangle:

viewer.camera.setView({
    destination : Cesium.Rectangle.fromDegrees(west, south, east, north),
    orientation: {
        heading : headingAngle,
        pitch : pitchAngle,
        roll : rollAngle
    }
    
});

All of the parameters are optional. The default values for any undefined parameters are the current camera position, heading, pitch, and roll.

The most common use case is to set the camera position looking straight down at the Earth with the heading oriented to north:

camera.setView({
    destination : Cesium.Cartesian3.fromDegrees(longitude, latitude, height),
    orientation: {
        heading : 0.0,
        pitch : -Cesium.Math.PI_OVER_TWO,
        roll : 0.0
    }
});

Custom Camera mouse/keyboard events

Let’s create our own event handlers that make the camera look towards the direction of the mouse and move forward, backward, left, right, up, and down on key presses. Let’s start by disabling the default event handlers. Add the following code (after var viewer = ...):

var scene = viewer.scene;
var canvas = viewer.canvas;
canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas
canvas.onclick = function() {
    canvas.focus();
};
var ellipsoid = viewer.scene.globe.ellipsoid;

// disable the default event handlers
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableTranslate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.screenSpaceCameraController.enableTilt = false;
scene.screenSpaceCameraController.enableLook = false;

Next, create variables to record the current mouse position, and flags to keep track of how the camera is moving:

var startMousePosition;
var mousePosition;
var flags = {
    looking : false,
    moveForward : false,
    moveBackward : false,
    moveUp : false,
    moveDown : false,
    moveLeft : false,
    moveRight : false
};

Add an event handler to set a flag when the left mouse button has been clicked and to record the current mouse position:

var handler = new Cesium.ScreenSpaceEventHandler(canvas);

handler.setInputAction(function(movement) {
    flags.looking = true;
    mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);

handler.setInputAction(function(movement) {
    mousePosition = movement.endPosition;
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

handler.setInputAction(function(position) {
    flags.looking = false;
}, Cesium.ScreenSpaceEventType.LEFT_UP);

Create keyboard event handlers to toggle flags for camera movement. We will set flags for the following keys and behaviors:

  • w will move the camera forward.
  • s will move the camera backward.
  • a will move the camera to the left.
  • d will move the camera to the right.
  • q will move the camera up.
  • e will move the camera down.
function getFlagForKeyCode(keyCode) {
    switch (keyCode) {
    case 'W'.charCodeAt(0):
        return 'moveForward';
    case 'S'.charCodeAt(0):
        return 'moveBackward';
    case 'Q'.charCodeAt(0):
        return 'moveUp';
    case 'E'.charCodeAt(0):
        return 'moveDown';
    case 'D'.charCodeAt(0):
        return 'moveRight';
    case 'A'.charCodeAt(0):
        return 'moveLeft';
    default:
        return undefined;
    }
}

document.addEventListener('keydown', function(e) {
    var flagName = getFlagForKeyCode(e.keyCode);
    if (typeof flagName !== 'undefined') {
        flags[flagName] = true;
    }
}, false);

document.addEventListener('keyup', function(e) {
    var flagName = getFlagForKeyCode(e.keyCode);
    if (typeof flagName !== 'undefined') {
        flags[flagName] = false;
    }
}, false);

Now we want to update the camera when the flags indicating that an event occurred are true. We can add a listener to the onTick event on the clock containing the following code:

viewer.clock.onTick.addEventListener(function(clock) {
    var camera = viewer.camera;
});

Next, make the camera look in the direction of mouse cursor. Add this code to our event listener function under the variable declarations:

if (flags.looking) {
    var width = canvas.clientWidth;
    var height = canvas.clientHeight;

    // Coordinate (0.0, 0.0) will be where the mouse was clicked.
    var x = (mousePosition.x - startMousePosition.x) / width;
    var y = -(mousePosition.y - startMousePosition.y) / height;

    var lookFactor = 0.05;
    camera.lookRight(x * lookFactor);
    camera.lookUp(y * lookFactor);
}

The method lookRight and lookUp take a single argument in radians which is the angle to rotate. We transform the mouse coordinates to be in the range (-1.0, 1.0) with the coordinate (0.0, 0.0) to be in the center of the canvas. The distance the mouse is from the center determines the speed of the turn. A position closer to the center moves the camera slower while farther from the center moves the camera faster.

To finish, let’s add code to move the camera’s position. Also add this to the event listener function:

// Change movement speed based on the distance of the camera to the surface of the ellipsoid.
var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;
var moveRate = cameraHeight / 100.0;

if (flags.moveForward) {
    camera.moveForward(moveRate);
}
if (flags.moveBackward) {
    camera.moveBackward(moveRate);
}
if (flags.moveUp) {
    camera.moveUp(moveRate);
}
if (flags.moveDown) {
    camera.moveDown(moveRate);
}
if (flags.moveLeft) {
    camera.moveLeft(moveRate);
}
if (flags.moveRight) {
    camera.moveRight(moveRate);
}

The moveForward, moveBackward,moveUp, moveDown, moveLeft, and moveRight methods take a single argument in meters to move the camera. The distance the camera will move on each key press changes as the distance from the camera to the surface of the ellipsoid changes. The closer the camera is to the surface the slower it will move on each key press.

The complete code is:

var viewer = new Cesium.Viewer('cesiumContainer');

var scene = viewer.scene;
var canvas = viewer.canvas;
canvas.setAttribute('tabindex', '0'); // needed to put focus on the canvas
canvas.onclick = function() {
    canvas.focus();
};
var ellipsoid = viewer.scene.globe.ellipsoid;

// disable the default event handlers
scene.screenSpaceCameraController.enableRotate = false;
scene.screenSpaceCameraController.enableTranslate = false;
scene.screenSpaceCameraController.enableZoom = false;
scene.screenSpaceCameraController.enableTilt = false;
scene.screenSpaceCameraController.enableLook = false;

var startMousePosition;
var mousePosition;
var flags = {
    looking : false,
    moveForward : false,
    moveBackward : false,
    moveUp : false,
    moveDown : false,
    moveLeft : false,
    moveRight : false
};

var handler = new Cesium.ScreenSpaceEventHandler(canvas);

handler.setInputAction(function(movement) {
    flags.looking = true;
    mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);

handler.setInputAction(function(movement) {
    mousePosition = movement.endPosition;
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

handler.setInputAction(function(position) {
    flags.looking = false;
}, Cesium.ScreenSpaceEventType.LEFT_UP);

function getFlagForKeyCode(keyCode) {
    switch (keyCode) {
    case 'W'.charCodeAt(0):
        return 'moveForward';
    case 'S'.charCodeAt(0):
        return 'moveBackward';
    case 'Q'.charCodeAt(0):
        return 'moveUp';
    case 'E'.charCodeAt(0):
        return 'moveDown';
    case 'D'.charCodeAt(0):
        return 'moveRight';
    case 'A'.charCodeAt(0):
        return 'moveLeft';
    default:
        return undefined;
    }
}

document.addEventListener('keydown', function(e) {
    var flagName = getFlagForKeyCode(e.keyCode);
    if (typeof flagName !== 'undefined') {
        flags[flagName] = true;
    }
}, false);

document.addEventListener('keyup', function(e) {
    var flagName = getFlagForKeyCode(e.keyCode);
    if (typeof flagName !== 'undefined') {
        flags[flagName] = false;
    }
}, false);

viewer.clock.onTick.addEventListener(function(clock) {
    var camera = viewer.camera;

    if (flags.looking) {
        var width = canvas.clientWidth;
        var height = canvas.clientHeight;

        // Coordinate (0.0, 0.0) will be where the mouse was clicked.
        var x = (mousePosition.x - startMousePosition.x) / width;
        var y = -(mousePosition.y - startMousePosition.y) / height;

        var lookFactor = 0.05;
        camera.lookRight(x * lookFactor);
        camera.lookUp(y * lookFactor);
    }

    // Change movement speed based on the distance of the camera to the surface of the ellipsoid.
    var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;
    var moveRate = cameraHeight / 100.0;

    if (flags.moveForward) {
        camera.moveForward(moveRate);
    }
    if (flags.moveBackward) {
        camera.moveBackward(moveRate);
    }
    if (flags.moveUp) {
        camera.moveUp(moveRate);
    }
    if (flags.moveDown) {
        camera.moveDown(moveRate);
    }
    if (flags.moveLeft) {
        camera.moveLeft(moveRate);
    }
    if (flags.moveRight) {
        camera.moveRight(moveRate);
    }
});

See the full example in the Sandcastle.

Camera

The Camera represents the state of the camera’s current position, orientation, reference frame, and view frustum.

  • The move* and zoom* functions translate the camera’s position along its orientation or a given vector. The orientation remains fixed.

  • The look* and twist* functions rotate the orientation about the direction, up, or right vectors. The position remains fixed.

  • The rotate* functions rotate the position and orientation about a given vector.

Note: The camera vectors above are orthonormal in each frame.

  • Functions to set the camera position and orientation given an extent or a position and target. For example:
var west = Cesium.Math.toRadians(-77.0);
var south = Cesium.Math.toRadians(38.0);
var east = Cesium.Math.toRadians(-72.0);
var north = Cesium.Math.toRadians(42.0);
var extent = new Cesium.Extent(west, south, east, north);
camera.viewExtent(extent, Cesium.Ellipsoid.WGS84);
  • Functions to create a ray from the camera position through a pixel. This is useful for picking, for example:
// find intersection of the pixel picked and an ellipsoid
var ray = camera.getPickRay(mousePosition);
var intersection = Cesium.IntersectionTests.rayEllipsoid(ray, Cesium.Ellipsoid.WGS84);

Screen space camera controller

The ScreenSpaceCameraController converts user input, like mouse and touch, from window coordinates to camera motion. It contains properties for enabling/disabling different types of input, modifying the amount of inertia and the minimum and maximum zoom distances.

Resources

Check out the camera examples in Sandcastle:

  • Camera Tutorial - Code example from this tutorial.
  • Camera - Code examples to fly to locations, view extents, and set the camera’s reference frame.

Also, check out the reference documentation: