Camera controllers for asset inspection#13604
Conversation
|
🔴 There was an error checking the CLA! If this is your first contribution, please send in a Contributor License Agreement. |
There was a problem hiding this comment.
No context here, just stumbled over this and was curious, because ... #12346 , #12989 , and others.
So very high-level:
I wondered whether the Controller and ControllerHost may need some infrastructure around other state changes, beyond "being added". Right now, there is the firstUpdate function to be called when a controller was added. Do controllers need special treatment depending on whether they have been disabled previously and are enabled in the new frame?
There's a lot of room for generalizations around HybridScreenspacePanCameraController. It's using very specific instances and conditions. One could pull out that angle-based criterion into some 'predicate' and associate that with the respective controller, yielding some CompoundController with pseudocode
const c = new CompoundController();
const condition = () => thatAngleIsBelow(125);
c.register(condition, new ControllerA());
c.register(() => true, new ControllerB());
I also wondered whether there is a conceptual overlap between the ControllerHost and that "Hybrid" controller, insofar that they are ~"both just dispatching input actions to Controller instances". But that may require more thought. Related, or more generally: Whether or not there should be some concept of indicating that ~"an input/event was consumed (and should stop being 'propagated')" may have to be thought through as well.
| * interface and is not intended to be instantiated directly. | ||
| * @class | ||
| * @abstract | ||
| * @see {@link HybridScreenspacePanCameraController} |
There was a problem hiding this comment.
Should we make casing consistent with ScreenSpaceCameraController? https://cesium.com/learn/cesiumjs/ref-doc/ScreenSpaceCameraController.html?classFilter=ScreenSpace
|
Posting types diff for easier comprehension Types diffdiff --git a/Source/Cesium.main.d.ts b/Source/Cesium.d.ts
index 58b1c55252..ca62847bce 100644
--- a/Source/Cesium.main.d.ts
+++ b/Source/Cesium.d.ts
@@ -9788,6 +9788,26 @@ export namespace Math {
* @returns The linearly interpolated value.
*/
function lerp(p: number, q: number, time: number): number;
+ /**
+ * @property value - The new value after applying the smooth damp.
+ * @property velocity - The updated current velocity.
+ */
+ type SmoothDampResult = {
+ value: number;
+ velocity: number;
+ };
+ /**
+ * Gradually changes a value towards a target value over time. The smoothing function uses a spring-damping algorithm based on Game Programming Gems 4 Chapter 1.10.
+ * @param p - The current value.
+ * @param q - The target value.
+ * @param velocity - The current velocity.
+ * @param [deltaTime = 0.0] - The time since the last call to this function. Value must be greater than or equal to 0.0.
+ * @param [maximumSpeed = Number.POSITIVE_INFINITY] - Optionally allows clamping to the specified maximum speed.
+ * @param [smoothTime = 0.0001] - Approximately the time it will take to reach the target. A smaller value will reach the target faster. This value must be greater than or equal to 0.0001.
+ * @param [result] - An object to store the result. If not provided, a new object will be created and returned.
+ * @returns An object containing the new value and the updated current velocity.
+ */
+ function smoothDamp(p: number, q: number, velocity: number, deltaTime?: number, maximumSpeed?: number, smoothTime?: number, result?: SmoothDampResult): SmoothDampResult;
/**
* pi
*/
@@ -28939,6 +28959,13 @@ export class Camera {
* @param [offset] - The offset from the target in a reference frame centered at the target.
*/
lookAtTransform(transform: Matrix4, offset?: Cartesian3 | HeadingPitchRange): void;
+ /**
+ * Sets the camera orientation to look at a target position in world coordinates. The camera's up vector will be oriented to the world up vector at the target position.
+ * If the camera is at the target position, the camera will be oriented to the world up vector at the target position.
+ * @param target - The target position in world coordinates.
+ * @param [ellipsoid = Ellipsoid.default] - The ellipsoid to use for determining the world up.
+ */
+ lookAtWorldPosition(target: Cartesian3, ellipsoid?: Ellipsoid): void;
/**
* Get the camera position needed to view a rectangle on an ellipsoid or map
* @param rectangle - The rectangle to view.
@@ -32580,6 +32607,467 @@ export class ConeEmitter {
constructor(angle?: number);
}
+/**
+ * An interface for a camera controller that can be registered with the scene to handle input events, camera animations, and other interactions. Implementations of this interface are expected to be registered with the scene via a {@link ControllerHost}.
+ * This type describes an
+ * interface and is not intended to be instantiated directly.
+ */
+export class Controller {
+ /**
+ * Determines if the controller is enabled and should be updated by the host scene.
+ */
+ enabled: boolean;
+ /**
+ * Invoked when the controller is added to the DOM. Implement <code>connectedCallback</code> to set up any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ connectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked when the controller is removed from the DOM. Implement <code>disconnectedCallback</code> to tear down any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ disconnectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked once per frame. Implement <code>update</code> to modify the camera or other parts of the scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+ /**
+ * Invoked when the controller is being updated the first time, immediately before <code>update</code> is called. Implement <code>firstUpdate</code> to perform one-time work after the relevant scene has begun it's render loop. Some examples might include initializing simulation time values or adding a primitive to the scene.
+ * @param time - The current simulation time.
+ */
+ firstUpdate(scene: Scene, time: JulianDate): void;
+}
+
+/**
+ * Creates an instance of a <code>ControllerHost</code>. Typically, a <code>ControllerHost</code> is created by the Scene constructor and accessed via {@link Scene#controllerHost}.
+ */
+export class ControllerHost {
+ /**
+ * The number of controllers registered to this host.
+ */
+ readonly controllerCount: number;
+ /**
+ * Registers a controller implementation with this host.
+ * @param controller - An implementation of the Controller interface to register with this host.
+ * @param element - The DOM element containing the Cesium scene.
+ * @param [priority = 0] - An index, less than or equal to the current count of registed controllers, that defines the precedence of the new controller relative to those previously registered. A priority of <code>0</code> would mean the new controller would apply it's updates before any other controller. As subsequent controllers are updated, their effects are applied on top of any previous update effects. If omitted, the new controller becomes the highest priority, i.e., it's updates are applied after all other controllers.
+ */
+ registerController(controller: Controller, element: HTMLElement, priority?: number): void;
+ /**
+ * Unregisters a controller implementation from this host.
+ * @param controller - An implementation of the Controller interface to unregister from this host.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ unregisterController(controller: Controller, element: HTMLElement): void;
+ /**
+ * Invoked once per frame by the host scene. Updates all registered controllers in order of their priority.
+ * @param scene - The host scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+}
+
+export interface HybridScreenspacePanCameraController extends Controller {
+}
+
+/**
+ * A contextual camera controller that combines screenspace map panning and screenspace elevator panning. The controller automatically switches between the two based on the camera's angle relative to nadir. If the camera is looking mostly down (within angleThreshold of nadir), <code>ScreenspaceMapCameraController</code> is used.
+ * If the camera is looking towards the horizon (beyond angleThreshold from nadir), the <code>ScreenspaceElevatorCameraController</code> is used.
+ * @example
+ * viewer.scene.screenSpaceCameraController.enableInputs = false;
+ * viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const hybridController = new HybridScreenspacePanCameraController();
+ * viewer.addController(hybridController);
+ */
+export class HybridScreenspacePanCameraController implements Controller {
+ /**
+ * The angle threshold in radians that determines which controller is used. If the camera is looking within this angle of nadir, the map controller is used. Otherwise, the elevator controller is used.
+ */
+ angleThreshold: number;
+ /**
+ * The controller that is used when the camera is looking more horizontally (beyond angleThreshold from nadir).
+ */
+ readonly elevatorController: ScreenspaceElevatorCameraController;
+ /**
+ * The controller that is used when the camera is looking mostly down (within angleThreshold of nadir).
+ */
+ readonly mapController: ScreenspaceMapCameraController;
+ /**
+ * Determines if the controller is enabled and should be updated by the host scene.
+ */
+ enabled: boolean;
+ /**
+ * Invoked when the controller is added to the DOM. Implement <code>connectedCallback</code> to set up any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ connectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked when the controller is removed from the DOM. Implement <code>disconnectedCallback</code> to tear down any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ disconnectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked once per frame. Implement <code>update</code> to modify the camera or other parts of the scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+ /**
+ * Invoked when the controller is being updated the first time, immediately before <code>update</code> is called. Implement <code>firstUpdate</code> to perform one-time work after the relevant scene has begun it's render loop. Some examples might include initializing simulation time values or adding a primitive to the scene.
+ * @param time - The current simulation time.
+ */
+ firstUpdate(scene: Scene, time: JulianDate): void;
+}
+
+/**
+ * This enumerated type is for classifying mouse buttons: left, middle, and right.
+ */
+export enum MouseButton {
+ /**
+ * Represents a mouse left button.
+ */
+ LEFT = 0,
+ /**
+ * Represents a mouse middle button.
+ */
+ MIDDLE = 1,
+ /**
+ * Represents a mouse right button.
+ */
+ RIGHT = 2
+}
+
+export namespace ScreenspaceElevatorCameraController {
+ /**
+ * @property [dragInputs] - The drag input bindings that control panning.
+ */
+ type ControllerOptions = {
+ dragInputs?: ScreenspaceInputBindings.InputBinding[];
+ };
+ /**
+ * @property startPosition - The position of the mouse when the drag started.
+ * @property endPosition - The position of the mouse when the drag ended.
+ */
+ type DragEvent = {
+ startPosition: Cartesian2;
+ endPosition: Cartesian2;
+ };
+}
+
+export interface ScreenspaceElevatorCameraController extends Controller {
+}
+
+/**
+ * Creates an instance of a ScreenspaceElevatorCameraController.
+ * @example
+ * viewer.scene.screenSpaceCameraController.enableInputs = false;
+ * viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const elevatorCameraController = new Cesium.ScreenspaceElevatorCameraController();
+ * viewer.addController(elevatorCameraController);
+ * @example
+ * // Configure the controller to use the right mouse button for panning instead of the default left mouse button.
+ * const elevatorCameraController = new Cesium.ScreenspaceElevatorCameraController({
+ * dragInputs: [{ button: Cesium.MouseButton.RIGHT}]
+ * });
+ * viewer.addController(elevatorCameraController);
+ * @param [options] - The options for configuring the controller.
+ */
+export class ScreenspaceElevatorCameraController implements Controller {
+ constructor(options?: ScreenspaceElevatorCameraController.ControllerOptions);
+ /**
+ * The drag input bindings that control vertical panning. Each binding is a combination of the mouse button
+ * and an optional keyboard modifier.
+ */
+ dragInputs: ScreenspaceInputBindings.InputBinding[];
+ /**
+ * The speed in meters per pixel at which the camera pans.
+ */
+ panSpeed: number;
+ /**
+ * The rate at which the camera's pan velocity decays over time.
+ */
+ inertialDecay: number;
+ /**
+ * A parameter in the range <code>[0, 1)</code> used to limit the range
+ * of inputs to a percentage of the window width/height per animation frame.
+ * This helps keep the camera under control in low-frame-rate situations.
+ */
+ maximumMovementRatio: number;
+ /**
+ * Determines if the controller is enabled and should be updated by the host scene.
+ */
+ enabled: boolean;
+ /**
+ * Invoked when the controller is added to the DOM. Implement <code>connectedCallback</code> to set up any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ connectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked when the controller is removed from the DOM. Implement <code>disconnectedCallback</code> to tear down any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ disconnectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked once per frame. Implement <code>update</code> to modify the camera or other parts of the scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+ /**
+ * Invoked when the controller is being updated the first time, immediately before <code>update</code> is called. Implement <code>firstUpdate</code> to perform one-time work after the relevant scene has begun it's render loop. Some examples might include initializing simulation time values or adding a primitive to the scene.
+ * @param time - The current simulation time.
+ */
+ firstUpdate(scene: Scene, time: JulianDate): void;
+}
+
+export namespace ScreenspaceInputBindings {
+ /**
+ * @property button - The mouse button used for drag start/stop.
+ * @property [modifier] - The optional keyboard modifier to register.
+ */
+ type InputBinding = {
+ button: MouseButton;
+ modifier?: number;
+ };
+ /**
+ * @property start - Called on drag start.
+ * @property end - Called on drag stop.
+ * @property move - Called on drag move.
+ */
+ type DragInputActions = {
+ start: (...params: any[]) => any;
+ end: (...params: any[]) => any;
+ move: (...params: any[]) => any;
+ };
+ /**
+ * Registers drag input bindings on a screen space event handler.
+ * @param handler - The screen space event handler.
+ * @param inputBindings - The drag bindings to register.
+ * @param dragInputActions - The callbacks to invoke for drag actions.
+ */
+ function registerDragInputBindings(handler: ScreenSpaceEventHandler, inputBindings: InputBinding[], dragInputActions: DragInputActions): void;
+}
+
+export namespace ScreenspaceMapCameraController {
+ /**
+ * @property [dragInputs] - The drag input bindings that control panning.
+ */
+ type ControllerOptions = {
+ dragInputs?: ScreenspaceInputBindings.InputBinding[];
+ };
+ /**
+ * @property startPosition - The position of the mouse when the drag started.
+ * @property endPosition - The position of the mouse when the drag ended.
+ */
+ type DragEvent = {
+ startPosition: Cartesian2;
+ endPosition: Cartesian2;
+ };
+}
+
+export interface ScreenspaceMapCameraController extends Controller {
+}
+
+/**
+ * Creates an instance of a ScreenspaceMapCameraController.
+ * @example
+ * viewer.scene.screenSpaceCameraController.enableInputs = false;
+ *
+ * const mapCameraController = new Cesium.ScreenspaceMapCameraController();
+ * viewer.addController(mapCameraController);
+ * @example
+ * // Configure the controller to use the right mouse button for panning instead of the default left mouse button.
+ * const mapCameraController = new Cesium.ScreenspaceMapCameraController({
+ * dragInputs: [{ button: Cesium.MouseButton.RIGHT}]
+ * });
+ * viewer.addController(mapCameraController);
+ * @param [options] - The options for configuring the controller.
+ */
+export class ScreenspaceMapCameraController implements Controller {
+ constructor(options?: ScreenspaceMapCameraController.ControllerOptions);
+ /**
+ * The drag input bindings that map panning. Each binding is a combination of the mouse button
+ * and an optional keyboard modifier.
+ */
+ dragInputs: ScreenspaceInputBindings.InputBinding[];
+ /**
+ * The speed in meters per pixel at which the camera pans.
+ */
+ panSpeed: number;
+ /**
+ * The rate at which the camera's pan velocity decays over time.
+ */
+ inertialDecay: number;
+ /**
+ * A parameter in the range <code>[0, 1)</code> used to limit the range
+ * of inputs to a percentage of the window width/height per animation frame.
+ * This helps keep the camera under control in low-frame-rate situations.
+ */
+ maximumMovementRatio: number;
+ /**
+ * Determines if the controller is enabled and should be updated by the host scene.
+ */
+ enabled: boolean;
+ /**
+ * Invoked when the controller is added to the DOM. Implement <code>connectedCallback</code> to set up any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ connectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked when the controller is removed from the DOM. Implement <code>disconnectedCallback</code> to tear down any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ disconnectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked once per frame. Implement <code>update</code> to modify the camera or other parts of the scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+ /**
+ * Invoked when the controller is being updated the first time, immediately before <code>update</code> is called. Implement <code>firstUpdate</code> to perform one-time work after the relevant scene has begun it's render loop. Some examples might include initializing simulation time values or adding a primitive to the scene.
+ * @param time - The current simulation time.
+ */
+ firstUpdate(scene: Scene, time: JulianDate): void;
+}
+
+export namespace ScreenspaceTiltOrbitCameraController {
+ /**
+ * @property [dragInputs] - The drag input bindings that control tilting and orbiting.
+ */
+ type ControllerOptions = {
+ dragInputs?: ScreenspaceInputBindings.InputBinding[];
+ };
+ /**
+ * @property position - The position of the mouse when the drag started.
+ */
+ type StartDragEvent = {
+ position: Cartesian2;
+ };
+ /**
+ * @property startPosition - The position of the mouse when the drag started.
+ * @property endPosition - The position of the mouse when the drag ended.
+ */
+ type DragEvent = {
+ startPosition: Cartesian2;
+ endPosition: Cartesian2;
+ };
+}
+
+export interface ScreenspaceTiltOrbitCameraController extends Controller {
+}
+
+/**
+ * Creates a new instance of <code>ScreenspaceTiltOrbitCameraController</code>.
+ * @example
+ * viewer.scene.screenSpaceCameraController.enableInputs = false;
+ * viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const tiltOrbitController = new Cesium.ScreenspaceTiltOrbitCameraController();
+ * viewer.addController(tiltOrbitController);
+ * @example
+ * // Configure the controller to use the left mouse button for tilting and orbiting instead of the default right mouse button.
+ * const tiltOrbitController = new Cesium.ScreenspaceTiltOrbitCameraController({
+ * dragInputs: [{ button: Cesium.MouseButton.LEFT }]
+ * });
+ * viewer.addController(tiltOrbitController);
+ * @param [options] - The options for configuring the controller.
+ */
+export class ScreenspaceTiltOrbitCameraController implements Controller {
+ constructor(options?: ScreenspaceTiltOrbitCameraController.ControllerOptions);
+ /**
+ * Enabled dragging to tilt the camera.
+ */
+ tiltEnabled: boolean;
+ /**
+ * Enabled dragging to orbit the camera.
+ */
+ orbitEnabled: boolean;
+ /**
+ * The drag input bindings that control tilting. Each binding is a combination of the mouse button
+ * and an optional keyboard modifier.
+ */
+ dragInputs: ScreenspaceInputBindings.InputBinding[];
+ /**
+ * The amount at which the camera tilts per dragged pixel. A value of 1.0 means that dragging the mouse across the entire canvas will tilt the camera by 90 degrees.
+ */
+ tiltMagnitude: number;
+ /**
+ * Specifies the length of time in seconds in which a single tilt animation completes.
+ */
+ tiltAnimationDuration: number;
+ /**
+ * The maximum tilt velocity in radians per second. A value of Number.POSITIVE_INFINITY means that the maximum tilt velocity is unbounded.
+ */
+ maximumTiltVelocity: number;
+ /**
+ * The minimum tilt angle in radians from the zenith, or the ellipsoid surface normal, at the tilt origin at which the camera can orbit.
+ */
+ minimumOrbitTiltAngle: number;
+ /**
+ * The amount at which the camera orbits per dragged pixel. A value of 1.0 means that dragging the mouse across the entire canvas will orbit the camera by 180 degrees.
+ */
+ orbitMagnitude: number;
+ /**
+ * Specifies the length of time in seconds in which a single orbit animation completes.
+ */
+ orbitAnimationDuration: number;
+ /**
+ * The maximum orbit velocity in radians per second. A value of Number.POSITIVE_INFINITY means that the maximum orbit velocity is unbounded.
+ */
+ maximumOrbitVelocity: number;
+ /**
+ * A parameter in the range <code>[0, 1)</code> used to limit the range
+ * of inputs to a percentage of the window width/height per animation frame.
+ * This helps keep the camera under control in low-frame-rate situations.
+ */
+ maximumMovementRatio: number;
+ /**
+ * Attempts to orbit the camera around the specified origin by the specified amount in radians. Positive values orbit the camera clockwise, negative values orbit the camera counterclockwise. If the drag origin is not on the ellipsoid, no orbit is applied.
+ * @param camera - The camera to orbit.
+ * @param target - The target position to orbit around in world coordinates.
+ * @param axis - The axis to orbit around, typically the negative of the surface normal at the target position.
+ * @param amount - The amount to orbit the camera in radians. Positive values orbit the camera clockwise, negative values orbit the camera counterclockwise.
+ * @param dt - The time delta in seconds since the last update.
+ * @param [ellipsoid = Ellipsoid.default] - The ellipsoid to pick for the orbit origin. If undefined, the default ellipsoid is used.
+ */
+ orbit(camera: Camera, target: Cartesian3, axis: Cartesian3, amount: number, dt: number, ellipsoid?: Ellipsoid): void;
+ /**
+ * Attempts to tilt the camera by the specified amount in radians. Positive values tilt the camera down, negative values tilt the camera up. If the drag origin is not on the ellipsoid, no tilt is applied.
+ * @param camera - The camera to tilt.
+ * @param target - The target position to tilt around in world coordinates.
+ * @param axis - The axis to tilt around, typically the negative of the surface normal at the target position.
+ * @param amount - The amount to tilt the camera in radians. Positive values tilt the camera down, negative values tilt the camera up.
+ * @param dt - The time delta in seconds since the last update. Value must be greater than 0.
+ * @param [ellipsoid = Ellipsoid.default] - The ellipsoid to pick for the tilt origin. If undefined, the default ellipsoid is used.
+ */
+ tilt(camera: Camera, target: Cartesian3, axis: Cartesian3, amount: number, dt: number, ellipsoid?: Ellipsoid): void;
+ /**
+ * Determines if the controller is enabled and should be updated by the host scene.
+ */
+ enabled: boolean;
+ /**
+ * Invoked when the controller is added to the DOM. Implement <code>connectedCallback</code> to set up any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ connectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked when the controller is removed from the DOM. Implement <code>disconnectedCallback</code> to tear down any DOM event listeners.
+ * @param element - The DOM element containing the Cesium scene.
+ */
+ disconnectedCallback(element: HTMLElement): void;
+ /**
+ * Invoked once per frame. Implement <code>update</code> to modify the camera or other parts of the scene.
+ * @param time - The current simulation time.
+ */
+ update(scene: Scene, time: JulianDate): void;
+ /**
+ * Invoked when the controller is being updated the first time, immediately before <code>update</code> is called. Implement <code>firstUpdate</code> to perform one-time work after the relevant scene has begun it's render loop. Some examples might include initializing simulation time values or adding a primitive to the scene.
+ * @param time - The current simulation time.
+ */
+ firstUpdate(scene: Scene, time: JulianDate): void;
+}
+
/**
* The credit display is responsible for displaying credits on screen.
* @example
@@ -43634,6 +44122,16 @@ export class Scene {
* Gets or sets the camera.
*/
readonly camera: Camera;
+ /**
+ * Collects an array of <code>Controller</code> objects that can be registered with the scene to handle input events, camera animations, and other interactions.
+ * @example
+ * scene.screenSpaceCameraController.enableInputs = false;
+ * scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const tiltOrbitController = new Cesium.ScreenspaceTiltOrbitCameraController();
+ * scene.controllerHost.registerController(tiltOrbitController, scene.canvas.parentNode);
+ */
+ readonly controllerHost: ControllerHost;
/**
* Gets the controller for camera input handling.
*/
@@ -47234,6 +47732,24 @@ export class CesiumWidget {
* unless <code>useDefaultRenderLoop</code> is set to false;
*/
render(): void;
+ /**
+ * Adds a controller— an implementation of the {@link Controller} interface used to handle input events, camera animations, and other interactions— to the widget's scene.
+ * @example
+ * widget.scene.screenSpaceCameraController.enableInputs = false;
+ * widget.scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const tiltOrbitController = new Cesium.ScreenspaceTiltOrbitCameraController();
+ * widget.addController(tiltOrbitController);
+ * @param controller - An implementation of the <code>Controller</code> interface.
+ */
+ addController(controller: Controller): void;
+ /**
+ * Removes a controller— an implementation of the {@link Controller} interface used to handle input events, camera animations, and other interactions— from the widget's scene.
+ * @example
+ * widget.removeController(tiltOrbitController);
+ * @param controller - An implementation of the <code>Controller</code> interface.
+ */
+ removeController(controller: Controller): void;
/**
* Asynchronously sets the camera to view the provided entity, entities, or data source.
* If the data source is still in the process of loading or the visualization is otherwise still loading,
@@ -49650,6 +50166,24 @@ export class Viewer {
* removing the widget from layout.
*/
destroy(): void;
+ /**
+ * Adds a controller— an implementation of the {@link Controller} interface used to handle input events, camera animations, and other interactions— to the viewer's scene.
+ * @example
+ * viewer.scene.screenSpaceCameraController.enableInputs = false;
+ * viewer.scene.screenSpaceCameraController.enableCollisionDetection = false;
+ *
+ * const tiltOrbitController = new Cesium.ScreenspaceTiltOrbitCameraController();
+ * viewer.addController(tiltOrbitController);
+ * @param controller - An implementation of the <code>Controller</code> interface.
+ */
+ addController(controller: Controller): void;
+ /**
+ * Removes a controller— an implementation of the {@link Controller} interface used to handle input events, camera animations, and other interactions— from the viewer's scene.
+ * @example
+ * viewer.removeController(tiltOrbitController);
+ * @param controller - An implementation of the <code>Controller</code> interface.
+ */
+ removeController(controller: Controller): void;
/**
* Asynchronously sets the camera to view the provided entity, entities, or data source.
* If the data source is still in the process of loading or the visualization is otherwise still loading,
|
|
This is looking great. Great organization and configurability with new code that is minimal but wires together existing resources. I will continue to test the controllers with the time available. |
Co-authored-by: Marco Hutter <javagl@javagl.de>
Co-authored-by: Marco Hutter <javagl@javagl.de>
@javagl I think this is going to depend on the Controller implementation. Rather than generalize this, I'm opting to leave it up to the implementation to handle if applicable. The Controllers implemented here, for example, need to reset their timestamps if re-enabled.
I considered this as well. At the moment, we do not provide a mechanism to stop event propagation, but I also did not identify any use case where that was needed thus far. I think this could be introduced later in a not completely breaking way if we find its needed. |
| <td>Orbit</td> | ||
| </tr> | ||
| <tr> | ||
| <td>Zoom</td> |
There was a problem hiding this comment.
Is zoom enabled currently in this scene? Seems like no?
And is this top left UI menu complete? Is the intent to just list which controls work as the scene is currently set up?
There was a problem hiding this comment.
The UI menu is not yet complete— I was going to add short descriptions and note the default controls.
| scene.screenSpaceCameraController.enableCollisionDetection = false; | ||
|
|
||
| // Set up the modular camera controllers | ||
| const panController = new Cesium.HybridScreenspacePanCameraController(); |
There was a problem hiding this comment.
I am not sure I am using / understanding this controller correctly. Is my understanding correct that the behavior changes from horizontal to vertical at the 125 degrees threshold? I am not seeing this happen as I use this sandcastle, maybe I am not understanding where the threshold is. Maybe some more instructions or a visual indicator could help.
Edit: Actually I think I get it now and I really like it. Feels super intuitive. Could be useful to tell to show a hint when the mode changes from Map to Elevator, but not necessary to add now.
|
Thanks for the reviews so far @lukemckinstry and @javagl! There are a few remaining todo's, so let's aim to get this in after today's release. |
Known TODOs:
Required before merge:
CHANGES.mdOptional/Follow-ups
Description
This PR:
Controllerframework, as discussed in Extensible camera controller architecture #13473.Controllerclasses. These are designed as a drop-in alternative to the defaultScreenspaceCameraControllerfor more simple camera controls scoped for an asset inspect use case.Camera function matrix
ScreenspaceMapCameraController- Single touch drag
- Panning plane originates at pointer position
- Inertia with configurable exponential decay
ScreenspaceElevatorCameraController- Panning plane originates at pointer position
- Inertia with configurable exponential decay
HybridScreenspacePanCameraControllerScreenspaceTiltOrbitCameraController- Left mouse button + ctrl
- Two touch drag
- Maintains camera up relative to ellipsoid normal
- Tilts around screen center position; Fallbacks to pointer position
- Critical damping with configurable interpolation time and max velocity
- Camera is allowed to rotate below ellipsoid (underground)
ScreenspaceTiltOrbitCameraController- Maintains camera up relative to ellipsoid normal
- Orbits around screen center position; Fallbacks to pointer position
- Critical damping with configurable interpolation time and max velocity
ScreenspaceZoomCameraController- Center mouse button drag
- Two touch pinch
- Velocity is proportional to distance from target based on configurable percentage
- Configurable maximum distance limit
- Inertia with configurable exponential decay
ScreenspaceCameraController.CesiumMath.smoothDampwith unit tests; Compare to Unity'sMathf.SmoothDamp.Issue number and link
Fixes #13473
CC swisstopo/swissgeol-viewer-suite#1854
Testing plan
TODO: Deployed sandcastle link
TODO: Deployed doc link
Author checklist
CONTRIBUTORS.mdCHANGES.mdwith a short summary of my changeAI acknowledgment
If yes, I used the following Tools(s) and/or Service(s): GitHub Copilot autocomplete
If yes, I used the following Model(s): Various