Merge pull request 'debouncing' (#88) from bx-2376-new_type into dev
Reviewed-on: #88
This commit is contained in:
commit
01cb9440b2
|
@ -3,6 +3,9 @@ import { TresCanvas } from '@tresjs/core'
|
|||
import { Stats, OrbitControls } from '@tresjs/cientos'
|
||||
import { degToRad } from 'three/src/math/MathUtils.js';
|
||||
|
||||
const container = ref<HTMLElement | null>(null);
|
||||
const { isIntersecting, startObserver, stopObserver } = useSceneVisibility();
|
||||
|
||||
const controlsState = reactive({
|
||||
position: { x: 0, y: 0, z: 0 },
|
||||
enablePan: false,
|
||||
|
@ -17,9 +20,21 @@ const cameraStat = reactive({
|
|||
aspect: 1920 / 600,
|
||||
// fov: 40,
|
||||
})
|
||||
const renderMode = computed(() => (isIntersecting.value ? 'always' : 'manual'));
|
||||
|
||||
onMounted(async () => {
|
||||
if (container.value) {
|
||||
await nextTick()
|
||||
startObserver(container.value);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopObserver();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="calc">
|
||||
<div class="calc" ref="container">
|
||||
<ClientOnly fallback-tag="div">
|
||||
<template #fallback>
|
||||
<div class="fallback">
|
||||
|
@ -27,9 +42,12 @@ const cameraStat = reactive({
|
|||
</div>
|
||||
</template>
|
||||
<Loader />
|
||||
<Scene :canvasProps="{ clearColor: '#e2e8f0' }">
|
||||
<TresCanvas clear-color="#e2e8f0" :render-mode="renderMode" :key="renderMode">
|
||||
<TresPerspectiveCamera v-bind="cameraStat" ref="camera" />
|
||||
<OrbitControls v-bind="controlsState" make-default />
|
||||
<Suspense>
|
||||
<ModelEnv />
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<ModelSmoothCamera />
|
||||
</Suspense>
|
||||
|
@ -38,7 +56,7 @@ const cameraStat = reactive({
|
|||
<ModelParametric />
|
||||
</Suspense>
|
||||
</TresGroup>
|
||||
</Scene>
|
||||
</TresCanvas>
|
||||
</ClientOnly>
|
||||
</div>
|
||||
</template>
|
|
@ -3,6 +3,9 @@ import { TresCanvas } from '@tresjs/core'
|
|||
import { OrbitControls } from '@tresjs/cientos'
|
||||
import { Vector3 } from 'three';
|
||||
|
||||
const container = ref<HTMLElement | null>(null);
|
||||
const { isIntersecting, startObserver, stopObserver } = useSceneVisibility();
|
||||
|
||||
const camera = ref()
|
||||
const controls = ref()
|
||||
const controlsState = reactive({
|
||||
|
@ -25,36 +28,56 @@ const changeDistance = (v = 1) => {
|
|||
camera.value.position.normalize().multiplyScalar(r)
|
||||
}
|
||||
}
|
||||
|
||||
const renderMode = computed(() => (isIntersecting.value ? 'always' : 'manual'));
|
||||
|
||||
onMounted(async () => {
|
||||
if (container.value) {
|
||||
await nextTick()
|
||||
startObserver(container.value);
|
||||
}
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
stopObserver();
|
||||
});
|
||||
</script>
|
||||
<template>
|
||||
<div class="h-96 relative">
|
||||
<ClientOnly fallback-tag="div">
|
||||
<template #fallback>
|
||||
<div class="fallback">
|
||||
Загрузка 3D модели
|
||||
</div>
|
||||
</template>
|
||||
<Scene :canvasProps="{ height: '600' }">
|
||||
<TresPerspectiveCamera :position="[-7, 2, 4]" ref="camera" />
|
||||
<OrbitControls v-bind="controlsState" ref="controls" make-default />
|
||||
<ModelDiagram />
|
||||
</Scene>
|
||||
</ClientOnly>
|
||||
<div class="canvas-icons">
|
||||
<a href="#" @click.prevent="toggleExpState">
|
||||
<Icon name="mdi:arrow-collapse-horizontal" v-if="explosion_state" />
|
||||
<Icon name="mdi:arrow-expand-horizontal" v-else />
|
||||
</a>
|
||||
<a href="#" @click.prevent="changeDistance(-0.5)"
|
||||
:class="[{ 'disabled': camera ? (camera.position.distanceTo(new Vector3(0, 0, 0)) <= controlsState.minDistance) : null }]">
|
||||
<Icon name="mdi:plus-circle-outline" />
|
||||
</a>
|
||||
<a href="#" @click.prevent="changeDistance(0.5)"
|
||||
:class="[{ 'disabled': camera ? (camera.position.distanceTo(new Vector3(0, 0, 0)) >= (controlsState.maxDistance)) : null }]">
|
||||
<Icon name="mdi:minus-circle-outline" />
|
||||
</a>
|
||||
<Suspense>
|
||||
<div ref="container" class="h-96 relative">
|
||||
<ClientOnly fallback-tag="div">
|
||||
<template #fallback>
|
||||
<div class="fallback">
|
||||
Загрузка 3D модели
|
||||
</div>
|
||||
</template>
|
||||
<TresCanvas height="600" :render-mode="renderMode" :key="renderMode">
|
||||
<TresPerspectiveCamera :position="[-7, 2, 4]" ref="camera" />
|
||||
<OrbitControls v-bind="controlsState" ref="controls" make-default />
|
||||
<Suspense>
|
||||
<ModelEnv />
|
||||
</Suspense>
|
||||
<Suspense>
|
||||
<ModelDiagram />
|
||||
</Suspense>
|
||||
</TresCanvas>
|
||||
</ClientOnly>
|
||||
<div class="canvas-icons">
|
||||
<a href="#" @click.prevent="toggleExpState">
|
||||
<Icon name="mdi:arrow-collapse-horizontal" v-if="explosion_state" />
|
||||
<Icon name="mdi:arrow-expand-horizontal" v-else />
|
||||
</a>
|
||||
<a href="#" @click.prevent="changeDistance(-0.5)"
|
||||
:class="[{ 'disabled': camera ? (camera.position.distanceTo(new Vector3(0, 0, 0)) <= controlsState.minDistance) : null }]">
|
||||
<Icon name="mdi:plus-circle-outline" />
|
||||
</a>
|
||||
<a href="#" @click.prevent="changeDistance(0.5)"
|
||||
:class="[{ 'disabled': camera ? (camera.position.distanceTo(new Vector3(0, 0, 0)) >= (controlsState.maxDistance)) : null }]">
|
||||
<Icon name="mdi:minus-circle-outline" />
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Suspense>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
import { GainMapLoader, } from '@monogrid/gainmap-js'
|
||||
import { useLoop } from '@tresjs/core';
|
||||
const { scene, renderer, camera } = useTresContext()
|
||||
const {onBeforeRender} = useLoop()
|
||||
const { onBeforeRender } = useLoop()
|
||||
|
||||
renderer.value.toneMapping = CineonToneMapping
|
||||
renderer.value.toneMappingExposure = 1
|
||||
|
@ -18,6 +18,7 @@ renderer.value.shadowMap.type = PCFSoftShadowMap
|
|||
|
||||
const pmremGenerator = new PMREMGenerator(renderer.value);
|
||||
pmremGenerator.compileEquirectangularShader();
|
||||
|
||||
onMounted(async () => {
|
||||
const loader = new GainMapLoader(renderer.value)
|
||||
const result = await loader.loadAsync([
|
||||
|
@ -35,14 +36,15 @@ onMounted(async () => {
|
|||
scene.value.environmentIntensity = 1.25
|
||||
scene.value.environmentRotation.z = 0.25
|
||||
result.renderTarget.texture.dispose();
|
||||
})
|
||||
onBeforeRender(()=>{
|
||||
if(camera.value) {
|
||||
const cameraDirection = new Vector3()
|
||||
camera.value.getWorldDirection(cameraDirection);
|
||||
const angle = Math.atan2(cameraDirection.z, cameraDirection.x);
|
||||
scene.value.environmentRotation.z = angle + 0.25
|
||||
}
|
||||
|
||||
onBeforeRender(() => {
|
||||
if (camera.value) {
|
||||
const cameraDirection = new Vector3()
|
||||
camera.value.getWorldDirection(cameraDirection);
|
||||
const angle = Math.atan2(cameraDirection.z, cameraDirection.x);
|
||||
scene.value.environmentRotation.z = angle + 0.25
|
||||
}
|
||||
})
|
||||
})
|
||||
</script>
|
||||
<template></template>
|
|
@ -0,0 +1,57 @@
|
|||
// useSceneVisibility.ts
|
||||
import { ref, onMounted, onBeforeUnmount } from 'vue';
|
||||
|
||||
export function useSceneVisibility() {
|
||||
const isIntersecting = ref(false); // Состояние видимости
|
||||
let observer: IntersectionObserver | null = null;
|
||||
let debounceTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
|
||||
const startObserver = (element: HTMLElement) => {
|
||||
observer = new IntersectionObserver(
|
||||
(entries) => {
|
||||
entries.forEach((entry) => {
|
||||
if (debounceTimeout) {
|
||||
clearTimeout(debounceTimeout); // Очищаем предыдущий таймер
|
||||
}
|
||||
|
||||
// Устанавливаем новый таймер
|
||||
debounceTimeout = setTimeout(() => {
|
||||
isIntersecting.value = entry.isIntersecting;
|
||||
}, 100); // Задержка в 300 мс
|
||||
});
|
||||
},
|
||||
{ threshold: 0.05 } // Порог видимости
|
||||
);
|
||||
|
||||
if (element) {
|
||||
observer.observe(element);
|
||||
}
|
||||
};
|
||||
|
||||
const stopObserver = () => {
|
||||
if (observer) {
|
||||
observer.disconnect();
|
||||
observer = null;
|
||||
}
|
||||
|
||||
if (debounceTimeout) {
|
||||
clearTimeout(debounceTimeout); // Очищаем таймер при остановке наблюдателя
|
||||
debounceTimeout = null;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
// Инициализация наблюдателя при монтировании
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
// Очистка наблюдателя при размонтировании
|
||||
stopObserver();
|
||||
});
|
||||
|
||||
return {
|
||||
isIntersecting,
|
||||
startObserver,
|
||||
stopObserver,
|
||||
};
|
||||
}
|
|
@ -51,9 +51,9 @@ export default defineNuxtConfig({
|
|||
vite: {
|
||||
assetsInclude: ['**/*.glb', '**/*.gltf'],
|
||||
build: {
|
||||
target: 'esnext'
|
||||
target: 'esnext',
|
||||
// minify: 'esbuild'
|
||||
// minify: false
|
||||
minify: false,
|
||||
},
|
||||
},
|
||||
robots: {
|
||||
|
|
|
@ -133,7 +133,9 @@ watch(openTab, () => {
|
|||
</div>
|
||||
<div class="container gap-4">
|
||||
<div class="col-span-full xl:col-span-8">
|
||||
<ExpDiagram />
|
||||
<Suspense>
|
||||
<ExpDiagram />
|
||||
</Suspense>
|
||||
</div>
|
||||
<div class="col-span-full xl:col-span-4 prose">
|
||||
<span v-html="advantagesText"></span>
|
||||
|
|
Loading…
Reference in New Issue