/
counterbugtech
/
KontrBugCAD
Обзор
Документация
Войти
/
counterbugtech
/
KontrBugCAD
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
js/managers/CameraManager.js
1 строка
8 KB
counterbugtech
Обновление до 0.9.44
28 май 2026, 06:20
Верифицирован
28 май 2026, 06:20
cef7548
Код
Авторство
О чём код?
import*as THREE from"three";import{OrbitControls}from"three/addons/controls/OrbitControls.js";import*as TWEEN from"@tweenjs/tween.js";export class CameraManager{constructor(t){this.renderer=t,this.camera=null,this.controls=null,this.sketchState=null,this.isSketchMode=!1,this.sketchPlane=null,this.listeners=[],this._isAnimating=!1,this._beforeAnimEnabled=!1,this._beforeAnimDamping=!1,this.maxDistance=1e4}setupCamera(t,e){this.camera=new THREE.PerspectiveCamera(50,t/e,.1,this.maxDistance),this.camera.position.set(100,100,100),this.camera.lookAt(0,0,0),this.controls=new OrbitControls(this.camera,this.renderer.domElement),this.configureControls(),this.notify()}configureControls(){this.controls.enableDamping=!0,this.controls.dampingFactor=.07,this.controls.screenSpacePanning=!0,this.controls.mouseButtons={LEFT:null,MIDDLE:THREE.MOUSE.PAN,RIGHT:THREE.MOUSE.ROTATE},this.controls.panSpeed=1,this.controls.rotateSpeed=1,this.controls.zoomSpeed=1,this.controls.minDistance=1,this.controls.maxDistance=this.maxDistance,this.controls.maxPolarAngle=Math.PI}setMaxDistance(t){this.camera&&this.controls&&(this.camera.far=t,this.camera.updateProjectionMatrix(),this.controls.maxDistance=t,this.controls.update())}getScreenPosition(t){const e=this.renderer.domElement.getBoundingClientRect(),a=t.clone().project(this.camera);if(a.z>1||a.z<-1)return null;return{x:(.5*a.x+.5)*e.width+e.left,y:(-.5*a.y+.5)*e.height+e.top}}getCurrentDistance(){return this.camera&&this.controls?this.camera.position.distanceTo(this.controls.target):100}animateCameraTo(t,e,a,i=300,s=null){if(!this.camera||!this.controls)return;this._isAnimating&&(TWEEN.removeAll(),this._restoreControlsAfterAnimation());const o=this.camera.position.clone(),r=this.controls.target.clone(),n=this.camera.up.clone();this._beforeAnimEnabled=this.controls.enabled,this._beforeAnimDamping=this.controls.enableDamping,this.controls.enabled=!1,this.controls.enableDamping=!1,this._isAnimating=!0;const c={x:o.x,y:o.y,z:o.z},h={x:r.x,y:r.y,z:r.z},m={x:n.x,y:n.y,z:n.z};new TWEEN.Tween(c).to({x:t.x,y:t.y,z:t.z},i).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(()=>{this.camera.position.set(c.x,c.y,c.z)}).start(),new TWEEN.Tween(h).to({x:e.x,y:e.y,z:e.z},i).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(()=>{this.controls.target.set(h.x,h.y,h.z)}).start(),new TWEEN.Tween(m).to({x:a.x,y:a.y,z:a.z},i).easing(TWEEN.Easing.Quadratic.InOut).onUpdate(()=>{this.camera.up.set(m.x,m.y,m.z).normalize()}).onComplete(()=>{this.camera.up.copy(a).normalize(),this.camera.lookAt(this.controls.target),this.camera.updateProjectionMatrix(),this.controls.update(),this._restoreControlsAfterAnimation(),s&&s()}).start()}_restoreControlsAfterAnimation(){this.controls.enabled=this._beforeAnimEnabled,this.controls.enableDamping=this._beforeAnimDamping,this._isAnimating=!1,this.controls.update(),this.notify()}setCornerView(t,e,a){console.log("setCornerView",t,e,a);const i=this.controls.target.clone(),s=this.getCurrentDistance(),o=new THREE.Vector3(t,e,a).normalize(),r=i.clone().add(o.multiplyScalar(s)),n=i,c=new THREE.Vector3(0,1,0);this.animateCameraTo(r,n,c,300,()=>{this.controls.update(),this.notify()})}setView(t){if(console.log("setView",t),this.isSketchMode&&"home"===t)return void this._orientCameraToPlane(this.sketchPlane);if(["home","isometric"].includes(t)){const e={home:[100,100,100],isometric:[100,100,100]},a=new THREE.Vector3(...e[t]),i=new THREE.Vector3(0,0,0),s=new THREE.Vector3(0,1,0);return void this.animateCameraTo(a,i,s,300,()=>{this.controls.update(),this.notify()})}const e=this.controls.target.clone(),a=this.getCurrentDistance();let i=new THREE.Vector3,s=new THREE.Vector3(0,1,0);switch(t){case"front":i.set(0,0,-1);break;case"back":i.set(0,0,1);break;case"left":i.set(-1,0,0);break;case"right":i.set(1,0,0);break;case"top":i.set(0,1,0);break;case"bottom":i.set(0,-1,0);break;default:return}const o=e.clone().add(i.multiplyScalar(a)),r=e;this.animateCameraTo(o,r,s,300,()=>{this.controls.update(),this.notify()})}rotateCamera(t){if(!this.camera||!this.controls||this._isAnimating)return;const e=this.camera.position.clone(),a=this.controls.target.clone(),i=this.camera.up.clone(),s=(new THREE.Vector3).subVectors(a,e).normalize();let o=(new THREE.Vector3).crossVectors(s,i).normalize(),r=(new THREE.Vector3).crossVectors(o,s).normalize();(new THREE.Quaternion).setFromUnitVectors(r,r.clone().applyQuaternion((new THREE.Quaternion).setFromUnitVectors(r,r.clone().applyAxisAngle(s,t))));const n=r.clone().applyAxisAngle(s,t);this.animateCameraTo(e,a,n,200)}rotateAroundTarget(t){if(!this.camera||!this.controls||this._isAnimating)return;const e=this.controls.target.clone(),a=this.camera.position.clone(),i=(new THREE.Vector3).subVectors(a,e),s=i.length();let o=Math.atan2(i.x,i.z);o+=t;const r=new THREE.Vector3(Math.sin(o)*s,i.y,Math.cos(o)*s),n=e.clone().add(r),c=this.camera.up.clone();this.animateCameraTo(n,e,c,200)}_orientCameraToPlane(t){if(!t)return;const e=this.renderer.domElement.width/this.renderer.domElement.height,a=(new THREE.Box3).setFromObject(t),i=new THREE.Vector3;a.getCenter(i);const s=new THREE.Vector3;a.getSize(s);const o=Math.max(s.x,s.y,s.z),r=Math.max(.6*o,50);this.camera instanceof THREE.OrthographicCamera||this.setOrthographic(),this.camera instanceof THREE.OrthographicCamera&&(this.camera.left=-r*e/2,this.camera.right=r*e/2,this.camera.top=r/2,this.camera.bottom=-r/2);const n=new THREE.Vector3(0,1,0).applyQuaternion(t.quaternion),c=new THREE.Vector3(0,0,1).applyQuaternion(t.quaternion),h=r/2,m=i.clone().add(c.clone().multiplyScalar(h));this.animateCameraTo(m,i,n,10,()=>{this.camera.updateProjectionMatrix(),this.controls.update(),this.notify()})}toggleProjection(){this.camera instanceof THREE.PerspectiveCamera?this.setOrthographic():this.setPerspective(),this.notify()}setPerspective(){if(!(this.camera instanceof THREE.PerspectiveCamera)){const t=this.camera.aspect||this.renderer.domElement.width/this.renderer.domElement.height,e=new THREE.PerspectiveCamera(60,t,.1,this.maxDistance);e.position.copy(this.camera.position),e.quaternion.copy(this.camera.quaternion),e.up.copy(this.camera.up),this.controls.object=e,this.camera=e}}setOrthographic(){if(!(this.camera instanceof THREE.OrthographicCamera)){const t=this.renderer.domElement.width/this.renderer.domElement.height,e=150,a=new THREE.OrthographicCamera(-e*t/2,e*t/2,e/2,-e/2,.1,this.maxDistance);a.position.copy(this.camera.position),a.quaternion.copy(this.camera.quaternion),a.up.copy(this.camera.up),this.controls.object=a,this.camera=a}}getProjectionType(){return this.camera instanceof THREE.PerspectiveCamera?"perspective":"orthographic"}pan(t,e){if(!this.camera||!this.controls)return;const a=new THREE.Vector3(1,0,0).applyQuaternion(this.camera.quaternion),i=new THREE.Vector3(0,1,0).applyQuaternion(this.camera.quaternion),s=(new THREE.Vector3).addScaledVector(a,t).addScaledVector(i,e);this.camera.position.add(s),this.controls.target.add(s),this.camera.updateProjectionMatrix(),this.controls.update(),this.notify()}enterSketchMode(t){this.sketchState={camera:this.camera,position:this.camera.position.clone(),target:this.controls.target.clone(),up:this.camera.up.clone()},this.isSketchMode=!0,this.sketchPlane=t,this._orientCameraToPlane(t)}exitSketchMode(){this.sketchState&&this.animateCameraTo(this.sketchState.position,this.sketchState.target,this.sketchState.up,10,()=>{this.controls.object=this.sketchState.camera,this.camera=this.sketchState.camera,this.camera.updateProjectionMatrix(),this.controls.update(),this.sketchState=null,this.isSketchMode=!1,this.sketchPlane=null,this.notify()})}handleResize(t,e){if(this.camera instanceof THREE.PerspectiveCamera)this.camera.aspect=t/e;else if(this.camera instanceof THREE.OrthographicCamera){const a=t/e,i=this.camera.top-this.camera.bottom;this.camera.left=-i*a/2,this.camera.right=i*a/2,this.camera.top=i/2,this.camera.bottom=-i/2}this.camera.updateProjectionMatrix()}updateControls(){this.controls&&this.controls.update()}onChange(t){this.listeners.push(t)}notify(){this.listeners.forEach(t=>t())}}