Ellipses & circles
Ellipses take a center vector, radius vector, and an angle. Note that if the coordinate plane is not square (if the aspect ratio is "squished"), ellipses undergo a sort of funny-looking shear, which can make visualizations confusing.
import { Mafs, Ellipse, Circle, CartesianCoordinates, useMovablePoint, Theme, } from "mafs"
import * as vec from "vec-la"
function MovableEllipse() {
const rotationHintRadius = 3
// This center point translates everything else.
const center = useMovablePoint([0, 0], {
color: Theme.orange,
})
const translation = vec
.matrixBuilder()
.translate(center.x, center.y)
.get()
// This outer point rotates the ellipse, and
// is also translated by the center point.
// Its position is used to build a rotation matrix.
const rotate = useMovablePoint([rotationHintRadius, 0], {
color: Theme.blue,
transform: translation,
// Constrain this point to only move in a circle
constrain: (position) =>
vec.scale(vec.norm(position), rotationHintRadius),
})
const angle = Math.PI / 2 - Math.atan2(...rotate.point)
const rotation = vec.matrixBuilder().rotate(angle).get()
// Lastly, these two points are rotated and translated
// according to the outer two points.
const width = useMovablePoint([2, 0], {
transform: vec.composeTransform(translation, rotation),
constrain: "horizontal",
})
const height = useMovablePoint([0, 1], {
transform: vec.composeTransform(translation, rotation),
constrain: "vertical",
})
return (
<Mafs>
<CartesianCoordinates />
{/*
* Display a little hint that the
* point is meant to move radially
*/}
<Circle
center={center.point}
radius={rotationHintRadius}
strokeStyle="dashed"
strokeOpacity={0.3}
fillOpacity={0}
/>
<Ellipse
center={center.point}
radius={[Math.abs(width.x), Math.abs(height.y)]}
angle={angle}
/>
{center.element}
{width.element}
{height.element}
{rotate.element}
</Mafs>
)
}
Work in progress
Support for defining ellipses in terms of two foci is planned. In the meantime, you can accomplish this using a parametric function.
Circles
Circles have the same interface as Ellipses, but take a single value for their radius and don't take an angle.
import {
Mafs,
Circle,
CartesianCoordinates,
useMovablePoint,
} from "mafs"
import * as vec from "vec-la"
function MovableCircle() {
const pointOnCircle = useMovablePoint([
Math.sqrt(2) / 2,
Math.sqrt(2) / 2,
])
const r = vec.mag(pointOnCircle.point)
return (
<Mafs>
<CartesianCoordinates />
<Circle center={[0, 0]} radius={r} />
{pointOnCircle.element}
</Mafs>
)
}