mathbox-react 0.0.9-dev-3 → 0.0.11-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/renovate.json +13 -0
- package/.github/workflows/lint.yaml +2 -2
- package/build/cjs/{types/components → components}/ContainedMathbox.d.ts +0 -0
- package/build/cjs/{types/components → components}/Mathbox.d.ts +0 -0
- package/build/cjs/components/MathboxNodeContext.d.ts +4 -0
- package/build/cjs/{types/components → components}/components.d.ts +7 -1
- package/build/cjs/{types/components/Cartesian.spec.d.ts → components/components.spec.d.ts} +0 -0
- package/build/cjs/{types/components → components}/index.d.ts +0 -0
- package/build/cjs/{types/components → components}/types.d.ts +0 -0
- package/build/cjs/components/util.d.ts +38 -0
- package/build/cjs/{types/index.d.ts → index.d.ts} +0 -0
- package/build/cjs/index.js +1 -15
- package/build/cjs/index.js.map +1 -1
- package/build/cjs/{types/stories → stories}/utils.d.ts +0 -0
- package/build/cjs/{types/testSetup.d.ts → testSetup.d.ts} +0 -0
- package/build/cjs/{types/testUtils.d.ts → testUtils.d.ts} +0 -0
- package/build/esm/{types/components → components}/ContainedMathbox.d.ts +0 -0
- package/build/esm/{types/components → components}/Mathbox.d.ts +0 -0
- package/build/esm/components/MathboxNodeContext.d.ts +4 -0
- package/build/esm/{types/components → components}/components.d.ts +7 -1
- package/build/esm/{types/components/Cartesian.spec.d.ts → components/components.spec.d.ts} +0 -0
- package/build/esm/{types/components → components}/index.d.ts +0 -0
- package/build/esm/{types/components → components}/types.d.ts +0 -0
- package/build/esm/components/util.d.ts +38 -0
- package/build/esm/{types/index.d.ts → index.d.ts} +0 -0
- package/build/esm/index.js +1 -15
- package/build/esm/index.js.map +1 -1
- package/build/esm/{types/stories → stories}/utils.d.ts +0 -0
- package/build/esm/{types/testSetup.d.ts → testSetup.d.ts} +0 -0
- package/build/esm/{types/testUtils.d.ts → testUtils.d.ts} +0 -0
- package/build/index.d.ts +9 -1
- package/package.json +41 -37
- package/rollup.config.js +1 -1
- package/src/components/Mathbox.tsx +3 -2
- package/src/components/{Cartesian.spec.tsx → components.spec.tsx} +74 -3
- package/src/components/components.tsx +48 -9
- package/src/components/util.ts +64 -1
- package/src/stories/Point.stories.tsx +8 -1
- package/build/cjs/types/components/MathboxNodeContext.d.ts +0 -4
- package/build/cjs/types/components/util.d.ts +0 -18
- package/build/esm/types/components/MathboxNodeContext.d.ts +0 -4
- package/build/esm/types/components/util.d.ts +0 -18
- package/scratch.js +0 -149
|
@@ -3,12 +3,12 @@ import React, {
|
|
|
3
3
|
useState,
|
|
4
4
|
forwardRef,
|
|
5
5
|
useImperativeHandle,
|
|
6
|
-
useMemo,
|
|
7
6
|
} from "react"
|
|
8
7
|
import { Color } from "three"
|
|
9
8
|
import { mathBox, RootProps, MathboxSelection, MathBoxOptions } from "mathbox"
|
|
10
9
|
import MathboxAPIContext from "./MathboxNodeContext"
|
|
11
10
|
import { WithChildren } from "./types"
|
|
11
|
+
import { useDeepCompareMemo } from "./util"
|
|
12
12
|
|
|
13
13
|
type Props = WithChildren<
|
|
14
14
|
{
|
|
@@ -22,7 +22,7 @@ const Mathbox = (
|
|
|
22
22
|
ref: React.Ref<MathboxSelection<"root"> | null>
|
|
23
23
|
) => {
|
|
24
24
|
const { container, children, options, ...rootProps } = props
|
|
25
|
-
const mathboxOptions =
|
|
25
|
+
const mathboxOptions = useDeepCompareMemo(options ?? {}, {})
|
|
26
26
|
const [selection, setSelection] = useState<MathboxSelection<"root"> | null>(
|
|
27
27
|
null
|
|
28
28
|
)
|
|
@@ -39,6 +39,7 @@ const Mathbox = (
|
|
|
39
39
|
* TODO: Should Mathbox component allow setting these more easily?
|
|
40
40
|
*/
|
|
41
41
|
mathbox.three.renderer.setClearColor(new Color(0xffffff), 1.0)
|
|
42
|
+
mathbox.three.camera.position.set(1, 1, 2)
|
|
42
43
|
return () => {
|
|
43
44
|
mathbox.select("*").remove()
|
|
44
45
|
mathbox.three.destroy()
|
|
@@ -3,7 +3,7 @@ import { render, act } from "@testing-library/react"
|
|
|
3
3
|
import { MathboxSelection } from "mathbox"
|
|
4
4
|
import ContainedMathbox from "./ContainedMathbox"
|
|
5
5
|
import Mathbox from "./Mathbox"
|
|
6
|
-
import { Cartesian, Grid } from "./components"
|
|
6
|
+
import { Cartesian, Grid, Voxel } from "./components"
|
|
7
7
|
import { MathboxRef } from "./types"
|
|
8
8
|
|
|
9
9
|
function assertNotNil<T>(value: T): asserts value is NonNullable<T> {
|
|
@@ -27,6 +27,24 @@ const assertSelectionsEqual = (s1: MathboxSelection, s2: MathboxSelection) => {
|
|
|
27
27
|
})
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
describe("ContainedMathbox", () => {
|
|
31
|
+
it("makes a new mathbox instance only if the options have changed", () => {
|
|
32
|
+
const mbRef: MathboxRef<"root"> = { current: null }
|
|
33
|
+
const { rerender } = render(<ContainedMathbox options={{}} ref={mbRef} />)
|
|
34
|
+
|
|
35
|
+
const mb0 = mbRef.current
|
|
36
|
+
assertNotNil(mb0)
|
|
37
|
+
rerender(<ContainedMathbox options={{}} ref={mbRef} />)
|
|
38
|
+
const mb1 = mbRef.current
|
|
39
|
+
expect(mb1).toBe(mb0)
|
|
40
|
+
assertNotNil(mb1)
|
|
41
|
+
rerender(<ContainedMathbox options={{ plugins: ["core"] }} ref={mbRef} />)
|
|
42
|
+
const mb2 = mbRef.current
|
|
43
|
+
assertNotNil(mb2)
|
|
44
|
+
expect(mb2).not.toBe(mb1)
|
|
45
|
+
})
|
|
46
|
+
})
|
|
47
|
+
|
|
30
48
|
describe("Cartesian", () => {
|
|
31
49
|
it("exposes Mathbox instance via ref", () => {
|
|
32
50
|
const mbRef: MathboxRef<"root"> = { current: null }
|
|
@@ -116,6 +134,41 @@ describe("Cartesian", () => {
|
|
|
116
134
|
expect(cartesian.get("visible")).toBe(false)
|
|
117
135
|
})
|
|
118
136
|
|
|
137
|
+
it("updates liveProps on its mathbox instance when rerendered", async () => {
|
|
138
|
+
const mbRef: MathboxRef<"root"> = { current: null }
|
|
139
|
+
const { rerender } = render(
|
|
140
|
+
<ContainedMathbox ref={mbRef}>
|
|
141
|
+
<Cartesian>
|
|
142
|
+
<Grid
|
|
143
|
+
liveProps={{
|
|
144
|
+
width: (t) => 1 + t,
|
|
145
|
+
}}
|
|
146
|
+
/>
|
|
147
|
+
</Cartesian>
|
|
148
|
+
</ContainedMathbox>
|
|
149
|
+
)
|
|
150
|
+
const grid = mbRef.current?.select<"grid">("grid")
|
|
151
|
+
assertNotNil(grid)
|
|
152
|
+
|
|
153
|
+
const w1 = grid.get("width")
|
|
154
|
+
await new Promise((resolve) => {
|
|
155
|
+
setTimeout(resolve, 500)
|
|
156
|
+
})
|
|
157
|
+
const w2 = grid.get("width")
|
|
158
|
+
expect(w1).toBe(1)
|
|
159
|
+
// Mathbox uses seconds
|
|
160
|
+
expect(w2 - w1).toBeGreaterThan(0.45)
|
|
161
|
+
expect(w2 - w1).toBeLessThanOrEqual(0.5)
|
|
162
|
+
rerender(
|
|
163
|
+
<ContainedMathbox ref={mbRef}>
|
|
164
|
+
<Cartesian>
|
|
165
|
+
<Grid width={10} />
|
|
166
|
+
</Cartesian>
|
|
167
|
+
</ContainedMathbox>
|
|
168
|
+
)
|
|
169
|
+
expect(grid.get("width")).toBe(10)
|
|
170
|
+
})
|
|
171
|
+
|
|
119
172
|
it("re-renders inside new instance when root changes", () => {
|
|
120
173
|
const mbRef: MathboxRef<"root"> = { current: null }
|
|
121
174
|
const cartesianRef: MathboxRef<"cartesian"> = { current: null }
|
|
@@ -145,7 +198,7 @@ describe("Cartesian", () => {
|
|
|
145
198
|
* When re-rendered, this will create a new mathBox since the options
|
|
146
199
|
* object prop will have changed.
|
|
147
200
|
*/
|
|
148
|
-
const options2 = {}
|
|
201
|
+
const options2 = { plugins: ["core"] }
|
|
149
202
|
expect(options1).not.toBe(options2)
|
|
150
203
|
|
|
151
204
|
rerender(
|
|
@@ -163,7 +216,7 @@ describe("Cartesian", () => {
|
|
|
163
216
|
assertNotNil(cartesian2)
|
|
164
217
|
assertNotNil(grid2)
|
|
165
218
|
|
|
166
|
-
//
|
|
219
|
+
// The options have changed (via deep equal) so a new instance is created
|
|
167
220
|
expect(mb1).not.toBe(mb2)
|
|
168
221
|
|
|
169
222
|
expect(cartesian2).toHaveLength(1)
|
|
@@ -238,3 +291,21 @@ describe("Cartesian", () => {
|
|
|
238
291
|
expect(mbRef.current.select("grid").length).toBe(0)
|
|
239
292
|
})
|
|
240
293
|
})
|
|
294
|
+
|
|
295
|
+
describe("<Voxel />", () => {
|
|
296
|
+
it("throws a runtime error if it has children", () => {
|
|
297
|
+
const willThrow = () =>
|
|
298
|
+
render(
|
|
299
|
+
<ContainedMathbox>
|
|
300
|
+
<Cartesian>
|
|
301
|
+
{/* eslint-disable-next-line @typescript-eslint/ban-ts-comment */}
|
|
302
|
+
{/* @ts-expect-error */}
|
|
303
|
+
<Voxel>
|
|
304
|
+
<Grid />
|
|
305
|
+
</Voxel>
|
|
306
|
+
</Cartesian>
|
|
307
|
+
</ContainedMathbox>
|
|
308
|
+
)
|
|
309
|
+
expect(willThrow).toThrow("Component <Voxel /> cannot have children.")
|
|
310
|
+
})
|
|
311
|
+
})
|
|
@@ -9,33 +9,49 @@ import React, {
|
|
|
9
9
|
import { Props, NodeType, MathboxSelection } from "mathbox"
|
|
10
10
|
import MathboxAPIContext from "./MathboxNodeContext"
|
|
11
11
|
import { WithChildren } from "./types"
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import {
|
|
13
|
+
isRootDestroyed,
|
|
14
|
+
isSelectionParent,
|
|
15
|
+
canNodeHaveChildren,
|
|
16
|
+
ParentNodeTypes,
|
|
17
|
+
capitalize,
|
|
18
|
+
} from "./util"
|
|
19
|
+
|
|
20
|
+
type LiveProps<P> = {
|
|
21
|
+
[K in keyof P]: (t: number, dt: number) => P[K]
|
|
22
|
+
}
|
|
14
23
|
type MathboxComponent<T extends NodeType> = React.ForwardRefExoticComponent<
|
|
15
|
-
WithChildren<Props[T]>
|
|
24
|
+
(T extends ParentNodeTypes ? WithChildren<Props[T]> : Props[T]) &
|
|
25
|
+
React.RefAttributes<MathboxSelection<T>> & {
|
|
26
|
+
liveProps?: LiveProps<Props[T]>
|
|
27
|
+
}
|
|
16
28
|
>
|
|
17
29
|
|
|
18
30
|
const mathboxComponentFactory = <T extends NodeType>(
|
|
19
31
|
type: T
|
|
20
32
|
): MathboxComponent<T> => {
|
|
33
|
+
const canHaveChildren = canNodeHaveChildren(type)
|
|
34
|
+
const componentName = capitalize(type)
|
|
21
35
|
const Comp = (
|
|
22
|
-
props: WithChildren<Props[T]
|
|
36
|
+
props: WithChildren<Props[T]> & { liveProps?: LiveProps<Props[T]> },
|
|
23
37
|
ref: React.Ref<MathboxSelection<T> | null>
|
|
24
38
|
) => {
|
|
25
39
|
const [_ignored, forceUpdate] = useReducer((x) => x + 1, 0)
|
|
26
40
|
const parent = useContext(MathboxAPIContext)
|
|
27
41
|
const selection = useRef<MathboxSelection<T> | null>(null)
|
|
42
|
+
const prevLiveProps = useRef<LiveProps<Props[T]> | undefined>(undefined)
|
|
28
43
|
useEffect(
|
|
29
44
|
() => () => {
|
|
30
45
|
if (selection.current) {
|
|
31
46
|
selection.current.remove()
|
|
47
|
+
selection.current = null
|
|
32
48
|
}
|
|
33
49
|
},
|
|
34
50
|
[]
|
|
35
51
|
)
|
|
36
52
|
useImperativeHandle(ref, () => selection.current)
|
|
37
53
|
|
|
38
|
-
const { children, ...others } = props
|
|
54
|
+
const { children, liveProps, ...others } = props
|
|
39
55
|
useEffect(() => {
|
|
40
56
|
if (!parent) return
|
|
41
57
|
if (isRootDestroyed(parent)) {
|
|
@@ -51,14 +67,37 @@ const mathboxComponentFactory = <T extends NodeType>(
|
|
|
51
67
|
}
|
|
52
68
|
if (!selection.current) {
|
|
53
69
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
54
|
-
// @ts-
|
|
55
|
-
selection.current = parent[type](others)
|
|
70
|
+
// @ts-expect-error
|
|
71
|
+
selection.current = parent[type](others, liveProps)
|
|
56
72
|
forceUpdate()
|
|
57
73
|
} else {
|
|
74
|
+
/**
|
|
75
|
+
* If liveProps have changed, remove all the old liveProps.
|
|
76
|
+
* (The same prop cannot be re-assigned live without being un-assigned
|
|
77
|
+
* first.)
|
|
78
|
+
*
|
|
79
|
+
* We could unbind just the ones that have changed, but simpler to
|
|
80
|
+
* unbind them all.
|
|
81
|
+
*/
|
|
82
|
+
if (prevLiveProps.current && liveProps !== prevLiveProps.current) {
|
|
83
|
+
Object.keys(prevLiveProps.current).forEach((key) => {
|
|
84
|
+
// @ts-expect-error this is not in ts yet
|
|
85
|
+
selection.current.unbind(key)
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
if (liveProps && liveProps !== prevLiveProps.current) {
|
|
89
|
+
selection.current.bind(liveProps)
|
|
90
|
+
}
|
|
58
91
|
selection.current.set(others)
|
|
59
92
|
}
|
|
60
|
-
|
|
61
|
-
|
|
93
|
+
prevLiveProps.current = liveProps
|
|
94
|
+
}, [parent, others, liveProps])
|
|
95
|
+
if (!canHaveChildren) {
|
|
96
|
+
if (props.children) {
|
|
97
|
+
throw new Error(`Component <${componentName} /> cannot have children.`)
|
|
98
|
+
}
|
|
99
|
+
return null
|
|
100
|
+
}
|
|
62
101
|
return (
|
|
63
102
|
<MathboxAPIContext.Provider value={selection.current}>
|
|
64
103
|
{props.children}
|
package/src/components/util.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-underscore-dangle */
|
|
2
|
-
import
|
|
2
|
+
import isEqual from "lodash/isEqual"
|
|
3
|
+
import { useRef, useMemo } from "react"
|
|
4
|
+
import { MathboxSelection, NodeType } from "mathbox"
|
|
3
5
|
|
|
4
6
|
type WithPrivateUp = MathboxSelection & { _up?: WithPrivateUp }
|
|
5
7
|
|
|
@@ -41,3 +43,64 @@ export const isSelectionParent = (
|
|
|
41
43
|
const selectionParentNode = (selection as WithPrivateUp)._up?.[0]
|
|
42
44
|
return selectionParentNode === parent[0]
|
|
43
45
|
}
|
|
46
|
+
|
|
47
|
+
const CAN_HAVE_CHILDREN = [
|
|
48
|
+
"view",
|
|
49
|
+
"cartesian",
|
|
50
|
+
"cartesian4",
|
|
51
|
+
"polar",
|
|
52
|
+
"spherical",
|
|
53
|
+
"stereographic",
|
|
54
|
+
"stereographic4",
|
|
55
|
+
"transform",
|
|
56
|
+
"transform4",
|
|
57
|
+
"vertex",
|
|
58
|
+
"fragment",
|
|
59
|
+
"layer",
|
|
60
|
+
"mask",
|
|
61
|
+
"group",
|
|
62
|
+
"inherit",
|
|
63
|
+
"root",
|
|
64
|
+
"unit",
|
|
65
|
+
"rtt",
|
|
66
|
+
"clock",
|
|
67
|
+
"now",
|
|
68
|
+
"move",
|
|
69
|
+
"present",
|
|
70
|
+
"reveal",
|
|
71
|
+
"slide",
|
|
72
|
+
] as const
|
|
73
|
+
|
|
74
|
+
export type ParentNodeTypes = typeof CAN_HAVE_CHILDREN[number]
|
|
75
|
+
|
|
76
|
+
export const canNodeHaveChildren = (type: NodeType) =>
|
|
77
|
+
(CAN_HAVE_CHILDREN as readonly string[]).includes(type)
|
|
78
|
+
|
|
79
|
+
export const capitalize = (s: string) => {
|
|
80
|
+
if (!s) return ""
|
|
81
|
+
return s[0].toLocaleUpperCase() + s.slice(1)
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Returns the same reference to `value` as long as the the given values are
|
|
86
|
+
* deep equal.
|
|
87
|
+
*
|
|
88
|
+
* This is, in general, not a great idea. See
|
|
89
|
+
* https://github.com/facebook/react/issues/14476#issuecomment-471199055
|
|
90
|
+
*
|
|
91
|
+
* This should work OK for mathbox options because the objects in question are
|
|
92
|
+
* either shallow, or are deep equal at a fairly shallow level.
|
|
93
|
+
* E.g., OrbitControls may not be a shall object, but if it's not, it will at
|
|
94
|
+
* least be deep equal between renders.
|
|
95
|
+
*
|
|
96
|
+
* But should work OK for mathbox options.
|
|
97
|
+
*/
|
|
98
|
+
export const useDeepCompareMemo = <T>(value: T, initial: T): T => {
|
|
99
|
+
const oldValue = useRef<T>(initial)
|
|
100
|
+
const memoOptions = useMemo(() => {
|
|
101
|
+
if (isEqual(value, oldValue.current)) return oldValue.current
|
|
102
|
+
oldValue.current = value
|
|
103
|
+
return value
|
|
104
|
+
}, [value])
|
|
105
|
+
return memoOptions
|
|
106
|
+
}
|
|
@@ -29,7 +29,7 @@ export default {
|
|
|
29
29
|
|
|
30
30
|
const Template: Story<React.ComponentProps<typeof Point>> = (args) => {
|
|
31
31
|
const { points, ...otherArgs } = args
|
|
32
|
-
const [data, setData] = useState<MathboxSelection<"array"
|
|
32
|
+
const [data, setData] = useState<MathboxSelection<"array"> | null>(null)
|
|
33
33
|
return (
|
|
34
34
|
<Mathbox containerStyle={{ height: 450 }}>
|
|
35
35
|
<Cartesian
|
|
@@ -66,3 +66,10 @@ const Template: Story<React.ComponentProps<typeof Point>> = (args) => {
|
|
|
66
66
|
|
|
67
67
|
export const DefaultPoint = Template.bind({})
|
|
68
68
|
DefaultPoint.args = {}
|
|
69
|
+
|
|
70
|
+
export const LiveProps = Template.bind({})
|
|
71
|
+
LiveProps.args = {
|
|
72
|
+
liveProps: {
|
|
73
|
+
size: (t: number) => 20 * (1 + 0.5 * Math.sin(t)),
|
|
74
|
+
},
|
|
75
|
+
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { MathboxSelection } from "mathbox";
|
|
2
|
-
export declare const isRootDestroyed: (selection: MathboxSelection) => boolean;
|
|
3
|
-
/**
|
|
4
|
-
* Check that parent is actually the selection's parent.
|
|
5
|
-
* The mathbox components occasionally render with a selection value whose
|
|
6
|
-
* parent does not match the parent specified in MathboxContext.
|
|
7
|
-
*
|
|
8
|
-
* I believe this fundamentally this is happening because
|
|
9
|
-
* - we store parent value in context...
|
|
10
|
-
* - we update the context parent value using useEffect hooks..
|
|
11
|
-
* - useEffect hooks are called children before parents.
|
|
12
|
-
*
|
|
13
|
-
* One wonders whether we really need to be using useEffect hooks for the
|
|
14
|
-
* mathbox components, or if we can just put all the node creation/removal stuff
|
|
15
|
-
* in a render function. Hooks seem nice for dependencies, but mathbox is pretty
|
|
16
|
-
* smart about diffing out the actual changes.
|
|
17
|
-
*/
|
|
18
|
-
export declare const isSelectionParent: (selection: MathboxSelection, parent: MathboxSelection) => boolean;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { MathboxSelection } from "mathbox";
|
|
2
|
-
export declare const isRootDestroyed: (selection: MathboxSelection) => boolean;
|
|
3
|
-
/**
|
|
4
|
-
* Check that parent is actually the selection's parent.
|
|
5
|
-
* The mathbox components occasionally render with a selection value whose
|
|
6
|
-
* parent does not match the parent specified in MathboxContext.
|
|
7
|
-
*
|
|
8
|
-
* I believe this fundamentally this is happening because
|
|
9
|
-
* - we store parent value in context...
|
|
10
|
-
* - we update the context parent value using useEffect hooks..
|
|
11
|
-
* - useEffect hooks are called children before parents.
|
|
12
|
-
*
|
|
13
|
-
* One wonders whether we really need to be using useEffect hooks for the
|
|
14
|
-
* mathbox components, or if we can just put all the node creation/removal stuff
|
|
15
|
-
* in a render function. Hooks seem nice for dependencies, but mathbox is pretty
|
|
16
|
-
* smart about diffing out the actual changes.
|
|
17
|
-
*/
|
|
18
|
-
export declare const isSelectionParent: (selection: MathboxSelection, parent: MathboxSelection) => boolean;
|
package/scratch.js
DELETED
|
@@ -1,149 +0,0 @@
|
|
|
1
|
-
const classDescriptions = {
|
|
2
|
-
axis: ["draw", "Draw an axis", {}, { end: "true", zBias: "-1" }],
|
|
3
|
-
face: ["draw", "Draw polygon faces"],
|
|
4
|
-
grid: ["draw", "Draw a 2D line grid", {}, { width: "1", zBias: "-2" }],
|
|
5
|
-
line: ["draw", "Draw lines"],
|
|
6
|
-
point: ["draw", "Draw points"],
|
|
7
|
-
strip: ["draw", "Draw triangle strips"],
|
|
8
|
-
surface: ["draw", "Draw surfaces", {}, { lineX: "false", lineY: "false" }],
|
|
9
|
-
ticks: ["draw", "Draw ticks"],
|
|
10
|
-
vector: ["draw", "Draw vectors"],
|
|
11
|
-
|
|
12
|
-
view: ["view", "Adjust view range"],
|
|
13
|
-
cartesian: ["view", "Apply cartesian view"],
|
|
14
|
-
cartesian4: ["view", "Apply 4D cartesian view"],
|
|
15
|
-
polar: ["view", "Apply polar view"],
|
|
16
|
-
spherical: ["view", "Apply spherical view"],
|
|
17
|
-
stereographic: ["view", "Apply stereographic projection"],
|
|
18
|
-
stereographic4: ["view", "Apply 4D stereographic projection"],
|
|
19
|
-
|
|
20
|
-
transform: ["transform", "Transform geometry in 3D"],
|
|
21
|
-
transform4: ["transform", "Transform geometry in 4D"],
|
|
22
|
-
vertex: ["transform", "Apply custom vertex shader pass"],
|
|
23
|
-
fragment: ["transform", "Apply custom fragment shader pass"],
|
|
24
|
-
layer: ["transform", "Independent 2D layer/overlay"],
|
|
25
|
-
mask: ["transform", "Apply custom mask pass"],
|
|
26
|
-
|
|
27
|
-
array: [
|
|
28
|
-
"data",
|
|
29
|
-
"1D array",
|
|
30
|
-
{ expr: "function (emit, i, time, delta) { ... }" },
|
|
31
|
-
],
|
|
32
|
-
interval: [
|
|
33
|
-
"data",
|
|
34
|
-
"1D sampled array",
|
|
35
|
-
{ expr: "function (emit, x, i, time, delta) { ... }" },
|
|
36
|
-
],
|
|
37
|
-
matrix: [
|
|
38
|
-
"data",
|
|
39
|
-
"2D matrix",
|
|
40
|
-
{ expr: "function (emit, i, j, time, delta) { ... }" },
|
|
41
|
-
],
|
|
42
|
-
area: [
|
|
43
|
-
"data",
|
|
44
|
-
"2D sampled matrix",
|
|
45
|
-
{ expr: "function (emit, x, y, i, j, time, delta) { ... }" },
|
|
46
|
-
],
|
|
47
|
-
voxel: [
|
|
48
|
-
"data",
|
|
49
|
-
"3D voxels",
|
|
50
|
-
{ expr: "function (emit, i, j, k, time, delta) { ... }" },
|
|
51
|
-
],
|
|
52
|
-
volume: [
|
|
53
|
-
"data",
|
|
54
|
-
"3D sampled voxels",
|
|
55
|
-
{ expr: "function (emit, x, y, z, i, j, k, time, delta) { ... }" },
|
|
56
|
-
],
|
|
57
|
-
scale: ["data", "Human-friendly divisions on an axis, subdivided as needed"],
|
|
58
|
-
|
|
59
|
-
html: ["overlay", "HTML element source"],
|
|
60
|
-
dom: ["overlay", "HTML DOM injector"],
|
|
61
|
-
|
|
62
|
-
text: [
|
|
63
|
-
"text",
|
|
64
|
-
"GL text source",
|
|
65
|
-
{},
|
|
66
|
-
{ minFilter: '"linear"', magFilter: '"linear"' },
|
|
67
|
-
],
|
|
68
|
-
format: [
|
|
69
|
-
"text",
|
|
70
|
-
"Text formatter",
|
|
71
|
-
{ expr: "function (x, y, z, w, i, j, k, l, time, delta) { ... }" },
|
|
72
|
-
{ minFilter: '"linear"', magFilter: '"linear"' },
|
|
73
|
-
],
|
|
74
|
-
retext: ["text", "Text atlas resampler"],
|
|
75
|
-
label: ["text", "Draw GL labels"],
|
|
76
|
-
|
|
77
|
-
clamp: ["operator", "Clamp out-of-bounds samples to the nearest data point"],
|
|
78
|
-
grow: ["operator", "Scale data relative to reference data point"],
|
|
79
|
-
join: [
|
|
80
|
-
"operator",
|
|
81
|
-
"Join two array dimensions into one by concatenating rows/columns/stacks",
|
|
82
|
-
],
|
|
83
|
-
lerp: ["operator", "Linear interpolation of data"],
|
|
84
|
-
memo: ["operator", "Memoize data to an array/texture"],
|
|
85
|
-
readback: [
|
|
86
|
-
"operator",
|
|
87
|
-
"Read data back to a binary JavaScript array",
|
|
88
|
-
{ expr: "function (x, y, z, w, i, j, k, l) { ... }" },
|
|
89
|
-
],
|
|
90
|
-
resample: ["operator", "Resample data to new dimensions with a shader"],
|
|
91
|
-
repeat: ["operator", "Repeat data in one or more dimensions"],
|
|
92
|
-
swizzle: ["operator", "Swizzle data values"],
|
|
93
|
-
spread: ["operator", "Spread data values according to array indices"],
|
|
94
|
-
split: [
|
|
95
|
-
"operator",
|
|
96
|
-
"Split one array dimension into two by splitting rows/columns/etc",
|
|
97
|
-
],
|
|
98
|
-
slice: ["operator", "Select one or more rows/columns/stacks"],
|
|
99
|
-
subdivide: ["operator", "Subdivide data points evenly or with a bevel"],
|
|
100
|
-
transpose: ["operator", "Transpose array dimensions"],
|
|
101
|
-
|
|
102
|
-
group: ["base", "Group elements for visibility and activity"],
|
|
103
|
-
inherit: ["base", "Inherit and inject a trait from another element"],
|
|
104
|
-
root: ["base", "Tree root"],
|
|
105
|
-
unit: ["base", "Change unit sizing for drawing ops"],
|
|
106
|
-
|
|
107
|
-
shader: ["shader", "Custom shader snippet"],
|
|
108
|
-
|
|
109
|
-
camera: ["camera", "Camera instance or proxy"],
|
|
110
|
-
|
|
111
|
-
rtt: [
|
|
112
|
-
"rtt",
|
|
113
|
-
"Render objects to a texture",
|
|
114
|
-
{},
|
|
115
|
-
{ minFilter: '"linear"', magFilter: '"linear"', type: '"unsignedByte"' },
|
|
116
|
-
],
|
|
117
|
-
compose: [
|
|
118
|
-
"rtt",
|
|
119
|
-
"Full-screen render pass",
|
|
120
|
-
{},
|
|
121
|
-
{ zWrite: "false", zTest: "false", color: '"white"' },
|
|
122
|
-
],
|
|
123
|
-
|
|
124
|
-
clock: ["time", "Relative clock that starts from zero."],
|
|
125
|
-
now: ["time", "Absolute UNIX time in seconds since 01/01/1970"],
|
|
126
|
-
|
|
127
|
-
move: ["present", "Move elements in/out on transition"],
|
|
128
|
-
play: ["present", "Play a sequenced animation"],
|
|
129
|
-
present: ["present", "Present a tree of slides"],
|
|
130
|
-
reveal: ["present", "Reveal/hide elements on transition"],
|
|
131
|
-
slide: ["present", "Presentation slide"],
|
|
132
|
-
step: ["present", "Step through a sequenced animation"],
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
const capitalize = (s) => `${s[0].toUpperCase()}${s.slice(1)}`
|
|
136
|
-
|
|
137
|
-
const makeDef = (name) => {
|
|
138
|
-
const [group] = classDescriptions[name]
|
|
139
|
-
const Name = capitalize(name)
|
|
140
|
-
const dest = `https://gitgud.io/unconed/mathbox/-/blob/master/docs/primitives.md#${group}${name}`
|
|
141
|
-
const def = `
|
|
142
|
-
/**
|
|
143
|
-
* Component wrapper for mathbox [\`${name}\`](${dest}).
|
|
144
|
-
*/
|
|
145
|
-
export const ${Name} = mathboxComponentFactory('${name}');`
|
|
146
|
-
console.log(def)
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
Object.keys(classDescriptions).sort().forEach(makeDef)
|