Skip to main content

Overview

The PlanCamera class manages camera positioning, controls, and viewport interactions in OpenPlans. It provides a top-down view optimized for architectural and engineering drawings with built-in orbit controls, zoom functionality, and view fitting capabilities.

Camera System

PlanCamera uses the camera-controls library to provide smooth, intuitive camera interactions. The camera is automatically configured for plan view (top-down) rendering.

Initialization

The camera is automatically created when you instantiate OpenPlans:
const container = document.getElementById('canvas');
const openplans = new OpenPlans(container);

// PlanCamera is automatically initialized and configured
// Access it via openplans.planCamera (internal property)

Properties

controls
CameraControls
The camera controls instance providing orbit, pan, and zoom functionality. Based on the camera-controls library.Key features:
  • Orbit rotation (disabled for touch with one finger)
  • Pan with mouse drag
  • Zoom with mouse wheel
  • Dolly to cursor position
clock
THREE.Clock
Internal clock used for smooth camera animations and transitions.

Configuration

The camera is pre-configured with the following settings:
// Default camera position (top-down view)
camera.position.set(0, 20, 0);

// Controls configuration
controls.touches.one = CameraControls.ACTION.NONE;  // Disable one-finger touch rotation
controls.dollyToCursor = true;                      // Zoom towards cursor
controls.minDistance = 1.5;                          // Minimum zoom distance

Methods

fitToElement()

Automatically adjusts the camera to frame one or more meshes in the viewport.
const walls = [
  openplans.line({ startPoint: [0, 0, 0], endPoint: [10, 0, 0], color: 0x000000 }),
  openplans.line({ startPoint: [10, 0, 0], endPoint: [10, 0, 8], color: 0x000000 })
];

// Fit camera to view all walls
openplans.planCamera.fitToElement(walls);
meshes
THREE.Mesh[]
required
Array of Three.js meshes to fit in the viewport. The camera will adjust position and zoom to show all provided meshes with a small margin.
How it works:
  1. Calculates a bounding box containing all meshes
  2. Expands the box by 2 units for padding
  3. Fits the camera to the bounding sphere
  4. Animates the transition smoothly

update()

Updates the camera controls. This is called automatically in the render loop.
// This happens automatically in OpenPlans
function animate() {
  planCamera.update();
  renderer.render(scene, camera);
}
Internal behavior:
  • Calculates delta time since last update
  • Updates camera controls with smooth interpolation
  • Handles ongoing camera animations

setupCamera()

Internal method for additional camera configuration. This method is called during initialization to set up camera-controls integration.
Camera presets and view modes can be implemented by manually configuring the camera-controls instance through the OpenPlans API.

Usage with OpenPlans Methods

OpenPlans provides high-level methods that utilize the PlanCamera internally:

fit()

Fit the camera to all entities of a specific type:
// Create multiple rectangles
openplans.rectangle({ center: [0, 0, 0], width: 5, height: 5, color: 0xFF0000 });
openplans.rectangle({ center: [10, 0, 10], width: 5, height: 5, color: 0x00FF00 });

// Fit camera to view all rectangles
openplans.fit('RectanglePrimitive');
element
string
required
The ogType of elements to fit (e.g., ‘LinePrimitive’, ‘RectanglePrimitive’, ‘space’).

Complete Example

import { OpenPlans } from '@opengeometry/openplans';

// Initialize
const container = document.getElementById('canvas');
const openplans = new OpenPlans(container);
await openplans.setupOpenGeometry();

// Create a floor plan
const walls = [
  openplans.line({ startPoint: [0, 0, 0], endPoint: [10, 0, 0], color: 0x000000 }),
  openplans.line({ startPoint: [10, 0, 0], endPoint: [10, 0, 8], color: 0x000000 }),
  openplans.line({ startPoint: [10, 0, 8], endPoint: [0, 0, 8], color: 0x000000 }),
  openplans.line({ startPoint: [0, 0, 8], endPoint: [0, 0, 0], color: 0x000000 })
];

// Fit camera to show entire floor plan
openplans.fit('LinePrimitive');

// Add camera controls event listener
openplans.planCamera.controls.addEventListener('update', () => {
  console.log('Camera moved!');
});

// Manually fit to specific elements
const door = openplans.baseDoor({ /* config */ });
setTimeout(() => {
  openplans.planCamera.fitToElement([door]);
}, 2000);

Advanced Camera Controls

Access the underlying camera-controls instance for advanced functionality:
const controls = openplans.planCamera.controls;

// Move camera to specific position
controls.moveTo(10, 20, 10, true);  // x, y, z, enableTransition

// Set camera rotation
controls.rotateTo(0, Math.PI / 2, true);

// Zoom to specific distance
controls.dollyTo(15, true);

// Reset camera
controls.reset(true);

// Disable/enable controls
controls.enabled = false;
See the camera-controls documentation for more advanced usage.

2D Views

OpenPlans supports creating additional 2D orthographic views:
const view2DContainer = document.getElementById('2d-view');
const { camera, renderer } = openplans.create2DView(view2DContainer, 0);

// The 2D view will automatically render with the main scene
container
HTMLElement
required
The container element for the 2D view.
sectionHeight
number
default:"0"
The height at which to create a horizontal section plane for the 2D view.
Returns: Object containing the camera and renderer for the 2D view.

Camera Events

Listen to camera events for custom interactions:
// Camera update event
openplans.planCamera.controls.addEventListener('update', () => {
  // Triggered when camera moves, zooms, or rotates
  console.log('Camera updated');
});

// Control start event
openplans.planCamera.controls.addEventListener('controlstart', () => {
  console.log('User started interacting');
});

// Control end event
openplans.planCamera.controls.addEventListener('controlend', () => {
  console.log('User finished interacting');
});

Best Practices

  • Use fitToElement() or fit() to frame content after adding elements
  • Listen to camera events to update UI or trigger actions
  • Set appropriate minDistance for your scale
  • Use camera transitions for smooth user experience
  • Consider creating 2D views for section cuts and detail views

Notes

  • The camera starts at position (0, 20, 0) looking down at the origin
  • One-finger touch rotation is disabled to prevent accidental rotations on mobile
  • Zoom dollies toward the cursor position for intuitive interaction
  • The minimum zoom distance is set to 1.5 units
  • Camera updates are synchronized with the render loop automatically
Last modified on March 7, 2026