lunchboxjs 0.1.4018 → 0.2.1001-beta.2
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/dist/lunchboxjs.js +1739 -1670
- package/dist/lunchboxjs.min.js +1 -1
- package/dist/lunchboxjs.module.js +1694 -1667
- package/extras/OrbitControlsWrapper.vue +5 -7
- package/package.json +15 -4
- package/src/components/LunchboxEventHandlers.tsx +237 -0
- package/src/components/LunchboxWrapper/LunchboxScene.tsx +8 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.tsx +341 -0
- package/src/components/LunchboxWrapper/prepCanvas.ts +27 -21
- package/src/components/LunchboxWrapper/resizeCanvas.ts +13 -12
- package/src/components/autoGeneratedComponents.ts +1 -1
- package/src/components/index.ts +2 -4
- package/src/core/createNode.ts +2 -18
- package/src/core/extend.ts +1 -1
- package/src/core/index.ts +0 -3
- package/src/core/instantiateThreeObject/index.ts +7 -2
- package/src/core/instantiateThreeObject/processProps.ts +1 -1
- package/src/core/interaction.ts +55 -0
- package/src/core/minidom.ts +5 -9
- package/src/core/update.ts +92 -53
- package/src/core/updateObjectProp.ts +5 -14
- package/src/index.ts +270 -76
- package/src/keys.ts +25 -0
- package/src/nodeOps/createElement.ts +2 -5
- package/src/nodeOps/index.ts +70 -57
- package/src/nodeOps/insert.ts +11 -32
- package/src/nodeOps/remove.ts +1 -17
- package/src/types.ts +34 -10
- package/src/utils/index.ts +11 -4
- package/dist/.DS_Store +0 -0
- package/src/.DS_Store +0 -0
- package/src/components/LunchboxWrapper/LunchboxWrapper.ts +0 -312
- package/src/components/catalogue.ts +0 -3
- package/src/core/.DS_Store +0 -0
- package/src/core/allNodes.ts +0 -4
- package/src/core/ensure.ts +0 -203
- package/src/core/interaction/index.ts +0 -102
- package/src/core/interaction/input.ts +0 -4
- package/src/core/interaction/interactables.ts +0 -14
- package/src/core/interaction/setupAutoRaycaster.ts +0 -224
- package/src/core/start.ts +0 -11
package/src/core/ensure.ts
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
import { allNodes, createNode, isMinidomNode, MiniDom } from '.'
|
|
2
|
-
import { setupAutoRaycaster } from './interaction/setupAutoRaycaster'
|
|
3
|
-
import { computed, reactive, ref, WritableComputedRef } from 'vue'
|
|
4
|
-
import { Lunch } from '..'
|
|
5
|
-
|
|
6
|
-
// ENSURE ROOT
|
|
7
|
-
// ====================
|
|
8
|
-
export const rootUuid = 'LUNCHBOX_ROOT'
|
|
9
|
-
export let lunchboxRootNode: MiniDom.RendererRootNode
|
|
10
|
-
export function ensureRootNode(options: Partial<Lunch.RootMeta> = {}) {
|
|
11
|
-
if (!lunchboxRootNode) {
|
|
12
|
-
lunchboxRootNode = new MiniDom.RendererRootNode(options)
|
|
13
|
-
}
|
|
14
|
-
return lunchboxRootNode
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// This is used in `buildEnsured` below and `LunchboxWrapper`
|
|
18
|
-
/** Search the overrides record and the node tree for a node in the given types */
|
|
19
|
-
export function tryGetNodeWithInstanceType<T extends THREE.Object3D>(
|
|
20
|
-
pascalCaseTypes: string | string[]
|
|
21
|
-
) {
|
|
22
|
-
if (!Array.isArray(pascalCaseTypes)) {
|
|
23
|
-
pascalCaseTypes = [pascalCaseTypes]
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// default to override if we have one
|
|
27
|
-
for (let singleType of pascalCaseTypes) {
|
|
28
|
-
if (overrides[singleType]) return overrides[singleType] as Lunch.Node<T>
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// look for auto-created node
|
|
32
|
-
for (let singleType of pascalCaseTypes) {
|
|
33
|
-
const found =
|
|
34
|
-
autoCreated[singleType] ||
|
|
35
|
-
allNodes.find(
|
|
36
|
-
(node) =>
|
|
37
|
-
(node as MiniDom.RendererBaseNode).type?.toLowerCase() ===
|
|
38
|
-
singleType.toLowerCase()
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
// cancel if found example is marked !isDefault
|
|
42
|
-
if (
|
|
43
|
-
isMinidomNode(found) &&
|
|
44
|
-
(found.props['is-default'] === false ||
|
|
45
|
-
!found.props['isDefault'] === false)
|
|
46
|
-
) {
|
|
47
|
-
return null
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// if we have one, save and return
|
|
51
|
-
if (found) {
|
|
52
|
-
const createdAsNode = found as MiniDom.RendererStandardNode<T>
|
|
53
|
-
autoCreated[singleType] = createdAsNode
|
|
54
|
-
return createdAsNode
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return null
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// GENERIC ENSURE FUNCTION
|
|
62
|
-
// ====================
|
|
63
|
-
// Problem:
|
|
64
|
-
// I want to make sure an object of type Xyz exists in my Lunchbox app.
|
|
65
|
-
// If it doesn't exist, I want to create it and add it to the root node.
|
|
66
|
-
//
|
|
67
|
-
// Solution:
|
|
68
|
-
// export const ensuredXyz = buildEnsured<Xyz>('Xyz', 'FALLBACK_XYZ')
|
|
69
|
-
//
|
|
70
|
-
// Now in other components, you can do both:
|
|
71
|
-
// import { ensuredXyz }
|
|
72
|
-
// ensuredXyz.value (...)
|
|
73
|
-
// and:
|
|
74
|
-
// ensuredXyz.value = ...
|
|
75
|
-
export const autoCreated: Record<string, Lunch.Node | null> = reactive({})
|
|
76
|
-
export const overrides: Record<string, Lunch.Node | null> = reactive({})
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Build a computed ensured value with a getter and setter.
|
|
80
|
-
* @param pascalCaseTypes List of types this can be. Will autocreate first type if array provided.
|
|
81
|
-
* @param fallbackUuid Fallback UUID to use.
|
|
82
|
-
* @param props Props to pass to autocreated element
|
|
83
|
-
* @returns Computed getter/setter for ensured object.
|
|
84
|
-
*/
|
|
85
|
-
function buildEnsured<T extends THREE.Object3D>(
|
|
86
|
-
pascalCaseTypes: string | string[],
|
|
87
|
-
fallbackUuid: string,
|
|
88
|
-
props: Record<string, any> = {},
|
|
89
|
-
callback: ((node: MiniDom.RendererStandardNode<T>) => void) | null = null
|
|
90
|
-
) {
|
|
91
|
-
// make sure we've got an array
|
|
92
|
-
if (!Array.isArray(pascalCaseTypes)) {
|
|
93
|
-
pascalCaseTypes = [pascalCaseTypes]
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// add type for autoCreated and overrides
|
|
97
|
-
for (let singleType of pascalCaseTypes) {
|
|
98
|
-
if (!autoCreated[singleType]) {
|
|
99
|
-
autoCreated[singleType] = null
|
|
100
|
-
}
|
|
101
|
-
if (!overrides[singleType]) {
|
|
102
|
-
overrides[singleType] = null
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
return computed({
|
|
107
|
-
get(): MiniDom.RendererStandardNode<T> {
|
|
108
|
-
// try to get existing type
|
|
109
|
-
const existing = tryGetNodeWithInstanceType<T>(
|
|
110
|
-
pascalCaseTypes as string[]
|
|
111
|
-
)
|
|
112
|
-
if (existing) return existing
|
|
113
|
-
|
|
114
|
-
// otherwise, create a new node
|
|
115
|
-
const root = ensureRootNode()
|
|
116
|
-
const node = createNode<T>({
|
|
117
|
-
type: pascalCaseTypes[0],
|
|
118
|
-
uuid: fallbackUuid,
|
|
119
|
-
props,
|
|
120
|
-
})
|
|
121
|
-
root.addChild(node)
|
|
122
|
-
autoCreated[pascalCaseTypes[0]] = node
|
|
123
|
-
if (callback) {
|
|
124
|
-
callback(node)
|
|
125
|
-
}
|
|
126
|
-
return node
|
|
127
|
-
},
|
|
128
|
-
set(val: MiniDom.RendererStandardNode<T>) {
|
|
129
|
-
const t = val.type ?? ''
|
|
130
|
-
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
131
|
-
overrides[pascalType] = val
|
|
132
|
-
},
|
|
133
|
-
})
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ENSURE CAMERA
|
|
137
|
-
// ====================
|
|
138
|
-
export const fallbackCameraUuid = 'FALLBACK_CAMERA'
|
|
139
|
-
export const defaultCamera = buildEnsured(
|
|
140
|
-
['PerspectiveCamera', 'OrthographicCamera'],
|
|
141
|
-
fallbackCameraUuid,
|
|
142
|
-
{ args: [45, 0.5625, 1, 1000] }
|
|
143
|
-
) as unknown as WritableComputedRef<Lunch.Node<THREE.Camera>>
|
|
144
|
-
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
145
|
-
* Functions waiting for a Camera need to wait for this to be true. */
|
|
146
|
-
export const cameraReady = ref(false)
|
|
147
|
-
|
|
148
|
-
export const ensuredCamera = computed<Lunch.Node<THREE.Camera> | null>({
|
|
149
|
-
get() {
|
|
150
|
-
return (
|
|
151
|
-
cameraReady.value ? (defaultCamera.value as any) : (null as any)
|
|
152
|
-
) as any
|
|
153
|
-
},
|
|
154
|
-
set(val: any) {
|
|
155
|
-
const t = val.type ?? ''
|
|
156
|
-
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
157
|
-
overrides[pascalType] = val as any
|
|
158
|
-
},
|
|
159
|
-
})
|
|
160
|
-
|
|
161
|
-
// ENSURE RENDERER
|
|
162
|
-
// ====================
|
|
163
|
-
export const fallbackRendererUuid = 'FALLBACK_RENDERER'
|
|
164
|
-
export const ensuredRenderer = buildEnsured(
|
|
165
|
-
// TODO: ensure support for css/svg renderers
|
|
166
|
-
['WebGLRenderer'], //, 'CSS2DRenderer', 'CSS3DRenderer', 'SVGRenderer'],
|
|
167
|
-
fallbackRendererUuid,
|
|
168
|
-
{}
|
|
169
|
-
) as unknown as WritableComputedRef<Lunch.Node<THREE.WebGLRenderer>>
|
|
170
|
-
/** Special value to be changed ONLY in `LunchboxWrapper`.
|
|
171
|
-
* Functions waiting for a Renderer need to wait for this to be true. */
|
|
172
|
-
export const rendererReady = ref(false)
|
|
173
|
-
|
|
174
|
-
export const ensureRenderer = computed<Lunch.Node<THREE.WebGLRenderer> | null>({
|
|
175
|
-
get() {
|
|
176
|
-
return (
|
|
177
|
-
rendererReady.value ? (ensuredRenderer.value as any) : (null as any)
|
|
178
|
-
) as any
|
|
179
|
-
},
|
|
180
|
-
set(val: any) {
|
|
181
|
-
const t = val.type ?? ''
|
|
182
|
-
const pascalType = t[0].toUpperCase() + t.slice(1)
|
|
183
|
-
overrides[pascalType] = val as any
|
|
184
|
-
},
|
|
185
|
-
})
|
|
186
|
-
|
|
187
|
-
// ENSURE SCENE
|
|
188
|
-
// ====================
|
|
189
|
-
export const fallbackSceneUuid = 'FALLBACK_SCENE'
|
|
190
|
-
export const ensuredScene = buildEnsured<THREE.Scene>(
|
|
191
|
-
'Scene',
|
|
192
|
-
fallbackSceneUuid
|
|
193
|
-
)
|
|
194
|
-
|
|
195
|
-
// ENSURE AUTO-RAYCASTER
|
|
196
|
-
export const autoRaycasterUuid = 'AUTO_RAYCASTER'
|
|
197
|
-
// `unknown` is intentional here - we need to typecast the node since Raycaster isn't an Object3D
|
|
198
|
-
export const ensuredRaycaster = buildEnsured(
|
|
199
|
-
'Raycaster',
|
|
200
|
-
autoRaycasterUuid,
|
|
201
|
-
{},
|
|
202
|
-
(node) => setupAutoRaycaster(node as unknown as Lunch.Node<THREE.Raycaster>)
|
|
203
|
-
) as unknown as WritableComputedRef<Lunch.Node<THREE.Raycaster>>
|
|
@@ -1,102 +0,0 @@
|
|
|
1
|
-
import { watch } from 'vue'
|
|
2
|
-
import {
|
|
3
|
-
addInteractable,
|
|
4
|
-
interactables,
|
|
5
|
-
removeInteractable,
|
|
6
|
-
} from './interactables'
|
|
7
|
-
import { ensuredRaycaster } from '..'
|
|
8
|
-
import { inputActive } from './input'
|
|
9
|
-
import { currentIntersections } from '.'
|
|
10
|
-
import { Lunch } from '../..'
|
|
11
|
-
|
|
12
|
-
export * from './input'
|
|
13
|
-
export * from './interactables'
|
|
14
|
-
export * from './setupAutoRaycaster'
|
|
15
|
-
|
|
16
|
-
/** Add an event listener to the given node. Also creates the event teardown function and any necessary raycaster/interaction dictionary updates. */
|
|
17
|
-
export function addEventListener({
|
|
18
|
-
node,
|
|
19
|
-
key,
|
|
20
|
-
value,
|
|
21
|
-
}: {
|
|
22
|
-
node: Lunch.Node
|
|
23
|
-
key: Lunch.EventKey
|
|
24
|
-
value: Lunch.EventCallback
|
|
25
|
-
}) {
|
|
26
|
-
// create new records for this key if needed
|
|
27
|
-
if (!node.eventListeners[key]) {
|
|
28
|
-
node.eventListeners[key] = []
|
|
29
|
-
}
|
|
30
|
-
if (!node.eventListenerRemoveFunctions[key]) {
|
|
31
|
-
node.eventListenerRemoveFunctions[key] = []
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// add event listener
|
|
35
|
-
node.eventListeners[key].push(value)
|
|
36
|
-
|
|
37
|
-
// if we need it, let's get/create the main raycaster
|
|
38
|
-
if (interactionsRequiringRaycaster.includes(key)) {
|
|
39
|
-
// we're not using `v` here, we're just making sure the raycaster has been created
|
|
40
|
-
// TODO: is this necessary?
|
|
41
|
-
const v = ensuredRaycaster.value
|
|
42
|
-
|
|
43
|
-
if (node.instance && !interactables.includes(node)) {
|
|
44
|
-
addInteractable(node)
|
|
45
|
-
node.eventListenerRemoveFunctions[key].push(() =>
|
|
46
|
-
removeInteractable(node)
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// register click, pointerdown, pointerup
|
|
52
|
-
if (key === 'onClick' || key === 'onPointerDown' || key === 'onPointerUp') {
|
|
53
|
-
const stop = watch(
|
|
54
|
-
() => inputActive.value,
|
|
55
|
-
(isDown) => {
|
|
56
|
-
const idx = currentIntersections
|
|
57
|
-
.map((v) => v.element)
|
|
58
|
-
.findIndex(
|
|
59
|
-
(v) =>
|
|
60
|
-
v.instance &&
|
|
61
|
-
v.instance.uuid === node.instance?.uuid
|
|
62
|
-
)
|
|
63
|
-
if (idx !== -1) {
|
|
64
|
-
if (
|
|
65
|
-
isDown &&
|
|
66
|
-
(key === 'onClick' || key === 'onPointerDown')
|
|
67
|
-
) {
|
|
68
|
-
node.eventListeners[key].forEach((func) => {
|
|
69
|
-
func({
|
|
70
|
-
intersection:
|
|
71
|
-
currentIntersections[idx].intersection,
|
|
72
|
-
})
|
|
73
|
-
})
|
|
74
|
-
} else if (!isDown && key === 'onPointerUp') {
|
|
75
|
-
node.eventListeners[key].forEach((func) => {
|
|
76
|
-
func({
|
|
77
|
-
intersection:
|
|
78
|
-
currentIntersections[idx].intersection,
|
|
79
|
-
})
|
|
80
|
-
})
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
)
|
|
85
|
-
|
|
86
|
-
node.eventListenerRemoveFunctions[key].push(stop)
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return node
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
const interactionsRequiringRaycaster = [
|
|
93
|
-
'onClick',
|
|
94
|
-
'onPointerUp',
|
|
95
|
-
'onPointerDown',
|
|
96
|
-
'onPointerOver',
|
|
97
|
-
'onPointerOut',
|
|
98
|
-
'onPointerEnter',
|
|
99
|
-
'onPointerLeave',
|
|
100
|
-
'onPointerMove',
|
|
101
|
-
// 'onPointerMissed',
|
|
102
|
-
]
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { Lunch } from '../..'
|
|
2
|
-
|
|
3
|
-
export const interactables: Array<Lunch.Node> = []
|
|
4
|
-
|
|
5
|
-
export const addInteractable = (target: Lunch.Node) => {
|
|
6
|
-
interactables.push(target)
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export const removeInteractable = (target: Lunch.Node) => {
|
|
10
|
-
const idx = interactables.indexOf(target)
|
|
11
|
-
if (idx !== -1) {
|
|
12
|
-
interactables.splice(idx, 1)
|
|
13
|
-
}
|
|
14
|
-
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import { interactables } from '.'
|
|
2
|
-
import {
|
|
3
|
-
ensuredCamera,
|
|
4
|
-
ensuredRaycaster,
|
|
5
|
-
ensureRenderer,
|
|
6
|
-
onBeforeRender,
|
|
7
|
-
} from '..'
|
|
8
|
-
import { globals, Lunch } from '../../'
|
|
9
|
-
import { ref, watch, WatchStopHandle } from 'vue'
|
|
10
|
-
import { inputActive } from './input'
|
|
11
|
-
import { Intersection } from 'three'
|
|
12
|
-
|
|
13
|
-
let mouseMoveListener: (event: MouseEvent) => void
|
|
14
|
-
let mouseDownListener: (event: MouseEvent) => void
|
|
15
|
-
let mouseUpListener: (event: MouseEvent) => void
|
|
16
|
-
|
|
17
|
-
export const mousePos = ref({ x: Infinity, y: Infinity })
|
|
18
|
-
let autoRaycasterEventsInitialized = false
|
|
19
|
-
|
|
20
|
-
let frameID: number
|
|
21
|
-
|
|
22
|
-
export const setupAutoRaycaster = (node: Lunch.Node<THREE.Raycaster>) => {
|
|
23
|
-
const instance = node.instance
|
|
24
|
-
|
|
25
|
-
if (!instance) return
|
|
26
|
-
|
|
27
|
-
// add mouse events once renderer is ready
|
|
28
|
-
let stopWatcher: WatchStopHandle | null = null
|
|
29
|
-
stopWatcher = watch(
|
|
30
|
-
() => ensureRenderer.value,
|
|
31
|
-
(renderer) => {
|
|
32
|
-
// make sure renderer exists
|
|
33
|
-
if (!renderer?.instance) return
|
|
34
|
-
|
|
35
|
-
// cancel early if autoraycaster exists
|
|
36
|
-
if (autoRaycasterEventsInitialized) {
|
|
37
|
-
if (stopWatcher) stopWatcher()
|
|
38
|
-
return
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
// create mouse events
|
|
42
|
-
mouseMoveListener = (evt) => {
|
|
43
|
-
const screenWidth =
|
|
44
|
-
(renderer.instance!.domElement.width ?? 1) /
|
|
45
|
-
globals.dpr.value
|
|
46
|
-
const screenHeight =
|
|
47
|
-
(renderer.instance!.domElement.height ?? 1) /
|
|
48
|
-
globals.dpr.value
|
|
49
|
-
|
|
50
|
-
mousePos.value.x = (evt.offsetX / screenWidth) * 2 - 1
|
|
51
|
-
mousePos.value.y = -(evt.offsetY / screenHeight) * 2 + 1
|
|
52
|
-
}
|
|
53
|
-
mouseDownListener = () => (inputActive.value = true)
|
|
54
|
-
mouseUpListener = () => (inputActive.value = false)
|
|
55
|
-
|
|
56
|
-
// add mouse events
|
|
57
|
-
renderer.instance.domElement.addEventListener(
|
|
58
|
-
'mousemove',
|
|
59
|
-
mouseMoveListener
|
|
60
|
-
)
|
|
61
|
-
renderer.instance.domElement.addEventListener(
|
|
62
|
-
'mousedown',
|
|
63
|
-
mouseDownListener
|
|
64
|
-
)
|
|
65
|
-
renderer.instance.domElement.addEventListener(
|
|
66
|
-
'mouseup',
|
|
67
|
-
mouseUpListener
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
// TODO: add touch events
|
|
71
|
-
|
|
72
|
-
// process mouse events asynchronously, whenever the mouse state changes
|
|
73
|
-
watch(
|
|
74
|
-
() => [inputActive.value, mousePos.value.x, mousePos.value.y],
|
|
75
|
-
() => {
|
|
76
|
-
if (frameID) cancelAnimationFrame(frameID)
|
|
77
|
-
frameID = requestAnimationFrame(() => {
|
|
78
|
-
autoRaycasterBeforeRender()
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
// mark complete
|
|
84
|
-
autoRaycasterEventsInitialized = true
|
|
85
|
-
|
|
86
|
-
// cancel setup watcher
|
|
87
|
-
if (stopWatcher) {
|
|
88
|
-
stopWatcher()
|
|
89
|
-
}
|
|
90
|
-
},
|
|
91
|
-
{ immediate: true }
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// AUTO-RAYCASTER CALLBACK
|
|
96
|
-
// ====================
|
|
97
|
-
export let currentIntersections: Array<{
|
|
98
|
-
element: Lunch.Node
|
|
99
|
-
intersection: Intersection<THREE.Object3D>
|
|
100
|
-
}> = []
|
|
101
|
-
|
|
102
|
-
const autoRaycasterBeforeRender = () => {
|
|
103
|
-
// setup
|
|
104
|
-
const raycaster = ensuredRaycaster.value?.instance
|
|
105
|
-
const camera = ensuredCamera.value?.instance
|
|
106
|
-
if (!raycaster || !camera) return
|
|
107
|
-
|
|
108
|
-
raycaster.setFromCamera(globals.mousePos.value, camera)
|
|
109
|
-
const intersections = raycaster.intersectObjects(
|
|
110
|
-
interactables.map((v) => v.instance as any as THREE.Object3D)
|
|
111
|
-
)
|
|
112
|
-
|
|
113
|
-
let enterValues: Array<Intersection<THREE.Object3D>> = [],
|
|
114
|
-
sameValues: Array<Intersection<THREE.Object3D>> = [],
|
|
115
|
-
leaveValues: Array<Intersection<THREE.Object3D>> = [],
|
|
116
|
-
entering: Array<{
|
|
117
|
-
element: Lunch.Node
|
|
118
|
-
intersection: Intersection<THREE.Object3D>
|
|
119
|
-
}> = [],
|
|
120
|
-
staying: Array<{
|
|
121
|
-
element: Lunch.Node
|
|
122
|
-
intersection: Intersection<THREE.Object3D>
|
|
123
|
-
}> = []
|
|
124
|
-
|
|
125
|
-
// intersection arrays
|
|
126
|
-
leaveValues = currentIntersections.map((v) => v.intersection)
|
|
127
|
-
|
|
128
|
-
// element arrays
|
|
129
|
-
intersections?.forEach((intersection) => {
|
|
130
|
-
const currentIdx = currentIntersections.findIndex(
|
|
131
|
-
(v) => v.intersection.object === intersection.object
|
|
132
|
-
)
|
|
133
|
-
if (currentIdx === -1) {
|
|
134
|
-
// new intersection
|
|
135
|
-
enterValues.push(intersection)
|
|
136
|
-
|
|
137
|
-
const found = interactables.find(
|
|
138
|
-
(v) => v.instance?.uuid === intersection.object.uuid
|
|
139
|
-
)
|
|
140
|
-
if (found) {
|
|
141
|
-
entering.push({ element: found, intersection })
|
|
142
|
-
}
|
|
143
|
-
} else {
|
|
144
|
-
// existing intersection
|
|
145
|
-
sameValues.push(intersection)
|
|
146
|
-
|
|
147
|
-
const found = interactables.find(
|
|
148
|
-
(v) => v.instance?.uuid === intersection.object.uuid
|
|
149
|
-
)
|
|
150
|
-
if (found) {
|
|
151
|
-
staying.push({ element: found, intersection })
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
// this is a current intersection, so it won't be in our `leave` array
|
|
155
|
-
const leaveIdx = leaveValues.findIndex(
|
|
156
|
-
(v) => v.object.uuid === intersection.object.uuid
|
|
157
|
-
)
|
|
158
|
-
if (leaveIdx !== -1) {
|
|
159
|
-
leaveValues.splice(leaveIdx, 1)
|
|
160
|
-
}
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
const leaving: Array<{
|
|
164
|
-
element: Lunch.Node
|
|
165
|
-
intersection: Intersection<THREE.Object3D>
|
|
166
|
-
}> = leaveValues.map((intersection) => {
|
|
167
|
-
return {
|
|
168
|
-
element: interactables.find(
|
|
169
|
-
(interactable) =>
|
|
170
|
-
interactable.instance?.uuid === intersection.object.uuid
|
|
171
|
-
) as any as Lunch.Node,
|
|
172
|
-
intersection,
|
|
173
|
-
}
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
// new interactions
|
|
177
|
-
entering.forEach(({ element, intersection }) => {
|
|
178
|
-
fireEventsFromIntersections({
|
|
179
|
-
element,
|
|
180
|
-
eventKeys: ['onPointerEnter'],
|
|
181
|
-
intersection,
|
|
182
|
-
})
|
|
183
|
-
})
|
|
184
|
-
|
|
185
|
-
// unchanged interactions
|
|
186
|
-
staying.forEach(({ element, intersection }) => {
|
|
187
|
-
const eventKeys: Array<Lunch.EventKey> = [
|
|
188
|
-
'onPointerOver',
|
|
189
|
-
'onPointerMove',
|
|
190
|
-
]
|
|
191
|
-
fireEventsFromIntersections({ element, eventKeys, intersection })
|
|
192
|
-
})
|
|
193
|
-
|
|
194
|
-
// exited interactions
|
|
195
|
-
leaving.forEach(({ element, intersection }) => {
|
|
196
|
-
const eventKeys: Array<Lunch.EventKey> = [
|
|
197
|
-
'onPointerLeave',
|
|
198
|
-
'onPointerOut',
|
|
199
|
-
]
|
|
200
|
-
fireEventsFromIntersections({ element, eventKeys, intersection })
|
|
201
|
-
})
|
|
202
|
-
|
|
203
|
-
currentIntersections = ([] as any).concat(entering, staying)
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// utility function for firing multiple callbacks and multiple events on a Lunchbox.Element
|
|
207
|
-
const fireEventsFromIntersections = ({
|
|
208
|
-
element,
|
|
209
|
-
eventKeys,
|
|
210
|
-
intersection,
|
|
211
|
-
}: {
|
|
212
|
-
element: Lunch.Node
|
|
213
|
-
eventKeys: Array<Lunch.EventKey>
|
|
214
|
-
intersection: Intersection<THREE.Object3D>
|
|
215
|
-
}) => {
|
|
216
|
-
if (!element) return
|
|
217
|
-
eventKeys.forEach((eventKey) => {
|
|
218
|
-
if (element.eventListeners[eventKey]) {
|
|
219
|
-
element.eventListeners[eventKey].forEach((cb) => {
|
|
220
|
-
cb({ intersection })
|
|
221
|
-
})
|
|
222
|
-
}
|
|
223
|
-
})
|
|
224
|
-
}
|
package/src/core/start.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Lunch } from '..'
|
|
2
|
-
|
|
3
|
-
export const startCallbacks = [] as Lunch.UpdateCallback[]
|
|
4
|
-
|
|
5
|
-
export const onStart = (cb: Lunch.UpdateCallback, index = Infinity) => {
|
|
6
|
-
if (index === Infinity) {
|
|
7
|
-
startCallbacks.push(cb)
|
|
8
|
-
} else {
|
|
9
|
-
startCallbacks.splice(index, 0, cb)
|
|
10
|
-
}
|
|
11
|
-
}
|