Skip to content

Commit 445948a

Browse files
try html component for debugger
1 parent 5110c31 commit 445948a

File tree

5 files changed

+334
-1
lines changed

5 files changed

+334
-1
lines changed

src/core/abstractions/Decal/Item.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { onUnmounted, shallowRef, toRefs, watch } from 'vue'
33
import { MathUtils, Mesh } from 'three'
44
import { DecalGeometry } from 'three-stdlib'
55
import type { Decal, DecalAttributesItem, EnhancedTexture } from './types'
6+
import { Html } from '@tresjs/cientos'
67
78
const props = withDefaults(defineProps<DecalAttributesItem>(), {
89
properties: () => ({} as Decal),
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
<script setup lang="ts">
2+
import { useElementBounding, useMouse, useMouseInElement, useMousePressed } from '@vueuse/core'
3+
import type { UseMouseEventExtractor } from '@vueuse/core'
4+
import { ref, watch } from 'vue'
5+
6+
const testRef = ref<HTMLElement | null>(null)
7+
const { width, height, left, top } = useElementBounding(testRef)
8+
const { isOutside } = useMouseInElement(testRef)
9+
const { pressed: mouseIsPressed } = useMousePressed({ target: testRef, touch: false, drag: false })
10+
11+
const angle = ref(0)
12+
const resizerIsActive = ref(false)
13+
14+
const extractor: UseMouseEventExtractor = (event) => {
15+
if (event instanceof Touch) { return null }
16+
const centerX = width.value / 2
17+
const centerY = height.value / 2
18+
const offsetX = event.clientX - left.value - centerX
19+
const offsetY = event.clientY - top.value - centerY
20+
21+
return [offsetX, offsetY]
22+
}
23+
24+
const { x, y } = useMouse({ target: testRef, type: extractor })
25+
26+
watch([x, y], () => {
27+
const distance = Math.sqrt(x.value ** 2 + y.value ** 2)
28+
const radius = Math.min(width.value, height.value) / 2
29+
const distanceNormalized = distance / radius
30+
31+
resizerIsActive.value = distanceNormalized < 1.1 && distanceNormalized > 0.95
32+
33+
if (resizerIsActive.value) {
34+
const angleRad = Math.atan2(y.value, x.value)
35+
angle.value = angleRad + Math.PI
36+
}
37+
38+
if (mouseIsPressed.value && !resizerIsActive.value) {
39+
console.log('transformation')
40+
// testRef.value.style.transform = `translate(${x.value}px, ${y.value}px)`
41+
}
42+
43+
if (mouseIsPressed.value && resizerIsActive.value) {
44+
console.log('resize scale')
45+
}
46+
})
47+
</script>
48+
49+
<template>
50+
<div ref="testRef" class="test-controler__wrapper">
51+
<span class="border"></span>
52+
<span class="dot-center"></span>
53+
<div :class="{ hide: !resizerIsActive || isOutside }" class="bar" :style="`transform: rotate(${angle}rad) translateZ(0px)`">
54+
<span class="bar-inner"></span>
55+
</div>
56+
</div>
57+
</template>
58+
59+
<style scoped>
60+
.test-controler {
61+
position: fixed;
62+
top: 0;
63+
left: 0;
64+
width: 100vw;
65+
height: 100vh;
66+
z-index: 1000;
67+
pointer-events: none;
68+
}
69+
70+
.test-controler__wrapper {
71+
position: absolute;
72+
width: 450px;
73+
height: 450px;
74+
pointer-events: all;
75+
}
76+
77+
.dot-center {
78+
position: absolute;
79+
top: 50%;
80+
left: 50%;
81+
width: 10px;
82+
height: 10px;
83+
background-color: white;
84+
border-radius: 50%;
85+
transform: translate(-50%, -50%);
86+
}
87+
88+
.bar {
89+
position: absolute;
90+
top: 0;
91+
width: 100%;
92+
height: 100%;
93+
left: 0;
94+
cursor: ew-resize;
95+
}
96+
97+
.bar.hide {
98+
display: none;
99+
}
100+
101+
.bar-inner {
102+
position: absolute;
103+
top: 50%;
104+
left: 0%;
105+
width: 50px;
106+
height: 12px;
107+
border-radius: 5px;
108+
background-color: red;
109+
transform: translateX(-50%) rotate(90deg);
110+
}
111+
112+
.border {
113+
position: absolute;
114+
top: 0;
115+
left: 0;
116+
width: 100%;
117+
height: 100%;
118+
border-radius: 50%;
119+
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
120+
outline: 5px solid white;
121+
}
122+
</style>

src/core/abstractions/Decal/index.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import type { BoxHelper, Group, Intersection } from 'three'
66
import { Color, Euler, MathUtils, Mesh, SRGBColorSpace, Vector3 } from 'three'
77
import { DecalGeometry } from 'three-stdlib'
88
import { useRenderLoop, useTexture, useTresContext } from '@tresjs/core'
9-
import { Box } from '../../index'
9+
import { Box, Html } from '../../index'
1010
import Item from './Item.vue'
1111
import { parseTextureFilename, updateBoxHelper } from './utils'
1212
import { useControls } from '@tresjs/leches'
1313
import { useClipboard } from '@vueuse/core'
1414
import type { Decal, DecalAttributes, DecalElementProps, EnhancedTexture } from './types'
15+
import Resizer from './Resizer.vue'
1516
1617
const props = withDefaults(defineProps<DecalAttributes>(), {
1718
debug: false,
@@ -716,6 +717,10 @@ onUnmounted(() => {
716717
<TresMeshNormalMaterial />
717718
</Box>
718719

720+
<Html>
721+
<Resizer />
722+
</Html>
723+
719724
<TresGroup ref="boxHelpersRef">
720725
<TresBoxHelper
721726
v-if="debug"
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import { computed, ref } from 'vue'
2+
import { useControls } from '@tresjs/leches'
3+
4+
export function useDecalControls(textureMap, computedNodesDecal, onClearDecals, onDeleteCurrentDecal, onExportDecals) {
5+
const typeEdit = ref([
6+
{ text: 'scale', value: 'scale' },
7+
{ text: 'orientation', value: 'orientation' },
8+
{ text: 'position', value: 'position' },
9+
])
10+
11+
const {
12+
scaleControls,
13+
orientationZControls,
14+
keyTextureSelected,
15+
decalSelected,
16+
clearBtn,
17+
deleteBtn,
18+
typeEditControls,
19+
exportBtn,
20+
} = useControls({
21+
keyTextureSelected: {
22+
options: Object.keys(textureMap.value).map(key => ({
23+
text: key,
24+
value: key,
25+
})),
26+
value: Object.keys(textureMap.value)[0],
27+
},
28+
decalSelected: {
29+
options: computedNodesDecal.value,
30+
value: 'none',
31+
},
32+
typeEditControls: {
33+
label: 'Edit',
34+
options: typeEdit.value,
35+
value: typeEdit.value[0].value,
36+
visible: false,
37+
},
38+
scaleControls: {
39+
label: 'Scale',
40+
value: 1,
41+
visible: false,
42+
min: 0.001,
43+
max: 10,
44+
step: 0.001,
45+
},
46+
orientationZControls: {
47+
label: 'Orientation Z',
48+
visible: false,
49+
value: 0,
50+
min: -360,
51+
max: 360,
52+
step: 1,
53+
},
54+
deleteBtn: {
55+
label: 'Delete Decal',
56+
type: 'button',
57+
onClick: onDeleteCurrentDecal,
58+
visible: false,
59+
size: 'md',
60+
},
61+
exportBtn: {
62+
label: 'Export decals',
63+
type: 'button',
64+
onClick: onExportDecals,
65+
visible: false,
66+
size: 'md',
67+
},
68+
clearBtn: {
69+
label: 'Clear Decals',
70+
type: 'button',
71+
onClick: onClearDecals,
72+
size: 'md',
73+
},
74+
})
75+
76+
clearBtn.value.visible = false
77+
deleteBtn.value.visible = false
78+
exportBtn.value.visible = false
79+
80+
return {
81+
scaleControls,
82+
orientationZControls,
83+
keyTextureSelected,
84+
decalSelected,
85+
clearBtn,
86+
deleteBtn,
87+
typeEditControls,
88+
exportBtn,
89+
}
90+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/* eslint-disable no-console */
2+
3+
import { computed, nextTick, ref, shallowRef, toRaw } from 'vue'
4+
import { Euler, MathUtils, Vector3 } from 'three'
5+
import { useClipboard } from '@vueuse/core'
6+
import type { Decal, DecalAttributes, DecalElementProps, EnhancedTexture } from './types'
7+
8+
export function useDecals(textureMap, groupRef) {
9+
const nodesDecalRefs = ref<Decal[]>([])
10+
const decalItemsRef = ref<DecalElementProps[]>([])
11+
const { copy, isSupported } = useClipboard()
12+
13+
const computedNodesDecal = computed(() => [
14+
{ text: 'none', value: 'none' },
15+
...nodesDecalRefs.value.map((_, index) => ({
16+
text: `decal-${index}`,
17+
value: `decal-${index}`,
18+
})),
19+
])
20+
21+
const importDecals = async (decalsArray: any[]) => {
22+
if (!groupRef.value) { return }
23+
24+
for (const decalData of decalsArray) {
25+
const { position, normal, size, orientation, orientationZ, scale, uid, textureFilename } = decalData
26+
const selectedMap = textureMap.value[textureFilename]
27+
28+
if (!selectedMap) {
29+
console.warn(`Texture "${textureFilename}" introuvable dans textureMap.`)
30+
continue
31+
}
32+
33+
const recreatedDecal = {
34+
position: new Vector3(...position),
35+
orientation: new Euler(...orientation),
36+
orientationZ,
37+
size: new Vector3(...size),
38+
scale,
39+
normal: new Vector3(...normal),
40+
parent: groupRef.value?.parent as Group,
41+
map: selectedMap,
42+
uid,
43+
textureFilename,
44+
index: nodesDecalRefs.value.length,
45+
}
46+
47+
nodesDecalRefs.value.push(recreatedDecal)
48+
}
49+
50+
await nextTick()
51+
52+
// decalSelected.value.options = computedNodesDecal.value
53+
// decalSelected.value.value = 'none'
54+
}
55+
56+
const onClearDecals = async () => {
57+
nodesDecalRefs.value = []
58+
decalItemsRef.value = []
59+
await nextTick()
60+
console.log('✅ Decals have just been removed')
61+
}
62+
63+
const onDeleteCurrentDecal = async (selectedUid) => {
64+
const indexToDelete = nodesDecalRefs.value.findIndex(node => node.uid === selectedUid)
65+
if (indexToDelete === -1) {
66+
console.warn(`Decal with UID ${selectedUid} not found.`)
67+
return
68+
}
69+
nodesDecalRefs.value.splice(indexToDelete, 1)
70+
decalItemsRef.value.splice(indexToDelete, 1)
71+
await nextTick()
72+
console.log(`✅ ${selectedUid} just been removed`)
73+
}
74+
75+
const onExportDecals = async () => {
76+
const decalsArr = toRaw(nodesDecalRefs.value)
77+
const formattedDecals = decalsArr.map(item => ({
78+
position: item.position.toArray(),
79+
normal: item.normal.toArray(),
80+
size: item.size.toArray(),
81+
orientation: item.orientation.toArray().slice(0, 3),
82+
orientationZ: item.orientationZ,
83+
scale: item.scale,
84+
uid: item.uid,
85+
textureFilename: item.textureFilename,
86+
}))
87+
88+
const jsonString = JSON.stringify(formattedDecals, null, 2)
89+
90+
if (isSupported) {
91+
try {
92+
await copy(jsonString)
93+
console.log('✅ Data successfully copied to clipboard!')
94+
}
95+
catch (error) {
96+
console.error('Copy to clipboard fails:', error)
97+
}
98+
}
99+
else {
100+
console.error('Copying to the clipboard is not supported on this browser.')
101+
}
102+
103+
return jsonString
104+
}
105+
106+
return {
107+
nodesDecalRefs,
108+
decalItemsRef,
109+
computedNodesDecal,
110+
importDecals,
111+
onClearDecals,
112+
onDeleteCurrentDecal,
113+
onExportDecals,
114+
}
115+
}

0 commit comments

Comments
 (0)