-
Notifications
You must be signed in to change notification settings - Fork 91
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Scenes: put things next to each other
- Loading branch information
1 parent
1d00248
commit 8ebfc9a
Showing
6 changed files
with
271 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { PropTable } from "components/PropTable" | ||
import CodeAndExample from "components/CodeAndExample" | ||
|
||
import ScenesExample from "guide-examples/display/scenes/ScenesExample" | ||
import Code from "components/Code" | ||
|
||
import type { Metadata } from "next" | ||
|
||
export const metadata: Metadata = { | ||
title: "Scenes", | ||
} | ||
|
||
function ScenesPage() { | ||
return ( | ||
<> | ||
{/* <p> | ||
Scenes are a way to create a new coordinate space and show it inside of Mafs. This can be | ||
useful for doing something like showing two visualizations side-by-side. | ||
</p> | ||
<Code source={`import { Scene } from "mafs"`} language="tsx" /> | ||
<h2>Basic scene</h2> */} | ||
|
||
<CodeAndExample example={ScenesExample} /> | ||
|
||
{/* <PropTable of={"Scene"} /> */} | ||
</> | ||
) | ||
} | ||
|
||
export default ScenesPage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
docs/components/guide-examples/display/scenes/ScenesExample.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
"use client" | ||
|
||
import { clamp } from "lodash" | ||
import { | ||
Circle, | ||
Coordinates, | ||
Mafs, | ||
Plot, | ||
Scene, | ||
Theme, | ||
useMovablePoint, | ||
} from "mafs" | ||
|
||
function Scene1({ sceneSize, sceneSpacing }: any) { | ||
const c = useMovablePoint([0, 0], { | ||
constrain: ([x, y]) => [ | ||
clamp(x, -10, 10), | ||
clamp(y, -10, 10), | ||
], | ||
}) | ||
|
||
return ( | ||
<Scene | ||
x={-sceneSize - sceneSpacing / 2} | ||
y={-sceneSize / 2} | ||
width={sceneSize} | ||
height={sceneSize} | ||
viewBox={{ x: [-10, 10], y: [-10, 10], padding: 3 }} | ||
preserveAspectRatio={false} | ||
> | ||
<Coordinates.Cartesian | ||
xAxis={{ lines: 5 }} | ||
yAxis={{ lines: 5 }} | ||
/> | ||
<Plot.OfX | ||
y={(x) => Math.sin(x - c.x) + (x - c.x) / 2 + c.y} | ||
color={Theme.blue} | ||
/> | ||
{c.element} | ||
</Scene> | ||
) | ||
} | ||
|
||
function Scene2({ sceneSize, sceneSpacing }: any) { | ||
return ( | ||
<Scene | ||
x={sceneSpacing / 2} | ||
y={-sceneSize / 2} | ||
width={sceneSize} | ||
height={sceneSize} | ||
viewBox={{ | ||
x: [-10, 10], | ||
y: [-10, 10], | ||
padding: 3, | ||
}} | ||
preserveAspectRatio={false} | ||
> | ||
<Coordinates.Cartesian | ||
xAxis={{ lines: 5 }} | ||
yAxis={{ lines: 5 }} | ||
/> | ||
<Circle center={[0, 0]} radius={5} /> | ||
</Scene> | ||
) | ||
} | ||
|
||
export default function Example() { | ||
const sceneSize = 250 | ||
const sceneSpacing = 50 | ||
|
||
return ( | ||
<Mafs height={300} pan={false}> | ||
<Scene1 | ||
sceneSize={sceneSize} | ||
sceneSpacing={sceneSpacing} | ||
/> | ||
<Scene2 | ||
sceneSize={sceneSize} | ||
sceneSpacing={sceneSpacing} | ||
/> | ||
</Mafs> | ||
) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
import * as React from "react" | ||
import CoordinateContext, { CoordinateContextShape } from "../context/CoordinateContext" | ||
import PaneManager from "../context/PaneContext" | ||
|
||
import { round } from "../math" | ||
import { vec } from "../vec" | ||
import { TransformContext } from "../context/TransformContext" | ||
import { SpanContext } from "../context/SpanContext" | ||
|
||
export type ScenePropsT = React.PropsWithChildren<{ | ||
width?: number | "auto" | ||
height?: number | ||
|
||
/** Whether to enable panning with the mouse and keyboard */ | ||
pan?: boolean | ||
|
||
/** | ||
* Whether to enable zooming with the mouse and keyboard. This can also be an | ||
* object with `min` and `max` properties to set the scale limits. | ||
* | ||
* * `min` should be in the range (0, 1]. | ||
* * `max` should be in the range [1, ∞). | ||
*/ | ||
zoom?: boolean | { min: number; max: number } | ||
|
||
/** | ||
* A way to declare the "area of interest" of your visualizations. Mafs will center and zoom to | ||
* this area. | ||
*/ | ||
viewBox?: { x?: vec.Vector2; y?: vec.Vector2; padding?: number } | ||
/** | ||
* Whether to squish the graph to fill the Mafs viewport or to preserve the aspect ratio of the | ||
* coordinate space. | ||
*/ | ||
preserveAspectRatio?: "contain" | false | ||
|
||
/** Called when the view is clicked on, and passed the point where it was clicked. */ | ||
onClick?: (point: vec.Vector2, event: MouseEvent) => void | ||
}> | ||
|
||
type SceneProps = { | ||
width: number | ||
height: number | ||
x: number | ||
y: number | ||
} & Required<Pick<ScenePropsT, "viewBox" | "preserveAspectRatio">> & | ||
Pick<ScenePropsT, "children"> | ||
|
||
export function Scene({ x, y, width, height, viewBox, preserveAspectRatio, children }: SceneProps) { | ||
const padding = viewBox?.padding ?? 0.5 | ||
// Default behavior for `preserveAspectRatio == false` | ||
let xMin = (viewBox?.x?.[0] ?? 0) - padding | ||
let xMax = (viewBox?.x?.[1] ?? 0) + padding | ||
let yMin = (viewBox?.y?.[0] ?? 0) - padding | ||
let yMax = (viewBox?.y?.[1] ?? 0) + padding | ||
|
||
if (preserveAspectRatio === "contain") { | ||
const aspect = width / height | ||
const aoiAspect = (xMax - xMin) / (yMax - yMin) | ||
|
||
if (aoiAspect > aspect) { | ||
const yCenter = (yMax + yMin) / 2 | ||
const ySpan = (xMax - xMin) / aspect / 2 | ||
yMin = yCenter - ySpan | ||
yMax = yCenter + ySpan | ||
} else { | ||
const xCenter = (xMax + xMin) / 2 | ||
const xSpan = ((yMax - yMin) * aspect) / 2 | ||
xMin = xCenter - xSpan | ||
xMax = xCenter + xSpan | ||
} | ||
} | ||
|
||
const xSpan = xMax - xMin | ||
const ySpan = yMax - yMin | ||
|
||
const viewTransform = React.useMemo(() => { | ||
const scaleX = round((1 / xSpan) * width, 5) | ||
const scaleY = round((-1 / ySpan) * height, 5) | ||
return vec.matrixBuilder().scale(scaleX, scaleY).get() | ||
}, [height, width, xSpan, ySpan]) | ||
|
||
const viewTransformCSS = vec.toCSS(viewTransform) | ||
|
||
const coordinateContext = React.useMemo<CoordinateContextShape>( | ||
() => ({ xMin, xMax, yMin, yMax, height, width }), | ||
[xMin, xMax, yMin, yMax, height, width], | ||
) | ||
|
||
const id = React.useId() | ||
|
||
console.log({ xSpan, ySpan, viewTransformCSS, coordinateContext }) | ||
|
||
return ( | ||
<CoordinateContext.Provider value={coordinateContext}> | ||
<SpanContext.Provider value={{ xSpan, ySpan }}> | ||
<TransformContext.Provider | ||
value={{ userTransform: vec.identity, viewTransform: viewTransform }} | ||
> | ||
<PaneManager> | ||
<g | ||
transform={`translate(${x + width / 2} ${-y - height / 2})`} | ||
style={{ | ||
...({ | ||
"--mafs-view-transform": viewTransformCSS, | ||
"--mafs-user-transform": "translate(0, 0)", | ||
} as React.CSSProperties), | ||
}} | ||
> | ||
<defs> | ||
<clipPath id={`scene-clip-${id}`}> | ||
<rect | ||
x={xMin} | ||
y={yMin} | ||
width={xSpan} | ||
height={ySpan} | ||
fill="white" | ||
style={{ transform: "var(--mafs-view-transform)" }} | ||
/> | ||
</clipPath> | ||
</defs> | ||
<g clipPath={`url(#scene-clip-${id})`}>{children}</g> | ||
</g> | ||
</PaneManager> | ||
</TransformContext.Provider> | ||
</SpanContext.Provider> | ||
</CoordinateContext.Provider> | ||
) | ||
} | ||
|
||
Scene.displayName = "Scene" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters