import { type PerspectiveCamera, type SceneControl } from '@anov/3d-core'; import ObjectLayer from '../../Base/ObjectLayer'; import type { InfoPanelUpdateConfig } from './interfaces'; /** * InfoPanel * 一个基于 CSS3DObject 的三维信息面板。面板的排版以像素为单位, * 并可根据相机参数在 3D 世界中动态映射为适当的世界尺寸。 * * 关键特性: * - 像素锁定(`pixelLock`):保证屏幕像素尺寸恒定的看板效果。 * - 动态缩放(`updateDynamicScale`):实时根据相机 FOV、距离、视口宽高计算世界尺度。 * - 看板模式(`billboard`):支持水平(yaw)和全方位(full)朝向相机。 * - 自定义缩放(`scale` 与 `userScale3`):统一与非均匀缩放相乘得到最终缩放。 * * 用法概览: * const panel = new InfoPanel({ * text: { value: 'POI A', fontSize: 18 }, * size: [320, 180], * scale: 1, * pixelLock: true, * billboard: 'yaw', * anchor: 'top' * }); * panel.updateDynamicScale(camera); */ export default class InfoPanel extends ObjectLayer { /** * 内部状态与元素引用 * - config: 当前配置(已合并 defaults 与外部传入) * - container: 面板根容器(用于 CSS3DObject 承载) * - titleEl: 标题元素 * - contentEl: 内容元素(可选) * - innerWrap: 内部包裹,用于实现锚点与偏移 * - _cssObject: three.js CSS3DObject(加入到 scene graph) */ private config; private container; private titleEl; private contentEl; private innerWrap; private _cssObject; private _tmpObjPos; private _tmpCamPos; private _tmpCamDir; /** * 构造函数 * @param cfg 外部配置对象;仅识别本组件支持的字段,其他字段会忽略 */ constructor(cfg: InfoPanelUpdateConfig, sceneControl: SceneControl); /** * 将传入的配置与默认值合并并规范化。 * - 自动处理文本样式、九宫格背景、可见性、对齐与偏移。 * - `scale`: 支持数值(统一缩放)或长度为 3 的数组(非均匀缩放)。 * - `pixelLock`: 是否锁定屏幕像素尺寸。 * - `anchor`: 面板锚点。 * @param cfg 配置对象 */ updateConfig(cfg?: InfoPanelUpdateConfig): void; /** * 设置面板世界坐标(应用到 CSS3DObject)。 */ setPosition(x: number, y: number, z: number): void; /** * 设置面板世界旋转(欧拉角,单位:弧度)。 */ setRotation(x: number, y: number, z: number): void; /** * 设置统一缩放因子(立即应用到 CSS3DObject)。 * 注意:若使用 `updateDynamicScale`,每帧会覆盖此值。 */ setScale(s: number): void; /** * 设置看板模式。 * @param mode 'none' | 'yaw' | 'full' */ setBillboard(mode: 'none' | 'yaw' | 'full'): void; /** * 设置可见性。 * @param v 是否可见 */ setVisible(v: boolean): void; /** * 应用所有样式与文本到 DOM。 * 仅影响面板的排版与外观,不涉及 3D 变换。 */ applyStyle(): void; /** * 更新配置并立即重新应用到 DOM。 * @param cfg 新配置 */ update(cfg?: InfoPanelUpdateConfig): void; /** * 根据看板模式使面板朝向相机。 * - 'full':使用 `lookAt` 全方位朝向相机。 * - 'yaw':仅绕 Y 轴旋转,保持水平面朝向相机。 * - 'none':不处理朝向。 * @param camera three.js 相机 */ updateFacing(camera: PerspectiveCamera): void; /** * 动态缩放:根据相机 FOV、沿相机前向的距离 d、视口尺寸, * 计算“每像素对应的世界单位”,并结合用户缩放得到最终缩放。 * - pixelLock: s = worldPerPixelX * userScale * - 非锁定: s = userScale * - 最终各轴缩放: [sx, sy, sz] = s * userScale3 */ updateDynamicScale(camera: PerspectiveCamera, viewportWidth?: number, viewportHeight?: number): void; /** * 释放面板:从场景移除 CSS3DObject,并清理 DOM。 */ dispose(): void; /** * 获取当前面板在世界坐标中的宽高(单位:世界单位)。 * 注意:结果受相机参数、面板到相机的距离以及当前 `_cssObject.scale` 影响。 * @param camera three.js 相机 * @param viewportWidth 视口宽度(像素) * @param viewportHeight 视口高度(像素) * @returns `{ width, height }` 世界单位 */ getWorldSize(camera: PerspectiveCamera, viewportWidth?: number, viewportHeight?: number): { width: number; height: number; }; }