Skip to content

Commit a661ce0

Browse files
fix(cientos): correct click event handling during testing phase
1 parent fe39293 commit a661ce0

4 files changed

Lines changed: 141 additions & 139 deletions

File tree

‎packages/cientos/playground/vue/src/pages/abstractions/DecalDemo.vue‎

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,13 @@
11
<script setup lang="ts">
22
import { TresCanvas } from '@tresjs/core'
33
import { Box, Decal,DecalDebugUI, OrbitControls } from '@tresjs/cientos'
4-
import { TresLeches, useControls } from '@tresjs/leches'
54
import { useTexture, useTextures } from '@tresjs/cientos'
6-
import { DirectionalLight, SRGBColorSpace } from 'three'
5+
import { SRGBColorSpace } from 'three'
76
87
const gl = {
98
clearColor: '#F6B03B',
109
}
1110
12-
const { enabled, edgeColor, edgeThreshold } = useControls({
13-
enabled: { value: true, type: 'boolean', label: 'Enabled' },
14-
edgeColor: { value: '#292929', type: 'color', label: 'Color' },
15-
edgeThreshold: {
16-
label: 'Threshold Angle',
17-
value: 15,
18-
min: 1,
19-
max: 100,
20-
step: 1,
21-
},
22-
})
23-
2411
const { state: texture } = useTexture('/decal/tresjs-dark.png')
2512
2613
const texturePaths = [
@@ -91,7 +78,6 @@ watch(textures, (val) => {
9178
</script>
9279

9380
<template>
94-
<TresLeches />
9581
<DecalDebugUI />
9682

9783

@@ -114,7 +100,7 @@ watch(textures, (val) => {
114100

115101
<TresMesh :scale="2" :position-x="0">
116102
<TresBoxGeometry />
117-
<TresMeshBasicMaterial color="#f6f6f6" wireframe />
103+
<TresMeshBasicMaterial color="#f6f6f6" />
118104

119105

120106
<!-- <Decal :map="texture" debug /> -->

‎packages/cientos/src/core/abstractions/Decal/DebugUI.vue‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -335,9 +335,9 @@ onBeforeUnmount(stop)
335335
.cientos-decal-debug-ui__inner:hover {
336336
cursor: grab;
337337
338-
.cientos-decal-debug-ui__dot-center {
338+
/* .cientos-decal-debug-ui__dot-center {
339339
transform: translate(-50%, -50%) scale(1);
340-
}
340+
} */
341341
}
342342
343343
.cientos-decal-debug-ui__border {
@@ -355,11 +355,11 @@ onBeforeUnmount(stop)
355355
position: absolute;
356356
left: 50%;
357357
top: 50%;
358-
transform: translate(-50%, -50%) scale(0);
358+
transform: translate(-50%, -50%) scale(1);
359359
width: 10px;
360360
height: auto;
361361
aspect-ratio: 1 / 1;
362-
background: red;
362+
background: white;
363363
border-radius: 50%;
364364
box-shadow: 0 0 6px #000000e6;
365365
transition: transform 0.3s ease;

‎packages/cientos/src/core/abstractions/Decal/DecalItem.vue‎

Lines changed: 105 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
<script setup lang="ts">
2-
import { computed, nextTick, onBeforeUnmount, ref, shallowRef, toRaw, toRefs, watch } from 'vue'
2+
import { computed, nextTick, onBeforeUnmount, ref, shallowRef, toRefs, watch } from 'vue'
33
import { DecalGeometry } from 'three-stdlib'
4-
import { Mesh, MeshBasicMaterial, Vector3 } from 'three'
5-
import { useLoop } from '@tresjs/core'
4+
import {
5+
EdgesGeometry,
6+
LineBasicMaterial,
7+
LineSegments,
8+
Mesh,
9+
Vector3,
10+
} from 'three'
611
import { decalBus } from './DecalBus'
12+
// 1. On réimporte useLoop pour l'animation
13+
import { dispose, useLoop } from '@tresjs/core'
714
815
const props = defineProps<{
916
parent: Mesh
@@ -14,59 +21,101 @@ const props = defineProps<{
1421
isSelected: boolean
1522
}>()
1623
17-
const emit = defineEmits(['select'])
18-
19-
let localElapsed = 0
20-
const wasSelected = ref(false)
24+
const emit = defineEmits(['select', 'hover'])
2125
2226
const { parent, decal, map, isSelected, highlight } = toRefs(props)
2327
2428
const meshRef = ref<Mesh | null>(null)
25-
const raycastMesh = ref<Mesh | null>(null)
26-
const boxHelper = shallowRef(null)
2729
const isHovered = ref(false)
2830
31+
const helperLineRef = shallowRef<LineSegments | null>(null)
32+
2933
const originalScale = new Mesh().scale.clone()
3034
31-
// watch(() => [meshRef.value, parent.value], () => {
32-
// const p = toRaw(parent.value)
33-
// const m = toRaw(meshRef.value)
34-
35-
// // Si on a le parent et le mesh du sticker
36-
// if (p && m) {
37-
// // On force l'attachement parent-enfant natif de Three.js
38-
// // Cela corrige instantanément la position et l'échelle
39-
// p.attach(m)
40-
// }
41-
// }, { immediate: true })
42-
43-
const updateRaycastClone = () => {
44-
if (!props.groupTest || !meshRef.value) { return }
45-
46-
if (!raycastMesh.value) {
47-
raycastMesh.value = new Mesh(
48-
meshRef.value.geometry,
49-
new MeshBasicMaterial({ visible: false }),
50-
)
51-
52-
raycastMesh.value.name = `raycast-decal-${decal.value.id}`
53-
raycastMesh.value.userData = {
54-
id: decal.value.id,
55-
originalUuid: decal.value.uuid,
35+
// --- GESTION DE LA MÉMOIRE AVEC DISPOSE() ---
36+
37+
const clearHelper = () => {
38+
if (helperLineRef.value) {
39+
if (meshRef.value) {
40+
meshRef.value.remove(helperLineRef.value)
5641
}
42+
dispose(helperLineRef.value)
43+
helperLineRef.value = null
44+
}
45+
}
46+
47+
// --- CRÉATION OBJETS ---
48+
49+
const createHelper = () => {
50+
if (!meshRef.value || !meshRef.value.geometry) { return }
51+
52+
clearHelper()
53+
54+
const edgesGeometry = new EdgesGeometry(meshRef.value.geometry)
55+
56+
// 2. On active la transparence pour permettre l'animation d'opacité
57+
const lineMaterial = new LineBasicMaterial({
58+
color: 0x0000FF, // Reste toujours BLEU
59+
depthTest: false,
60+
linewidth: 2,
61+
transparent: true, // Important pour le clignotement
62+
opacity: 1,
63+
})
64+
65+
const line = new LineSegments(edgesGeometry, lineMaterial)
66+
67+
line.raycast = () => {}
68+
69+
meshRef.value.add(line)
70+
helperLineRef.value = line
71+
72+
updateHelperVisuals()
73+
}
5774
58-
props.groupTest.add(raycastMesh.value)
75+
const updateHelperVisuals = () => {
76+
if (!helperLineRef.value) { return }
77+
78+
// Gère uniquement la visibilité globale (on/off)
79+
const visible = isHovered.value || isSelected.value
80+
helperLineRef.value.visible = visible
81+
82+
// J'ai supprimé le changement de couleur ici, cela reste bleu (défini dans createHelper)
83+
}
84+
85+
// --- ANIMATION (CLIGNOTEMENT) ---
86+
87+
const { onBeforeRender } = useLoop()
88+
89+
onBeforeRender(({ elapsed }) => {
90+
// Si le helper n'existe pas ou n'est pas visible, on ne fait rien
91+
if (!helperLineRef.value || !helperLineRef.value.visible) { return }
92+
93+
const material = helperLineRef.value.material as LineBasicMaterial
94+
95+
if (isSelected.value) {
96+
// 3. Calcul du clignotement (Sinusoidale)
97+
// elapsed * 10 contrôle la vitesse
98+
const t = (Math.sin(elapsed * 10) + 1) / 2
99+
// Opacité oscille entre 0.2 et 1
100+
material.opacity = 0.2 + t * 0.8
59101
}
60102
else {
61-
raycastMesh.value.geometry = meshRef.value.geometry
103+
// Si juste survolé (pas sélectionné), opacité fixe à 1
104+
if (material.opacity !== 1) { material.opacity = 1 }
62105
}
63-
}
106+
})
107+
108+
// --- LOGIQUE GEOMETRIE (Inchangée) ---
64109
65110
const buildGeometry = () => {
66111
if (!meshRef.value || !parent.value) { return }
67112
68113
parent.value.updateMatrixWorld(true)
69114
115+
if (meshRef.value.geometry) {
116+
meshRef.value.geometry.dispose()
117+
}
118+
70119
const geometry = new DecalGeometry(
71120
parent.value,
72121
decal.value.position,
@@ -75,7 +124,6 @@ const buildGeometry = () => {
75124
)
76125
77126
const inverseMatrix = parent.value.matrixWorld.clone().invert()
78-
79127
geometry.applyMatrix4(inverseMatrix)
80128
81129
const worldNormal = new Vector3(0, 0, 1).applyEuler(decal.value.orientation)
@@ -84,7 +132,7 @@ const buildGeometry = () => {
84132
const baseOffset = 0.01
85133
const layerGap = 0.001
86134
const currentZ = decal.value.zIndex ?? 0
87-
const parentScale = parent.value.scale.x || 1 // Approximation uniforme
135+
const parentScale = parent.value.scale.x || 1
88136
const totalOffset = (baseOffset + currentZ * layerGap) / parentScale
89137
90138
geometry.translate(
@@ -93,75 +141,24 @@ const buildGeometry = () => {
93141
localNormal.z * totalOffset,
94142
)
95143
96-
if (meshRef.value.geometry) { meshRef.value.geometry.dispose() }
97144
meshRef.value.geometry = geometry
98145
146+
createHelper()
147+
99148
meshRef.value.position.set(0, 0, 0)
100149
meshRef.value.rotation.set(0, 0, 0)
101150
meshRef.value.scale.set(1, 1, 1)
102151
meshRef.value.renderOrder = decal.value.zIndex ?? 0
103-
104-
updateRaycastClone()
105152
}
106153
107154
watch(() => decal.value.zIndex, () => {
108155
buildGeometry()
109156
})
110157
111-
watch(isSelected, (selected) => {
112-
if (!meshRef.value) { return }
113-
const material = meshRef.value.material as any
114-
115-
if (!selected) {
116-
material.opacity = 1
117-
material.needsUpdate = true
118-
}
119-
})
120-
121-
watch(isSelected, (selected) => {
158+
watch([isSelected, isHovered], () => {
159+
updateHelperVisuals()
122160
if (!meshRef.value) { return }
123-
if (!selected) { meshRef.value.scale.copy(originalScale) }
124-
})
125-
126-
const { onBeforeRender } = useLoop()
127-
128-
onBeforeRender(({ delta }) => {
129-
if (raycastMesh.value && parent.value) {
130-
parent.value.updateMatrixWorld()
131-
132-
parent.value.matrixWorld.decompose(
133-
raycastMesh.value.position,
134-
raycastMesh.value.quaternion,
135-
raycastMesh.value.scale,
136-
)
137-
138-
raycastMesh.value.updateMatrixWorld()
139-
}
140-
141-
if (!meshRef.value) { return }
142-
const material = meshRef.value.material as any
143-
144-
if (isSelected.value && !wasSelected.value) {
145-
localElapsed = 0
146-
wasSelected.value = true
147-
}
148-
149-
if (!isSelected.value && wasSelected.value) {
150-
localElapsed = 0
151-
wasSelected.value = false
152-
}
153-
154-
localElapsed += delta
155-
156-
if (isSelected.value || isHovered.value) {
157-
const speed = 5
158-
const minO = 0.2
159-
const maxO = 1
160-
const t = (Math.sin(localElapsed * speed) + 1) / 2
161-
const opacity = minO + t * (maxO - minO)
162-
material.opacity = opacity
163-
material.needsUpdate = true
164-
}
161+
if (!isSelected.value) { meshRef.value.scale.copy(originalScale) }
165162
})
166163
167164
watch(
@@ -174,15 +171,13 @@ watch(
174171
175172
watch([meshRef, () => props.groupTest], () => {
176173
if (!meshRef.value || !props.groupTest) { return }
177-
178174
buildGeometry()
179175
originalScale.copy(meshRef.value.scale)
180176
}, { immediate: true })
181177
182178
const stop = decalBus.on((payload) => {
183179
if (payload.type === 'refresh-raycasts') {
184180
buildGeometry()
185-
updateRaycastClone()
186181
}
187182
})
188183
@@ -203,24 +198,28 @@ const onClickMesh = (event: MouseEvent) => {
203198
}
204199
205200
const onPointerEnter = (event: PointerEvent) => {
206-
console.log('pointer enter decal item')
207-
event.stopPropagation()
201+
event.stopPropagation() // Empêche le raycaster de traverser vers le parent
208202
isHovered.value = true
203+
document.body.style.cursor = 'pointer'
204+
205+
// PRÉVENIR LE PARENT
206+
emit('hover', true)
209207
}
210208
211209
const onPointerLeave = (event: PointerEvent) => {
212-
console.log('pointer leave decal item')
210+
// event.stopPropagation() // Pas nécessaire ici
213211
isHovered.value = false
212+
document.body.style.cursor = 'auto'
213+
214+
// PRÉVENIR LE PARENT
215+
emit('hover', false)
214216
}
215217
216218
onBeforeUnmount(() => {
217-
if (raycastMesh.value && props.groupTest) {
218-
props.groupTest.remove(raycastMesh.value)
219-
220-
if (raycastMesh.value.geometry) { raycastMesh.value.geometry.dispose() }
221-
if (raycastMesh.value.material) { (raycastMesh.value.material as any).dispose() }
219+
clearHelper()
222220
223-
raycastMesh.value = null
221+
if (meshRef.value && meshRef.value.geometry) {
222+
meshRef.value.geometry.dispose()
224223
}
225224
226225
stop()
@@ -239,7 +238,6 @@ defineExpose({ meshRef })
239238
:material-polygonOffsetFactor="-(10 + (decal.zIndex ?? 0))"
240239
:material-depthTest="true"
241240
:material-map="map"
242-
:material-opacity="isSelected ? 0.5 : 1"
243241
@click="onClickMesh"
244242
@pointerenter="onPointerEnter"
245243
@pointerleave="onPointerLeave"

0 commit comments

Comments
 (0)