Skip to main content

Ellipses

Interactive ellipses extend the circle concept to support different horizontal and vertical radii. In Locus, ellipses are created using the Circle component with different width and height values.

Creating an Ellipse

An ellipse is simply a circle with different width and height dimensions:

import { Circle } from '@wangyaoshen/locus-2d';

// Create an ellipse with width=200, height=100
<Circle
width={200}
height={100}
fill="rgba(33, 150, 243, 0.3)"
stroke="#2196F3"
lineWidth={3}
/>

Interactive Ellipse

Use InteractiveCircle with different dimensions to create a draggable ellipse:

import { InteractiveCircle } from '@wangyaoshen/locus-2d';
import { Vector2 } from '@wangyaoshen/locus-core';

<InteractiveCircle
width={200}
height={100}
fill="rgba(156, 39, 176, 0.3)"
stroke="#9C27B0"
lineWidth={3}
position={new Vector2(0, 0)}
interactive={true}
onMove={(pos) => console.log('Ellipse center:', pos)}
/>

Ellipse Properties

PropertyDescription
widthHorizontal diameter (2 × semi-major axis if width > height)
heightVertical diameter (2 × semi-minor axis if width > height)
positionCenter point of the ellipse
fillFill color
strokeStroke color

Use Cases

Orbit Visualization

// Create an elliptical orbit path
<Circle
width={400}
height={200}
stroke="#4CAF50"
lineWidth={2}
fill="transparent"
/>

// Add a draggable point on the orbit
<InteractiveCircle
size={20}
fill="#FF5722"
position={new Vector2(200, 0)}
constrain={ellipse([0, 0], 200, 100)}
interactive={true}
/>

Ellipse with Foci

// For an ellipse with semi-axes a and b:
// c = sqrt(a² - b²) where a > b
const a = 200; // semi-major
const b = 100; // semi-minor
const c = Math.sqrt(a * a - b * b);

// Foci at (-c, 0) and (c, 0)
const focus1 = [-c, 0];
const focus2 = [c, 0];

Constraining to Ellipse

Use the ellipse constraint to keep points on an elliptical path:

import { InteractivePoint, ellipse } from '@wangyaoshen/locus-interaction';

const point = new InteractivePoint({
position: [200, 0],
// Constrain to ellipse centered at origin with semi-axes 200, 100
constrain: ellipse([0, 0], 200, 100),
onMove: (pos) => {
const angle = Math.atan2(pos[1] / 100, pos[0] / 200);
console.log('Angle on ellipse:', angle);
},
});

Ellipse vs Circle

AspectCircleEllipse
RadiiEqual (r)Different (a, b)
Equationx² + y² = r²x²/a² + y²/b² = 1
FociOne (center)Two (along major axis)
Eccentricity00 < e < 1

Mathematical Properties

For an ellipse with semi-major axis a and semi-minor axis b:

// Eccentricity
const eccentricity = Math.sqrt(1 - (b * b) / (a * a));

// Focal distance from center
const focalDistance = Math.sqrt(a * a - b * b);

// Point on ellipse at angle θ
const pointOnEllipse = (theta) => [
a * Math.cos(theta),
b * Math.sin(theta),
];

// Perimeter (approximation)
const perimeter = Math.PI * (3 * (a + b) - Math.sqrt((3 * a + b) * (a + 3 * b)));

// Area
const area = Math.PI * a * b;