diff --git a/docs/components/guide-examples/examples/ProjectileMotion.tsx b/docs/components/guide-examples/examples/ProjectileMotion.tsx
index 22fabd3e..c233031a 100644
--- a/docs/components/guide-examples/examples/ProjectileMotion.tsx
+++ b/docs/components/guide-examples/examples/ProjectileMotion.tsx
@@ -75,7 +75,7 @@ export default function ProjectileMotion() {
<>
diff --git a/docs/components/guide-examples/plots/twisty-boi.tsx b/docs/components/guide-examples/plots/twisty-boi.tsx
index 74fefe8c..5974e73c 100644
--- a/docs/components/guide-examples/plots/twisty-boi.tsx
+++ b/docs/components/guide-examples/plots/twisty-boi.tsx
@@ -20,7 +20,7 @@ export default function TwistyBoi() {
[Math.cos(t), (t / k) * Math.sin(t)]}
/>
diff --git a/src/display/Plot/OfX.tsx b/src/display/Plot/OfX.tsx
index 4e8cd138..e9cc76a2 100644
--- a/src/display/Plot/OfX.tsx
+++ b/src/display/Plot/OfX.tsx
@@ -3,20 +3,25 @@ import { usePaneContext } from "../../context/PaneContext"
import { Parametric, ParametricProps } from "./Parametric"
import { vec } from "../../vec"
-export interface OfXProps extends Omit {
+export interface OfXProps extends Omit {
y: (x: number) => number
+ domain?: vec.Vector2
svgPathProps?: React.SVGProps
}
-export function OfX({ y, ...props }: OfXProps) {
+export function OfX({ y, domain, ...props }: OfXProps) {
+ const [xuMin, xuMax] = domain ?? [-Infinity, Infinity]
const {
- xPaneRange: [xMin, xMax],
+ xPaneRange: [xpMin, xpMax],
} = usePaneContext()
+ // Determine the most restrictive range values (either user-provided or the pane context)
+ const xMin = Math.max(xuMin, xpMin)
+ const xMax = Math.min(xuMax, xpMax)
const xy = React.useCallback((x) => [x, y(x)], [y])
- const t = React.useMemo(() => [xMin, xMax], [xMin, xMax])
+ const parametricDomain = React.useMemo(() => [xMin, xMax], [xMin, xMax])
- return
+ return
}
OfX.displayName = "Plot.OfX"
diff --git a/src/display/Plot/OfY.tsx b/src/display/Plot/OfY.tsx
index 273ab363..c3c36472 100644
--- a/src/display/Plot/OfY.tsx
+++ b/src/display/Plot/OfY.tsx
@@ -3,20 +3,25 @@ import { usePaneContext } from "../../context/PaneContext"
import { Parametric, ParametricProps } from "./Parametric"
import { vec } from "../../vec"
-export interface OfYProps extends Omit {
+export interface OfYProps extends Omit {
x: (y: number) => number
+ domain?: vec.Vector2
svgPathProps?: React.SVGProps
}
-export function OfY({ x, ...props }: OfYProps) {
+export function OfY({ x, domain, ...props }: OfYProps) {
+ const [yuMin, yuMax] = domain ?? [-Infinity, Infinity]
const {
- yPaneRange: [yMin, yMax],
+ yPaneRange: [ypMin, ypMax],
} = usePaneContext()
+ // Determine the most restrictive range values (either user-provided or the pane context)
+ const yMin = Math.max(yuMin, ypMin)
+ const yMax = Math.min(yuMax, ypMax)
const xy = React.useCallback((y) => [x(y), y], [x])
- const t = React.useMemo(() => [yMin, yMax], [yMin, yMax])
+ const parametricDomain = React.useMemo(() => [yMin, yMax], [yMin, yMax])
- return
+ return
}
OfY.displayName = "Plot.OfY"
diff --git a/src/display/Plot/Parametric.tsx b/src/display/Plot/Parametric.tsx
index d0abc9c1..c618e44e 100644
--- a/src/display/Plot/Parametric.tsx
+++ b/src/display/Plot/Parametric.tsx
@@ -4,10 +4,19 @@ import { Stroked } from "../Theme"
import { useTransformContext } from "../../context/TransformContext"
import { sampleParametric } from "./PlotUtils"
-export interface ParametricProps extends Stroked {
+// TODO: (v1.0.0) When the project has it's first major (breaking) update,
+// remove the Legacy interface and just have the new props interface (renamed, of course).
+// Also, remove the `t` property at that time.
+// Waiting until the major update to batch them together,
+// and to give time for consumers to update their usage.
+interface ParametricPropsLegacy extends Stroked {
/** A function that takes a `t` value and returns a point. */
xy: (t: number) => vec.Vector2
- /** The domain `t` between which to evaluate `xy`. */
+ /** The domain between which to evaluate `xy`. */
+ domain?: never
+ /**
+ * @deprecated - use the `domain` prop.
+ */
t: vec.Vector2
/** The minimum recursive depth of the sampling algorithm. */
minSamplingDepth?: number
@@ -17,8 +26,28 @@ export interface ParametricProps extends Stroked {
svgPathProps?: React.SVGProps
}
+interface ParametricPropsNew extends Stroked {
+ /** A function that takes a `t` value and returns a point. */
+ xy: (t: number) => vec.Vector2
+ /** The domain between which to evaluate `xy`. */
+ domain: vec.Vector2
+ /**
+ * @deprecated - use the `domain` prop.
+ */
+ t?: never
+ /** The minimum recursive depth of the sampling algorithm. */
+ minSamplingDepth?: number
+ /** The maximum recursive depth of the sampling algorithm. */
+ maxSamplingDepth?: number
+
+ svgPathProps?: React.SVGProps
+}
+
+export type ParametricProps = ParametricPropsNew | ParametricPropsLegacy
+
export function Parametric({
xy,
+ domain,
t,
color,
style = "solid",
@@ -33,7 +62,7 @@ export function Parametric({
// Negative because the y-axis is flipped in the SVG coordinate system.
const pixelsPerSquare = -vec.det(viewTransform)
- const [tMin, tMax] = t
+ const [tMin, tMax] = domain || t
const errorThreshold = 0.1 / pixelsPerSquare
const svgPath = React.useMemo(