1
0
Эх сурвалжийг харах

refactor!: 992 removal of emit from usetrescontextprovider composable (#999)

* added typecheck script

* added typecheck to ci

* ts error fixes

* fixed import

* moved render state stuff to useRenderer

* chore!: stripped unnecessarily returned elements from useRenderer

BREAKING CHANGE:

- useRenderer now returns invalidate and advance
- useTresContextProvider no longer contains render state

* chore: removed internal renderer ref

* refactor!: the renderer instance is now returned from useRenderer, made renderer being wrapped inside the context

BREAKING CHANGE:

- invalidate, advance, canBeInvalidated and the renderer instance are now accessed through the context via `renderer`
- the renderer instance in the context is now readonly

* refactor: removed one emit dependency

* tofo cleanup

* merge fix

* refactor: updated other parts to match structural changes

* worked around loop errors

* fixes concerning changes in playground

* updated english docs

* fix: wrong render mode in docs

* removed obsolete todo

* fix: added null check

* fix: removed deprecated toValue import

* feat: remove emit from useTresEventManager

* renamed type

* chore: got rid of emit concerning TresReady

* refactor!: removed emit from useTresContextProvider and useTresEventManager

BREAKING CHANGE:

- the type `EmitEventName` is no longer exported from @tresjs/core
- the type `EmitEventFn` is no longer exported from @tresjs/core

* chore: restored renderer tyope in LoopCallbackWithCtx

* refactor: renamed useRenderer

* fix: test

* cleanup

---------

Co-authored-by: Alvaro Saburido <alvaro.saburido@gmail.com>
Tino Koch 3 долоо хоног өмнө
parent
commit
090adf3077

+ 27 - 21
src/components/TresCanvas.vue

@@ -3,11 +3,12 @@ import type {
   ColorSpace,
   ShadowMapType,
   ToneMapping,
+  WebGLRenderer,
   WebGLRendererParameters,
 } from 'three'
 import type { App, Ref } from 'vue'
 import type { RendererPresetsType } from '../composables/useRenderer/const'
-import type { TresCamera, TresObject, TresScene } from '../types/'
+import type { TresCamera, TresObject, TresPointerEvent, TresScene } from '../types/'
 import { PerspectiveCamera, Scene } from 'three'
 import * as THREE from 'three'
 
@@ -33,7 +34,7 @@ import {
 import { extend } from '../core/catalogue'
 import { nodeOps } from '../core/nodeOps'
 
-import { disposeObject3D } from '../utils/'
+import { disposeObject3D, kebabToCamel } from '../utils/'
 import { registerTresDevtools } from '../devtools'
 
 export interface TresCanvasProps
@@ -73,24 +74,23 @@ const props = withDefaults(defineProps<TresCanvasProps>(), {
   enableProvideBridge: true,
 })
 
-// Define emits for Pointer events, pass `emit` into useTresEventManager so we can emit events off of TresCanvas
-// Not sure of this solution, but you have to have emits defined on the component to emit them in vue
-const emit = defineEmits([
-  'render',
-  'click',
-  'double-click',
-  'context-menu',
-  'pointer-move',
-  'pointer-up',
-  'pointer-down',
-  'pointer-enter',
-  'pointer-leave',
-  'pointer-over',
-  'pointer-out',
-  'pointer-missed',
-  'wheel',
-  'ready',
-])
+const emit = defineEmits<{
+  ready: [context: TresContext]
+  render: [renderer: WebGLRenderer]
+
+  click: [event: TresPointerEvent]
+  doubleClick: [event: TresPointerEvent]
+  contextMenu: [event: TresPointerEvent]
+  pointerMove: [event: TresPointerEvent]
+  pointerUp: [event: TresPointerEvent]
+  pointerDown: [event: TresPointerEvent]
+  pointerEnter: [event: TresPointerEvent]
+  pointerLeave: [event: TresPointerEvent]
+  pointerOver: [event: TresPointerEvent]
+  pointerOut: [event: TresPointerEvent]
+  pointerMissed: [event: TresPointerEvent]
+  wheel: [event: TresPointerEvent]
+}>()
 
 const slots = defineSlots<{
   default: () => any
@@ -189,7 +189,6 @@ onMounted(() => {
     canvas: existingCanvas,
     windowSize: props.windowSize ?? false,
     rendererOptions: props,
-    emit,
   })
 
   const { registerCamera, camera, cameras, deregisterCamera, renderer } = context.value
@@ -238,6 +237,13 @@ onMounted(() => {
     emit('render', renderer)
   })
 
+  context.value.eventManager?.onEvent(({ type, event, intersection }) => {
+    emit(
+      kebabToCamel(type) as any, // typescript doesn't know that kebabToCamel(type) is a valid key of PointerEmits
+      { type, event, intersection },
+    )
+  })
+
   // HMR support
   if (import.meta.hot && context.value) { import.meta.hot.on('vite:afterUpdate', () => handleHMR(context.value as TresContext)) }
 })

+ 0 - 1
src/composables/useLoader/component.vue

@@ -2,7 +2,6 @@
 import type { LoadingManager } from 'three'
 import type { LoaderProto } from './index'
 import { useLoader } from './index'
-import { defineEmits, defineProps } from 'vue'
 import { whenever } from '@vueuse/core'
 import type { TresObjectMap } from '../../utils/graph'
 

+ 8 - 5
src/composables/useTresContextProvider/index.ts

@@ -1,7 +1,7 @@
 import type { Camera } from 'three'
 import type { ComputedRef, DeepReadonly, MaybeRef, MaybeRefOrGetter, Ref, ShallowRef } from 'vue'
 import type { RendererLoop } from '../../core/loop'
-import type { EmitEventFn, TresControl, TresObject, TresScene } from '../../types'
+import type { TresControl, TresObject, TresScene } from '../../types'
 import type { UseRendererManagerReturn, UseRendererOptions } from '../useRenderer/useRendererManager'
 import { Raycaster } from 'three'
 import { inject, onUnmounted, provide, readonly, ref, shallowRef } from 'vue'
@@ -13,6 +13,7 @@ import { useRendererManager } from '../useRenderer/useRendererManager'
 import useSizes, { type SizesType } from '../useSizes'
 import { type TresEventManager, useTresEventManager } from '../useTresEventManager'
 import { useTresReady } from '../useTresReady'
+import { createEventHook, type EventHookOff } from '@vueuse/core'
 
 export interface PerformanceState {
   maxFrames: number
@@ -51,6 +52,7 @@ export interface TresContext {
   deregisterObjectAtPointerEventHandler?: (object: TresObject) => void
   registerBlockingObjectAtPointerEventHandler?: (object: TresObject) => void
   deregisterBlockingObjectAtPointerEventHandler?: (object: TresObject) => void
+  onReady: EventHookOff<TresContext> // TODO #980 consider removing this
 }
 
 export function useTresContextProvider({
@@ -58,13 +60,11 @@ export function useTresContextProvider({
   canvas,
   windowSize,
   rendererOptions,
-  emit,
 }: {
   scene: TresScene
   canvas: MaybeRef<HTMLCanvasElement>
   windowSize: MaybeRefOrGetter<boolean>
   rendererOptions: UseRendererOptions
-  emit: EmitEventFn
 }): TresContext {
   const localScene = shallowRef<TresScene>(scene)
   const sizes = useSizes(windowSize, canvas)
@@ -88,6 +88,8 @@ export function useTresContextProvider({
     },
   )
 
+  const readyEventHook = createEventHook<TresContext>() // TODO #980 consider removing this
+
   const ctx: TresContext = {
     sizes,
     scene: localScene,
@@ -113,6 +115,7 @@ export function useTresContextProvider({
     setCameraActive,
     deregisterCamera,
     loop,
+    onReady: readyEventHook.on,
   }
 
   provide('useTres', ctx)
@@ -128,9 +131,9 @@ export function useTresContextProvider({
   ctx.loop.start()
 
   onTresReady(() => {
-    emit('ready', ctx)
+    readyEventHook.trigger(ctx)
     ctx.loop.setReady(true)
-    useTresEventManager(scene, ctx, emit)
+    useTresEventManager(scene, ctx)
   })
 
   onUnmounted(() => {

+ 13 - 7
src/composables/useTresEventManager/index.ts

@@ -1,12 +1,15 @@
-import type { EmitEventFn, EmitEventName, Intersection, TresEvent, TresInstance, TresObject } from 'src/types'
+import type { Intersection, PointerEventType, TresEvent, TresInstance, TresObject, TresPointerEvent } from 'src/types'
 import type { Object3D, Object3DEventMap, Scene } from 'three'
 import type { TresContext } from '../useTresContextProvider'
 import { shallowRef } from 'vue'
 import { hyphenate } from '../../utils'
 import { useRaycaster } from '../useRaycaster'
 import { isObject3D, isTresObject } from '../../utils/is'
+import type { EventHookOff } from '@vueuse/core'
+import { createEventHook } from '@vueuse/core'
 
 export interface TresEventManager {
+  onEvent: EventHookOff<TresPointerEvent>
   /**
    * Forces the event system to refire events with the previous mouse event
    */
@@ -21,7 +24,6 @@ export interface TresEventManager {
   registerPointerMissedObject: (object: unknown) => void
   deregisterPointerMissedObject: (object: unknown) => void
 }
-
 function executeEventListeners(
   listeners: (event: TresEvent) => void | ((event: TresEvent) => void)[],
   event: TresEvent,
@@ -42,7 +44,6 @@ function executeEventListeners(
 export function useTresEventManager(
   scene: Scene,
   context: TresContext,
-  emit: EmitEventFn,
 ) {
   const _scene = shallowRef<Scene>()
   const _context = shallowRef<TresContext>()
@@ -55,6 +56,8 @@ export function useTresEventManager(
   // TODO: Optimize to not hit test on the whole scene
   const objectsWithEvents = shallowRef((_scene.value?.children as TresInstance[]).filter(hasChildrenWithEvents) || [])
 
+  const eventHook = createEventHook<TresPointerEvent>()
+
   /**
    * propogateEvent
    *
@@ -98,8 +101,9 @@ export function useTresEventManager(
       }
 
       // Convert eventName to kebab case and emit event from TresCanvas
-      const kebabEventName = hyphenate(eventName.slice(2)) as EmitEventName
-      emit(kebabEventName, { intersection, event })
+      const kebabEventName = hyphenate(eventName.slice(2)) as PointerEventType
+
+      eventHook.trigger({ type: kebabEventName, event, intersection })
     }
   }
 
@@ -178,8 +182,8 @@ export function useTresEventManager(
 
       executeEventListeners(object.onPointerMissed, event)
     })
-    // Emit pointer-missed from TresCanvas
-    emit('pointer-missed', { event })
+
+    eventHook.trigger({ type: 'pointer-missed', event })
   })
 
   function registerObject(maybeTresObject: unknown) {
@@ -214,6 +218,7 @@ export function useTresEventManager(
 
   // Attach methods to tres context
   context.eventManager = {
+    onEvent: eventHook.on,
     forceUpdate,
     registerObject,
     deregisterObject,
@@ -222,6 +227,7 @@ export function useTresEventManager(
   }
 
   return {
+    onEvent: eventHook.on,
     forceUpdate,
     registerObject,
     deregisterObject,

+ 4 - 2
src/types/index.ts

@@ -23,8 +23,10 @@ export interface TresCatalogue {
   [name: string]: ConstructorRepresentation
 }
 
-export type EmitEventName = 'render' | 'ready' | 'click' | 'double-click' | 'context-menu' | 'pointer-move' | 'pointer-up' | 'pointer-down' | 'pointer-enter' | 'pointer-leave' | 'pointer-over' | 'pointer-out' | 'pointer-missed' | 'wheel'
-export type EmitEventFn = (event: EmitEventName, ...args: any[]) => void
+export const pointerEventTypes = ['click', 'double-click', 'context-menu', 'pointer-move', 'pointer-up', 'pointer-down', 'pointer-enter', 'pointer-leave', 'pointer-over', 'pointer-out', 'pointer-missed', 'wheel'] as const
+export type PointerEventType = typeof pointerEventTypes[number]
+export interface TresPointerEvent { type: PointerEventType, event: TresEvent, intersection?: Intersection }
+
 export type TresCamera = THREE.OrthographicCamera | THREE.PerspectiveCamera
 
 /**