101 lines
2.9 KiB
TypeScript
101 lines
2.9 KiB
TypeScript
import { AxesHelper, Camera, PerspectiveCamera, Scene, WebGLRenderer } from "three";
|
||
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
|
||
|
||
export type Animate = {
|
||
fun: (arg: any) => any;
|
||
content: any;
|
||
};
|
||
export default class Viewer {
|
||
public id: string;
|
||
public viewerDom!: HTMLElement;
|
||
public renderer!: WebGLRenderer;
|
||
public scene!: Scene;
|
||
public camera!: PerspectiveCamera;
|
||
public controls!: OrbitControls;
|
||
public isDestroy = false; // 是否销毁
|
||
public animateEventList = new Map();
|
||
|
||
constructor(id: string) {
|
||
this.id = id;
|
||
this.initViewer();
|
||
}
|
||
|
||
private initViewer() {
|
||
this.initRender();
|
||
this.initScene();
|
||
this.initCamera();
|
||
this.initControl();
|
||
|
||
const animate = () => {
|
||
if (this.isDestroy) return;
|
||
requestAnimationFrame(animate);
|
||
this.updateDom();
|
||
this.renderDom();
|
||
|
||
// 全局的公共动画函数,添加函数可同步执行
|
||
this.animateEventList.forEach((event) => {
|
||
if (event.fun && event.content) event.fun(event.content);
|
||
});
|
||
};
|
||
animate();
|
||
}
|
||
|
||
private initRender() {
|
||
// 获取画布dom
|
||
this.viewerDom = document.getElementById(this.id) as HTMLElement;
|
||
this.renderer = new WebGLRenderer({ antialias: true });
|
||
|
||
this.viewerDom.appendChild(this.renderer.domElement);
|
||
}
|
||
|
||
// 创建场景
|
||
private initScene() {
|
||
this.scene = new Scene();
|
||
}
|
||
|
||
private initControl() {
|
||
this.controls = new OrbitControls(this.camera as Camera, this.renderer?.domElement);
|
||
|
||
this.controls.enableDamping = false;
|
||
this.controls.screenSpacePanning = false;
|
||
this.controls.minDistance = 2;
|
||
this.controls.maxDistance = 1000;
|
||
}
|
||
|
||
// 初始化相机
|
||
public initCamera() {
|
||
this.camera = new PerspectiveCamera(75, this.viewerDom.clientWidth / this.viewerDom.clientHeight, 0.1, 1000);
|
||
this.camera.position.set(5, 5, 10);
|
||
this.camera.lookAt(0, 0, 0);
|
||
}
|
||
|
||
//创建坐标轴辅助对象
|
||
public addAxis() {
|
||
const axis = new AxesHelper(1000);
|
||
this.scene?.add(axis);
|
||
}
|
||
|
||
// 添加动画事件
|
||
public addAnimate(id: string, animate: Animate) {
|
||
this.animateEventList.set(id, animate);
|
||
}
|
||
|
||
// 根据传入的id,删除动画事件列表中的对应事件
|
||
public removeAnimate(id: string) {
|
||
this.animateEventList?.delete(id);
|
||
}
|
||
|
||
// 更新参数
|
||
public updateDom() {
|
||
this.camera.aspect = this.viewerDom.clientWidth / this.viewerDom.clientHeight; // 摄像机视锥体的长宽比,通常是使用画布的宽/画布的高
|
||
this.camera.updateProjectionMatrix(); // 更新摄像机投影矩阵。在任何参数被改变以后必须被调用,来使得这些改变生效
|
||
this.renderer.setSize(this.viewerDom.clientWidth, this.viewerDom.clientHeight);
|
||
this.renderer.setPixelRatio(window.devicePixelRatio); // 设置设备像素比
|
||
}
|
||
|
||
// 渲染dom
|
||
public renderDom() {
|
||
this.renderer?.render(this.scene as Scene, this.camera as Camera);
|
||
}
|
||
}
|