Camera

The camera in CesiumJS controls the view of the scene. There are many ways to manipulate the camera, such as rotate, zoom, pan, and fly to a destination. CesiumJS has mouse and touch event handlers to interact with the camera, and an API to programmatically manipulate the camera. Learn how to use the Camera API and to customize camera controls.

Default camera behavior

Open the Hello World example in Sandcastle to explore the default camera controls. The defaults are:

Mouse Action 3D 2D Columbus View
Left click + drag Rotate around the globe Translate over the map Translate over the map
Right click + drag Zoom in and out Zoom in and out Zoom in and out
Middle wheel scrolling Zoom in and out Zoom in and out Zoom in and out
Middle click + drag Tilt the globe No action Tilt the map

Set the camera position and orientation programatically with the setView function. destination can be a Cartesian3 or Rectangle, and orientation can be heading/pitch/roll or direction/up. The heading, pitch, and roll angles are defined 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.

Copy to clipboard. Data copied clipboard.
camera.setView({
    destination : new Cesium.Cartesian3(x, y, z),
    orientation: {
        heading : headingAngle,
        pitch : pitchAngle,
        roll : rollAngle
    }
});
Copy to clipboard. Data copied clipboard.
viewer.camera.setView({
    destination : Cesium.Rectangle.fromDegrees(west, south, east, north),
    orientation: {
        heading : headingAngle,
        pitch : pitchAngle,
        roll : rollAngle
    }
});

All of the parameters are optional. If not specified, parameter values will default to the current camera position and orientation.

Set the camera position looking straight down at the Earth with the heading oriented to north using the following:

Copy to clipboard. Data copied clipboard.
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 or 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. Start by disabling the default event handlers. Add the following code (after var viewer = ...):

Copy to clipboard. Data copied clipboard.
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;

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

Copy to clipboard. Data copied clipboard.
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:

Copy to clipboard. Data copied clipboard.
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.
Copy to clipboard. Data copied clipboard.
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:

Copy to clipboard. Data copied clipboard.
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:

Copy to clipboard. Data copied clipboard.
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, add code to move the camera’s position. Also add this to the event listener function:

Copy to clipboard. Data copied clipboard.
// 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](/docs/cesiumjs-ref-doc/Camera.html?#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 the following:

Copy to clipboard. Data copied clipboard.
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);
    }
});

Open complete code example

Camera

The Camera represents the state of the camera’s current position, orientation, reference frame, and view frustum. The camera vectors above are orthonormal in each frame.

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

Move

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

Twist

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

Rotate

Functions to set the camera position and orientation given an extent or a position and target. For example:

Copy to clipboard. Data copied clipboard.
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:

Copy to clipboard. Data copied clipboard.
// 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, such as mouse and touch, from window coordinates to camera motion. It contains properties for enabling and 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: