drone-camera 0.0.0-stage → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +157 -2
- package/index.d.ts +51 -0
- package/index.d.ts.map +1 -0
- package/index.js +20474 -0
- package/index.js.map +1 -0
- package/index.umd.cjs +1361 -0
- package/index.umd.cjs.map +1 -0
- package/lib/drone-capture-manifest.d.ts +169 -0
- package/lib/drone-capture-manifest.d.ts.map +1 -0
- package/lib/drone-capture-panel.d.ts +135 -0
- package/lib/drone-capture-panel.d.ts.map +1 -0
- package/lib/drone-capture.d.ts +380 -0
- package/lib/drone-capture.d.ts.map +1 -0
- package/lib/drone-cesium-mission.d.ts +120 -0
- package/lib/drone-cesium-mission.d.ts.map +1 -0
- package/lib/drone-cesium-rig.d.ts +50 -0
- package/lib/drone-cesium-rig.d.ts.map +1 -0
- package/lib/drone-cesium.d.ts +519 -0
- package/lib/drone-cesium.d.ts.map +1 -0
- package/lib/drone-control.d.ts +188 -0
- package/lib/drone-control.d.ts.map +1 -0
- package/lib/drone-engine.d.ts +70 -0
- package/lib/drone-engine.d.ts.map +1 -0
- package/lib/drone-exif.d.ts +64 -0
- package/lib/drone-exif.d.ts.map +1 -0
- package/lib/drone-fly.d.ts +545 -0
- package/lib/drone-fly.d.ts.map +1 -0
- package/lib/drone-gallery.d.ts +146 -0
- package/lib/drone-gallery.d.ts.map +1 -0
- package/lib/drone-husky-model.d.ts +22 -0
- package/lib/drone-husky-model.d.ts.map +1 -0
- package/lib/drone-image-utils.d.ts +67 -0
- package/lib/drone-image-utils.d.ts.map +1 -0
- package/lib/drone-image-viewer.d.ts +97 -0
- package/lib/drone-image-viewer.d.ts.map +1 -0
- package/lib/drone-lights.d.ts +194 -0
- package/lib/drone-lights.d.ts.map +1 -0
- package/lib/drone-minimap.d.ts +155 -0
- package/lib/drone-minimap.d.ts.map +1 -0
- package/lib/drone-panel.d.ts +265 -0
- package/lib/drone-panel.d.ts.map +1 -0
- package/lib/drone-panorama-viewer.d.ts +162 -0
- package/lib/drone-panorama-viewer.d.ts.map +1 -0
- package/lib/drone-panorama.d.ts +242 -0
- package/lib/drone-panorama.d.ts.map +1 -0
- package/lib/drone-photogrammetry.d.ts +207 -0
- package/lib/drone-photogrammetry.d.ts.map +1 -0
- package/lib/drone-radar.d.ts +136 -0
- package/lib/drone-radar.d.ts.map +1 -0
- package/lib/drone-reconstruction-preview.d.ts +84 -0
- package/lib/drone-reconstruction-preview.d.ts.map +1 -0
- package/lib/drone-rig.d.ts +385 -0
- package/lib/drone-rig.d.ts.map +1 -0
- package/lib/drone-sim.d.ts +883 -0
- package/lib/drone-sim.d.ts.map +1 -0
- package/lib/drone-stitch.d.ts +84 -0
- package/lib/drone-stitch.d.ts.map +1 -0
- package/lib/drone-world.d.ts +194 -0
- package/lib/drone-world.d.ts.map +1 -0
- package/lib/mission-editor.d.ts +116 -0
- package/lib/mission-editor.d.ts.map +1 -0
- package/lib/mission-panel.d.ts +173 -0
- package/lib/mission-panel.d.ts.map +1 -0
- package/package.json +61 -4
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { DroneFly } from './drone-fly';
|
|
2
|
+
/**
|
|
3
|
+
* 鹰眼图(俯视小地图)—— 原生 DOM + Canvas 2D,与 drone-panel / mission-panel 同一套范式:
|
|
4
|
+
* 框架无关、`dcm-*` 类名、配色走 CSS 变量、构造即可挂载、destroy 彻底回收。
|
|
5
|
+
*
|
|
6
|
+
* ## 为什么不是"开第二个 three.js 视口"
|
|
7
|
+
* 它只是一张**态势示意图**,不是真实几何的第二次渲染 —— 只读 fly.sim 的真值
|
|
8
|
+
* (位置 / 航向 / 障碍 AABB / 航线 / 返航点)与 world 的航迹,自己投影成 2D。于是:
|
|
9
|
+
*
|
|
10
|
+
* 1. **零渲染器耦合**:WebGPU / WebGL / 无头环境都能跑,不碰 renderer、不碰相机、不碰场景;
|
|
11
|
+
* 2. **不会混进成片**:第二视口方案要把小地图渲进同一个 renderer,拍照与录像抓的就是那帧,
|
|
12
|
+
* 小地图会糊在成片角落;本方案出的是叠加层,与 renderer 输出天然分离;
|
|
13
|
+
* 3. **不占用三维资源**:没有额外的正交相机、视锥、scissor 状态要维护。
|
|
14
|
+
*
|
|
15
|
+
* ## 更新节奏与面板不同
|
|
16
|
+
* 面板 200ms 轮询读数足够,但小地图 5Hz 会一帧一格地跳。所以这里**自驱 requestAnimationFrame**
|
|
17
|
+
* 每帧重绘 —— 几百个图元的 canvas 重绘成本可忽略,且与宿主渲染循环互不干扰
|
|
18
|
+
* (`render()` 也对外公开,宿主想自己控制节拍可以调它)。
|
|
19
|
+
*
|
|
20
|
+
* ## 坐标映射是直给
|
|
21
|
+
* sim 的约定是 x 向东、z 向南(与模型一致),所以"北向上"就是屏幕右 = +x、屏幕上 = -z:
|
|
22
|
+
* `u = cx + (x - ox) · k`、`v = cy + (z - oz) · k`。不需要矩阵,也不需要碰相机。
|
|
23
|
+
* 顺带一个好处:机体箭头的 canvas 旋转角**恰好等于 heading 弧度**(0° = 北 = 屏幕上方)。
|
|
24
|
+
*
|
|
25
|
+
* ## 朝向固定北向
|
|
26
|
+
* 地图不旋转、只有机体箭头转 —— 这是 DJI 的默认读图方式:障碍物与返航点的相对方位
|
|
27
|
+
* 不随飞行姿态变化,"该往哪边飞"判断更稳(机头朝上模式下车头一偏,整张图都跟着晃)。
|
|
28
|
+
*/
|
|
29
|
+
/** 小地图吸附的容器角;bottom-center = 底边水平居中(两侧摇杆之间的空档) */
|
|
30
|
+
export type MiniMapPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right' | 'bottom-center';
|
|
31
|
+
export interface MiniMapOptions {
|
|
32
|
+
/** 挂载容器;缺省挂到 document.body(贴视口),给了容器就贴容器(必要时自动补 relative) */
|
|
33
|
+
container?: HTMLElement;
|
|
34
|
+
/** 吸附角,默认右下角(与控制面板右上、航线面板左上错开) */
|
|
35
|
+
position?: MiniMapPosition;
|
|
36
|
+
/**
|
|
37
|
+
* 角内偏移(像素):在默认 14px 边距之上再让出的距离。
|
|
38
|
+
* 右下角常被 HUD 摇杆 + 技能钮占着,demo 里就是用它把小地图抬到轮盘上方。
|
|
39
|
+
*/
|
|
40
|
+
offset?: {
|
|
41
|
+
x?: number;
|
|
42
|
+
y?: number;
|
|
43
|
+
};
|
|
44
|
+
/** 画布边长(CSS 像素),默认 186 */
|
|
45
|
+
size?: number;
|
|
46
|
+
/** 固定半量程(米);传了就关闭自动量程。缺省 null = 自动跟随 */
|
|
47
|
+
range?: number | null;
|
|
48
|
+
/** 自动量程下限(米),默认 40 */
|
|
49
|
+
minRange?: number;
|
|
50
|
+
/** 自动量程上限(米),默认 300 */
|
|
51
|
+
maxRange?: number;
|
|
52
|
+
visible?: boolean;
|
|
53
|
+
/** 注入内置样式,默认 true;宿主自备样式可关掉 */
|
|
54
|
+
injectStyles?: boolean;
|
|
55
|
+
/** 额外类名,追加在 `dcm` 之后 */
|
|
56
|
+
className?: string;
|
|
57
|
+
showObstacles?: boolean;
|
|
58
|
+
showMission?: boolean;
|
|
59
|
+
showTrail?: boolean;
|
|
60
|
+
showFov?: boolean;
|
|
61
|
+
showGrid?: boolean;
|
|
62
|
+
}
|
|
63
|
+
/** 探针/调试读数 */
|
|
64
|
+
export interface MiniMapStats {
|
|
65
|
+
/** 当前实际半量程(米) */
|
|
66
|
+
range: number;
|
|
67
|
+
/** 当前比例尺(像素 / 米) */
|
|
68
|
+
scale: number;
|
|
69
|
+
obstacleCount: number;
|
|
70
|
+
waypointCount: number;
|
|
71
|
+
trailPoints: number;
|
|
72
|
+
/** 机载水平视场角(度);非机载视角返回 null */
|
|
73
|
+
fovDeg: number | null;
|
|
74
|
+
/** 地图中心的世界坐标(= 机体位置) */
|
|
75
|
+
centerX: number;
|
|
76
|
+
centerZ: number;
|
|
77
|
+
}
|
|
78
|
+
export declare class DroneMiniMap {
|
|
79
|
+
private readonly fly;
|
|
80
|
+
private readonly container;
|
|
81
|
+
private readonly root;
|
|
82
|
+
private readonly canvas;
|
|
83
|
+
private readonly ctx;
|
|
84
|
+
private readonly size;
|
|
85
|
+
private readonly minRange;
|
|
86
|
+
private readonly maxRange;
|
|
87
|
+
private readonly showObstacles;
|
|
88
|
+
private readonly showMission;
|
|
89
|
+
private readonly showTrail;
|
|
90
|
+
private readonly showFov;
|
|
91
|
+
private readonly showGrid;
|
|
92
|
+
private colors;
|
|
93
|
+
private visible;
|
|
94
|
+
private destroyed;
|
|
95
|
+
/** 手动量程(米);null = 自动跟随 */
|
|
96
|
+
private manualRange;
|
|
97
|
+
private rangeCurrent;
|
|
98
|
+
private rangeTarget;
|
|
99
|
+
private rangeReady;
|
|
100
|
+
/** 本帧的投影参数:比例尺(像素/米)、地图中心的世界坐标 */
|
|
101
|
+
private scale;
|
|
102
|
+
private originX;
|
|
103
|
+
private originZ;
|
|
104
|
+
private raf;
|
|
105
|
+
private lastTime;
|
|
106
|
+
private frameDrawn;
|
|
107
|
+
/** 构造鹰眼图:Canvas 2D 俯视 HUD,只读 sim 真值,不碰三维渲染 */
|
|
108
|
+
constructor(fly: DroneFly, options?: MiniMapOptions);
|
|
109
|
+
/** 立即重绘一帧(宿主想自控节拍时可关掉内置 rAF —— 见 stop()) */
|
|
110
|
+
render(): void;
|
|
111
|
+
/** 显示/隐藏鹰眼图 */
|
|
112
|
+
setVisible(visible: boolean): void;
|
|
113
|
+
/** 鹰眼图当前是否可见 */
|
|
114
|
+
isVisible(): boolean;
|
|
115
|
+
/** 量程:传数字 = 固定该半量程(米);传 null = 回到自动跟随 */
|
|
116
|
+
setRange(range: number | null): void;
|
|
117
|
+
/** 当前实际半量程(米) */
|
|
118
|
+
getRange(): number;
|
|
119
|
+
/** 切主题(读一遍 CSS 变量)后调用;平时不必每帧读 */
|
|
120
|
+
refreshTheme(): void;
|
|
121
|
+
/** 探针读数 */
|
|
122
|
+
getStats(): MiniMapStats;
|
|
123
|
+
/** 本帧是否已绘制过(探针用:确认 rAF 真的在跑) */
|
|
124
|
+
hasDrawn(): boolean;
|
|
125
|
+
/** 停止内置刷新(之后需自行调用 render()) */
|
|
126
|
+
stop(): void;
|
|
127
|
+
/** 停止重绘循环并移除画布 */
|
|
128
|
+
destroy(): void;
|
|
129
|
+
private start;
|
|
130
|
+
private resolveColors;
|
|
131
|
+
/** 机载取景相机的当前水平视场角(度,已折算 zoom);非机载视角返回 null */
|
|
132
|
+
private horizontalFov;
|
|
133
|
+
/**
|
|
134
|
+
* 量程:自动模式下取「机体到返航点 / 到各航点的最远距离 + 余量」,
|
|
135
|
+
* 再向上取整到 RANGE_STEPS 的档位,最后缓动过去(换档不硬切)。
|
|
136
|
+
*/
|
|
137
|
+
private updateRange;
|
|
138
|
+
private drawFrame;
|
|
139
|
+
private toX;
|
|
140
|
+
private toY;
|
|
141
|
+
private gridStep;
|
|
142
|
+
private drawGrid;
|
|
143
|
+
/** 刻度环:满量程 + 半量程两道虚线同心圆(圆心即机体,因为机体恒居中) */
|
|
144
|
+
private drawRings;
|
|
145
|
+
private drawObstacles;
|
|
146
|
+
private drawMission;
|
|
147
|
+
private drawTrail;
|
|
148
|
+
private drawHome;
|
|
149
|
+
/** FPV 水平视场扇形:从机体出发、机头方向张开,看一眼就知道"现在镜头能拍到哪一片" */
|
|
150
|
+
private drawFov;
|
|
151
|
+
private drawDrone;
|
|
152
|
+
private drawCompass;
|
|
153
|
+
private drawScaleLabel;
|
|
154
|
+
}
|
|
155
|
+
//# sourceMappingURL=drone-minimap.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drone-minimap.d.ts","sourceRoot":"","sources":["../../src/lib/drone-camera/drone-minimap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 无人机控制面板(原生 DOM 实现):王者荣耀式 HUD —— 双虚拟摇杆 + 技能按钮 + 飞行控制面板。
|
|
3
|
+
*
|
|
4
|
+
* 布局(仿王者荣耀):
|
|
5
|
+
* - 左右两根虚拟摇杆**脱离面板**,作为悬浮 HUD 挂在画面左下 / 右下角(控制罗盘左右各一个);
|
|
6
|
+
* - 拍照 / 录像是「技能」按钮,悬浮在右轮盘上方(蓝圈 = 拍照,橙圈 = 录像),
|
|
7
|
+
* 角标显示拍照张数 / 录制秒数(对应游戏里技能的buff计数);
|
|
8
|
+
* - 面板本体只留飞行控制(上电/起飞/降落/返航/机臂/模式)+ 速度倍率(0~1000,数值即倍数)+
|
|
9
|
+
* 视角切换 + 云台,停靠按 position 选项。
|
|
10
|
+
*
|
|
11
|
+
* 设计边界:
|
|
12
|
+
* - 只用原生 DOM / CSS,不引入任何 UI 框架 —— 库整体保持与框架无关(Vue / React / 裸页面通用);
|
|
13
|
+
* - 面板自身不持有状态:渲染时从 DroneFly / DroneSim 读,操作时调 DroneFly 方法,
|
|
14
|
+
* 真值永远以引擎为准(见 sync)。宿主用别的方式改了视角或云台,面板下一轮同步就会跟上,不会脱节;
|
|
15
|
+
* - 样式默认注入一份(类名统一 `dcp-` 前缀、配色走 CSS 变量),可用 injectStyles:false 关闭,由宿主自行配色。
|
|
16
|
+
*
|
|
17
|
+
* 非直觉约定:
|
|
18
|
+
* - 面板以 200ms 轮询同步状态(可用 syncIntervalMs 调或关);拖动云台滑杆期间暂停回写,避免与用户输入打架;
|
|
19
|
+
* - 键盘是屏上双摇杆的第二套输入:按键时对应那根杆会**同步推杆**(杆帽位移 + 高亮 + 读数),
|
|
20
|
+
* 看起来就像有人在替你打杆;两套输入合成时"摇杆优先"(见 applyStick);
|
|
21
|
+
* - 技能(拍照 / 录像)另有组合键 `Ctrl`(`Cmd`)+ `K` / `L`,按一次触发一次,与点技能钮同一路径;
|
|
22
|
+
* - 摇杆按 DJI 遥控器(美国手 Mode 2)的杆位分工:左杆 = 上/下升降 + 左/右偏航,右杆 = 上/下前后 + 左/右横滚。
|
|
23
|
+
* 两根杆都是**自回中**的:松手立刻归零并回到中心 —— 对应真机的"松杆即停",不会因为漏掉抬起事件一直飞;
|
|
24
|
+
* - 摇杆用 Pointer Events + setPointerCapture 实现,鼠标 / 触摸 / 触控笔同一套代码,
|
|
25
|
+
* 并且按 pointerId 分别跟踪,双指可以同时推两根杆(真机双手打杆);
|
|
26
|
+
* - 悬浮层与面板是**两个兄弟节点**(都挂在 container 上):面板有 backdrop-filter,会把 fixed 后代的定位
|
|
27
|
+
* 基准改成面板自身,所以摇杆不能塞进面板里;悬浮层 pointer-events:none、只留轮盘可点,不挡场景交互。
|
|
28
|
+
*/
|
|
29
|
+
import type { DronePanelHost } from './drone-control';
|
|
30
|
+
import type { PhotoShot } from './drone-fly';
|
|
31
|
+
import type { CaptureService } from './drone-capture';
|
|
32
|
+
/** 面板停靠位置(相对挂载容器) */
|
|
33
|
+
export type DronePanelPosition = 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right';
|
|
34
|
+
/** DroneControlPanel 构造选项 */
|
|
35
|
+
export interface DroneControlPanelOptions {
|
|
36
|
+
/** 挂载容器;缺省挂到 document.body(此时面板与悬浮层改用 fixed 定位) */
|
|
37
|
+
container?: HTMLElement | null;
|
|
38
|
+
/** 面板停靠位置,默认 'top-right';左右轮盘固定悬浮在画面两下角,不受此项影响 */
|
|
39
|
+
position?: DronePanelPosition;
|
|
40
|
+
/** 面板标题,默认「无人机」 */
|
|
41
|
+
title?: string;
|
|
42
|
+
/** 是否注入自带样式,默认 true;关闭后仅保留 `dcp-*` 类名,由宿主自行配色 */
|
|
43
|
+
injectStyles?: boolean;
|
|
44
|
+
/** 云台俯仰快捷档位(度),默认 [-90, -30, -10, 0] */
|
|
45
|
+
pitchPresets?: number[];
|
|
46
|
+
/** 初始是否可见,默认 true */
|
|
47
|
+
visible?: boolean;
|
|
48
|
+
/** 拍照完成回调;未提供且 autoDownload 为 true 时自动下载 PNG */
|
|
49
|
+
onPhoto?: (shot: PhotoShot) => void;
|
|
50
|
+
/**
|
|
51
|
+
* 采集服务(可选)。提供后面板出现「拍摄模式」区,可切换广角 / 180° / 360°:
|
|
52
|
+
* 全景按预设网格逐张取景拍摄,每张都带全景分组信息登记进这个服务的当前会话。
|
|
53
|
+
*
|
|
54
|
+
* 与采集面板共用同一个实例时,全景照片会直接出现在那边的影像集里(见 demo 的接法)。
|
|
55
|
+
*/
|
|
56
|
+
captureService?: CaptureService;
|
|
57
|
+
/** 是否启用全景拍摄(默认 true);没有 `captureService` 时不显示该区 */
|
|
58
|
+
panorama?: boolean;
|
|
59
|
+
/** 全景每张之间的间隔(毫秒),默认 120 */
|
|
60
|
+
panoramaShotIntervalMs?: number;
|
|
61
|
+
/** 录像完成回调;未提供且 autoDownload 为 true 时自动下载 webm */
|
|
62
|
+
onRecording?: (blob: Blob, seconds: number) => void;
|
|
63
|
+
/** 无自定义回调时是否自动下载产物,默认 true */
|
|
64
|
+
autoDownload?: boolean;
|
|
65
|
+
/** 状态轮询间隔(毫秒),默认 200;传 0 关闭自动同步、完全由宿主调 sync() */
|
|
66
|
+
syncIntervalMs?: number;
|
|
67
|
+
/** 摇杆死区(0~1),默认 0.06;小于该幅值视为 0,抵住手指轻微抖动。作用于垂直通道(升降 / 前后) */
|
|
68
|
+
stickDeadzone?: number;
|
|
69
|
+
/**
|
|
70
|
+
* 横滚 / 偏航死区(0~1),默认 0.14。比垂直通道大一档 —— 触屏推杆时手指很难保证绝对竖直,
|
|
71
|
+
* 轻微的侧向分量会被放大成持续横移和机头偏转,几分钟就飞出弧线。加大这一路死区等于给
|
|
72
|
+
* 直线飞行留出一条"安全走廊",垂直通道不受影响、起手依然跟手。
|
|
73
|
+
*/
|
|
74
|
+
stickLateralDeadzone?: number;
|
|
75
|
+
/**
|
|
76
|
+
* 摇杆指数曲线 expo(0~1),默认 0.55,真机遥控器的 expo 手感:
|
|
77
|
+
* 输出 = expo·v³ + (1-expo)·v —— 中位附近行程放慢(便于精确微调),
|
|
78
|
+
* 末端仍能打满舵量(1 处恒等于 1),推到底的极速与转向权限不受影响。
|
|
79
|
+
* 传 0 退回线性响应。
|
|
80
|
+
*/
|
|
81
|
+
stickExpo?: number;
|
|
82
|
+
/**
|
|
83
|
+
* 偏航角速度缩放(0~1],默认 0.6。左杆左右 / ←→ 键的转向输出乘这个系数 ——
|
|
84
|
+
* 飞控的挡位角速度是照真机标的(普通挡 100°/s,满杆 3.6 秒转一圈),
|
|
85
|
+
* 在屏幕遥控器上偏快;这里只压遥控器侧的输出,飞控与挡位表不动。
|
|
86
|
+
* 传 1 退回真机原始速率。
|
|
87
|
+
*/
|
|
88
|
+
yawRateScale?: number;
|
|
89
|
+
/**
|
|
90
|
+
* 是否启用键盘控制,默认 true。键位(与屏上双摇杆等效,左手 WASD 对左杆、右手方向键对右杆):
|
|
91
|
+
* `W/S` 升降 · `A/D` 转向(左杆) · `↑/↓` 前后 · `←/→` 横滚(右杆);`Q/E` 是转向的备用键。
|
|
92
|
+
* 另外两组技能快捷键:`Ctrl`(macOS 上 `Cmd`)+ `K` 拍照、`Ctrl` + `L` 录像(开关,再按一次停止),
|
|
93
|
+
* 等同于点右轮盘上的拍照 / 录像钮,长按不连发。
|
|
94
|
+
* 键盘是开关量,内部做了渐进行程(按下渐推、松开渐回),不会突然满舵。
|
|
95
|
+
* 焦点在输入框内时不拦截按键。
|
|
96
|
+
*/
|
|
97
|
+
keyboard?: boolean;
|
|
98
|
+
/** 键盘推杆渐推时间(秒),默认 0.45;越大越柔和 */
|
|
99
|
+
keyboardRiseSeconds?: number;
|
|
100
|
+
/** 键盘松手渐回时间(秒),默认 0.18 */
|
|
101
|
+
keyboardFallSeconds?: number;
|
|
102
|
+
/** 是否启用移动端自适应(横屏紧凑布局 / 触控尺寸),默认 true */
|
|
103
|
+
adaptive?: boolean;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* 无人机控制面板:王者荣耀式 HUD(左右悬浮轮盘 + 右轮盘技能) + 飞行控制面板。
|
|
107
|
+
*
|
|
108
|
+
* ```ts
|
|
109
|
+
* const fly = new DroneFly(scene, camera, renderer, controls)
|
|
110
|
+
* await fly.initialize({ modelUrl: '/models/dji_mini4_pro.glb' })
|
|
111
|
+
* const panel = new DroneControlPanel(fly, { container: viewportEl, position: 'top-right' })
|
|
112
|
+
* // 卸载:panel.destroy()
|
|
113
|
+
* ```
|
|
114
|
+
*
|
|
115
|
+
* 按钮可用性由飞行阶段推导(见 sync):未上电时只有「上电」可点,待机/电机已启动才能「起飞」,
|
|
116
|
+
* 离地后才能「降落」「返航」—— 与真机的操作次序一致,不会点出无效请求。
|
|
117
|
+
* 方向由两根自回中虚拟摇杆给出(DJI 美国手 Mode 2),输出的是连续行程而不是开关量。
|
|
118
|
+
*
|
|
119
|
+
* 手感对齐真机遥控器:垂直通道死区 0.06、横滚/偏航死区 0.14(留出直线飞行走廊)、
|
|
120
|
+
* 全通道叠加 expo 指数曲线(默认 0.55,中位变钝、末端仍打满),可用
|
|
121
|
+
* `stickDeadzone` / `stickLateralDeadzone` / `stickExpo` 覆盖(传 0 即关闭)。
|
|
122
|
+
*/
|
|
123
|
+
export declare class DroneControlPanel {
|
|
124
|
+
/** 面板根元素(宿主可追加类名做二次定制) */
|
|
125
|
+
readonly root: HTMLDivElement;
|
|
126
|
+
/** 悬浮摇杆/技能层(面板的兄弟节点,铺满容器;宿主可追加类名做二次定制) */
|
|
127
|
+
readonly hudLayer: HTMLDivElement;
|
|
128
|
+
private readonly fly;
|
|
129
|
+
private readonly opts;
|
|
130
|
+
private readonly presets;
|
|
131
|
+
private readonly container;
|
|
132
|
+
private readonly abort;
|
|
133
|
+
private readonly deadzone;
|
|
134
|
+
private readonly lateralDeadzone;
|
|
135
|
+
private readonly expo;
|
|
136
|
+
private readonly yawRateScale;
|
|
137
|
+
private readonly keyboardEnabled;
|
|
138
|
+
private readonly keyboardRise;
|
|
139
|
+
private readonly keyboardFall;
|
|
140
|
+
/** 当前按下的键盘键(存 event.code,不受输入法/大写锁定影响) */
|
|
141
|
+
private readonly pressedKeys;
|
|
142
|
+
/** 键盘合成行程(带渐推渐回);与摇杆合成时"摇杆优先" */
|
|
143
|
+
private readonly keyboardStick;
|
|
144
|
+
private keyboardTimer;
|
|
145
|
+
private lastKeyboardTick;
|
|
146
|
+
private sticks;
|
|
147
|
+
private readonly refs;
|
|
148
|
+
private timer;
|
|
149
|
+
private pitchDragging;
|
|
150
|
+
/** 正在拖速度倍率滑杆:期间不回写,免得和用户的手打架 */
|
|
151
|
+
private speedDragging;
|
|
152
|
+
private photoBusy;
|
|
153
|
+
private visible;
|
|
154
|
+
private collapsed;
|
|
155
|
+
private destroyed;
|
|
156
|
+
/** 停止录像前抓的时长,用于回调与提示(stopRecording 后 sim.recordSeconds 会归零) */
|
|
157
|
+
private lastRecordSeconds;
|
|
158
|
+
/** 全景扫描器(未接采集服务时为 null) */
|
|
159
|
+
private panorama;
|
|
160
|
+
private panoramaUnsub;
|
|
161
|
+
/** 当前拍摄模式:单张 / 180° / 360° */
|
|
162
|
+
private shootMode;
|
|
163
|
+
/** 最近一次全景进度(面板只做展示) */
|
|
164
|
+
private panoProgress;
|
|
165
|
+
/** 构造控制面板并插入容器(可传 options 停靠位置/手感/键盘开关) */
|
|
166
|
+
constructor(fly: DronePanelHost, options?: DroneControlPanelOptions);
|
|
167
|
+
/** 插入容器(构造时已自动调用一次;面板与悬浮层一起挂) */
|
|
168
|
+
mount(): this;
|
|
169
|
+
/** 从容器移除但保留实例,可再次 mount */
|
|
170
|
+
unmount(): this;
|
|
171
|
+
/** 显示 / 隐藏(面板与悬浮轮盘一起切换) */
|
|
172
|
+
setVisible(visible: boolean): this;
|
|
173
|
+
/** 当前是否可见 */
|
|
174
|
+
isVisible(): boolean;
|
|
175
|
+
/** 折叠 / 展开(只收面板,左右轮盘与技能保持可用 —— 游戏里也不收操作区) */
|
|
176
|
+
setCollapsed(collapsed: boolean): this;
|
|
177
|
+
/** 彻底销毁:解绑事件、停轮询、移除 DOM */
|
|
178
|
+
destroy(): void;
|
|
179
|
+
/**
|
|
180
|
+
* 移除已注入的共享样式。
|
|
181
|
+
* 多个面板共存时请等最后一个销毁后再调用,否则其余面板会掉样式。
|
|
182
|
+
*/
|
|
183
|
+
static removeInjectedStyles(): void;
|
|
184
|
+
/** 把引擎当前状态刷到 HUD 上(飞行阶段/按钮可用性 / 视角高亮 / 云台角度 / 技能角标 / 摇杆读数) */
|
|
185
|
+
sync(): void;
|
|
186
|
+
/** 技能角标(游戏里的 buff 计数位):全景扫描中优先显示扫描进度,否则显示拍照张数 */
|
|
187
|
+
private syncHudBadge;
|
|
188
|
+
/** 拍摄模式区:模式高亮 + 读数(空闲显示张数,扫描中/完成显示进度) */
|
|
189
|
+
private syncShootMode;
|
|
190
|
+
private query;
|
|
191
|
+
private queryIn;
|
|
192
|
+
/** 面板本体:飞行控制 + 模式/视角/云台(方向轮盘与拍照录像已拆到悬浮层) */
|
|
193
|
+
private template;
|
|
194
|
+
/** 悬浮层:左右两根轮盘 + 右轮盘上的拍照/录像技能(位置关系由 CSS 钉死,旋转/缩放不散架) */
|
|
195
|
+
private hudTemplate;
|
|
196
|
+
/** 单根虚拟摇杆:底盘 + 十字刻度 + 四向提示 + 可按压的杆帽 + 实时读数 */
|
|
197
|
+
private stickTemplate;
|
|
198
|
+
private collectSticks;
|
|
199
|
+
/** 事件委托挂在指定子树上(面板与悬浮层各一份,共用 handleAction) */
|
|
200
|
+
private bindActionDelegate;
|
|
201
|
+
private bind;
|
|
202
|
+
private startStick;
|
|
203
|
+
private moveStick;
|
|
204
|
+
private endStick;
|
|
205
|
+
/** 把指针位置换算成摇杆行程:超出圆行程就按半径夹到边界(圆轨,和真机的物理限位一致) */
|
|
206
|
+
private updateStick;
|
|
207
|
+
/** 松杆 / 销毁:行程归零 + 杆帽回中。必须成对调用,否则摇杆会"卡住"让飞机一直飞 */
|
|
208
|
+
private resetStick;
|
|
209
|
+
/**
|
|
210
|
+
* 键盘 → 屏上摇杆:把渐进行程画到杆帽上(位移 + 高亮 + 读数),按键时看起来就像有人在替你打杆。
|
|
211
|
+
* 手指正按着的杆跳过 —— 那根杆的视觉由 updateStick 跟手绘制,键盘不该来抢。
|
|
212
|
+
*/
|
|
213
|
+
private syncKeyboardVisuals;
|
|
214
|
+
/**
|
|
215
|
+
* 画一根杆的杆帽位置:行程 ±1 直接映射到圆轨半径(上 / 右为正),与 formatStickText 的方向约定一致。
|
|
216
|
+
* 半径按底盘边长缓存 —— 键盘每 ~16ms 刷一次,不能每次都去读布局(会引发布局抖动);
|
|
217
|
+
* 换屏 / 旋转导致杆径变化时,边长对不上会自动重测。
|
|
218
|
+
*/
|
|
219
|
+
private paintStick;
|
|
220
|
+
/**
|
|
221
|
+
* 把「摇杆 + 键盘」合成后写进飞控 —— 唯一的 setStick 出口。
|
|
222
|
+
*
|
|
223
|
+
* 合成规则是**摇杆优先**:某根杆正被按住时,该杆的两个通道只听摇杆;
|
|
224
|
+
* 没被按住的杆才交给键盘。于是双指打杆时键盘不会来抢,松开手指后键盘又能接手。
|
|
225
|
+
* 偏航通道在这里统一乘 yawRateScale(真机挡位角速度在屏幕上偏快,见选项注释)。
|
|
226
|
+
*/
|
|
227
|
+
private applyStick;
|
|
228
|
+
private bindKeyboard;
|
|
229
|
+
private onKey;
|
|
230
|
+
/** 跑一个组合键动作:与点技能钮同一条路径,保证角标 / 计时 / 回调行为一致 */
|
|
231
|
+
private runShortcut;
|
|
232
|
+
/** 把按键状态渐推/渐回成行程;有变化才写飞控,静止时零开销 */
|
|
233
|
+
private tickKeyboard;
|
|
234
|
+
/** 松开全部键盘行程(失焦 / 销毁) */
|
|
235
|
+
private releaseKeyboard;
|
|
236
|
+
private stopKeyboard;
|
|
237
|
+
/** 两杆全部归零(销毁 / 外部打断时用) */
|
|
238
|
+
private releaseSticks;
|
|
239
|
+
/**
|
|
240
|
+
* 摇杆读数对齐引擎真值。正被按住的杆跳过 —— 它在跟手,回写会与用户输入打架。
|
|
241
|
+
*/
|
|
242
|
+
private syncStickReadout;
|
|
243
|
+
private stopTimer;
|
|
244
|
+
private renderPitch;
|
|
245
|
+
/**
|
|
246
|
+
* 下发速度倍率并同步两个控件。
|
|
247
|
+
*
|
|
248
|
+
* 真值以飞控为准(`sim.setSpeedScale` 内部夹到 0 ~ 1000),回写用夹紧后的值。
|
|
249
|
+
* ⚠️ 数字框**聚焦期间不回写**:归一化会抹掉用户刚敲的小数点("2." → "2"),
|
|
250
|
+
* 之后再敲 "5" 就成了 25;归一交给 change(失焦 / 回车)。
|
|
251
|
+
*/
|
|
252
|
+
private applySpeedScale;
|
|
253
|
+
/** 把倍率刷到滑杆与数字框上(轮询同步用;拖动滑杆 / 正在输入时跳过,免得和用户的手打架) */
|
|
254
|
+
private renderSpeedScale;
|
|
255
|
+
private setNote;
|
|
256
|
+
private handleAction;
|
|
257
|
+
private takePhoto;
|
|
258
|
+
/**
|
|
259
|
+
* 全景拍摄:点一次开始整组网格扫描,再点一次请求停止(见 `PanoramaCapture`)。
|
|
260
|
+
* 面板只负责挑会话与播报 —— 网格、逐张取景、方位复位都在库里,这里不碰渲染后端。
|
|
261
|
+
*/
|
|
262
|
+
private runPanorama;
|
|
263
|
+
private toggleRecording;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=drone-panel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drone-panel.d.ts","sourceRoot":"","sources":["../../src/lib/drone-camera/drone-panel.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,aAAa,CAAA;AAWxD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAQrD,qBAAqB;AACrB,MAAM,MAAM,kBAAkB,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,CAAA;AAE1F,6BAA6B;AAC7B,MAAM,WAAW,wBAAwB;IACvC,mDAAmD;IACnD,SAAS,CAAC,EAAE,WAAW,GAAG,IAAI,CAAA;IAC9B,kDAAkD;IAClD,QAAQ,CAAC,EAAE,kBAAkB,CAAA;IAC7B,mBAAmB;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,qBAAqB;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,gDAAgD;IAChD,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC;;;;;OAKG;IACH,cAAc,CAAC,EAAE,cAAc,CAAA;IAC/B,mDAAmD;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,2BAA2B;IAC3B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,iDAAiD;IACjD,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IACnD,8BAA8B;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,iDAAiD;IACjD,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,4DAA4D;IAC5D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gCAAgC;IAChC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,0BAA0B;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,wCAAwC;IACxC,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB;AA0eD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,iBAAiB;IAC5B,0BAA0B;IAC1B,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAA;IAC7B,0CAA0C;IAC1C,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAA;IAEjC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAgB;IACpC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAa;IACvC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAQ;IACjC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAQ;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAQ;IAC7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAS;IACzC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,0CAA0C;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAoB;IAChD,iCAAiC;IACjC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAK7B;IACD,OAAO,CAAC,aAAa,CAAsB;IAC3C,OAAO,CAAC,gBAAgB,CAAI;IAC5B,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAqBpB;IAED,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,aAAa,CAAQ;IAC7B,gCAAgC;IAChC,OAAO,CAAC,aAAa,CAAQ;IAC7B,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,SAAS,CAAQ;IACzB,+DAA+D;IAC/D,OAAO,CAAC,iBAAiB,CAAI;IAC7B,2BAA2B;IAC3B,OAAO,CAAC,QAAQ,CAA+B;IAC/C,OAAO,CAAC,aAAa,CAA4B;IACjD,8BAA8B;IAC9B,OAAO,CAAC,SAAS,CAAsB;IACvC,uBAAuB;IACvB,OAAO,CAAC,YAAY,CAAgC;IAEpD,2CAA2C;gBAC/B,GAAG,EAAE,cAAc,EAAE,OAAO,GAAE,wBAA6B;IA0FvE,iCAAiC;IACjC,KAAK,IAAI,IAAI;IAMb,2BAA2B;IAC3B,OAAO,IAAI,IAAI;IAMf,2BAA2B;IAC3B,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAOlC,aAAa;IACb,SAAS,IAAI,OAAO;IAIpB,6CAA6C;IAC7C,YAAY,CAAC,SAAS,EAAE,OAAO,GAAG,IAAI;IAMtC,2BAA2B;IAC3B,OAAO,IAAI,IAAI;IAiBf;;;OAGG;IACH,MAAM,CAAC,oBAAoB,IAAI,IAAI;IAOnC,8DAA8D;IAC9D,IAAI,IAAI,IAAI;IAyDZ,iDAAiD;IACjD,OAAO,CAAC,YAAY;IAcpB,yCAAyC;IACzC,OAAO,CAAC,aAAa;IAsCrB,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,OAAO;IAMf,4CAA4C;IAC5C,OAAO,CAAC,QAAQ;IA+FhB,uDAAuD;IACvD,OAAO,CAAC,WAAW;IAkCnB,8CAA8C;IAC9C,OAAO,CAAC,aAAa;IAwBrB,OAAO,CAAC,aAAa;IAqBrB,6CAA6C;IAC7C,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,IAAI;IA+DZ,OAAO,CAAC,UAAU;IAqBlB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,QAAQ;IAMhB,gDAAgD;IAChD,OAAO,CAAC,WAAW;IAyBnB,iDAAiD;IACjD,OAAO,CAAC,UAAU;IAYlB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAY3B;;;;OAIG;IACH,OAAO,CAAC,UAAU;IAoBlB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU;IAoBlB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,KAAK;IAwBb,6CAA6C;IAC7C,OAAO,CAAC,WAAW;IASnB,mCAAmC;IACnC,OAAO,CAAC,YAAY;IAgCpB,wBAAwB;IACxB,OAAO,CAAC,eAAe;IAcvB,OAAO,CAAC,YAAY;IAOpB,0BAA0B;IAC1B,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,WAAW;IAInB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAgBvB,mDAAmD;IACnD,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,OAAO;IAIf,OAAO,CAAC,YAAY;YAwFN,SAAS;IA0BvB;;;OAGG;YACW,WAAW;YAwCX,eAAe;CA0B9B"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 全景查看器(原生 DOM + 手写 WebGL):把等距柱状全景图**贴回球面**拖动环视 ——
|
|
3
|
+
* 一张平面的长条图,在这里变成能看四面八方的"球形照片"(真机相册里点开全景图的那种体验)。
|
|
4
|
+
*
|
|
5
|
+
* 为什么需要它:等距柱状图(2:1 长条)是全景的**存储格式**,不是**观看格式**。
|
|
6
|
+
* 一张 3600×1800 的条带摊在屏幕上看不出"四面八方";只要把它沿球面反投影,同一个文件
|
|
7
|
+
* 立刻变成可自由环视的球面 —— 这正是 DJI 相册打开球面全景时的做法。
|
|
8
|
+
*
|
|
9
|
+
* 三处刻意的设计:
|
|
10
|
+
*
|
|
11
|
+
* 1. **手写 WebGL,而不是引 three**。three 是库的 peerDependency,但影像集/查看器这一层
|
|
12
|
+
* 是"与渲染后端无关"的纯 DOM 模块(Cesium 宿主也在用)。为了看一张全景图把整个 three
|
|
13
|
+
* 拖进这条链路并不划算 —— 整件事只需要一个全屏三角形 + 一段反投影的片元着色器,
|
|
14
|
+
* 没有几何体、没有光照、没有材质。
|
|
15
|
+
*
|
|
16
|
+
* 2. **反投影用与 drone-stitch 完全相同的球面基**,两端必须同源才对得上:
|
|
17
|
+
* forward(θ,φ) = [sinθ·cosφ, sinφ, -cosθ·cosφ] θ 向右增、φ 为绝对仰角(天顶 +90°)
|
|
18
|
+
* u = (θ - thetaStart) / spanTheta, v = (phiTop - φ) / spanPhi
|
|
19
|
+
* 合成时是"球面方向 → 等距柱状像素",这里是"屏幕像素 → 球面方向 → 等距柱状像素"。
|
|
20
|
+
* 相机基 {right, up, forward} 由 θ/φ 直接构造(right = forward × ∂forward/∂φ,推导见
|
|
21
|
+
* `cameraBasis`),于是**拖动只是改两个标量**,没有欧拉角奇点、不用四元数/矩阵库。
|
|
22
|
+
*
|
|
23
|
+
* 3. **挂 `document.body` + 键盘走 window 捕获阶段**(与影像集、大图弹窗同一套约定):
|
|
24
|
+
* 面板的 `backdrop-filter` 会为 `position: fixed` 的后代换包含块;而面板的键盘飞行监听
|
|
25
|
+
* 挂在冒泡阶段,弹窗开着时按方向键必须只环视、绝不顺带把无人机飞出去。
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const viewer = new DronePanoramaViewer()
|
|
29
|
+
* viewer.open(result.url, '合成全景图') // 也接受合成结果对象
|
|
30
|
+
* viewer.close() // destroy() 彻底卸载
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
import type { PanoramaStitchResult } from './drone-panorama';
|
|
34
|
+
/** 全景查看器构造选项 */
|
|
35
|
+
export interface DronePanoramaViewerOptions {
|
|
36
|
+
/** 是否注入自带样式,默认 true */
|
|
37
|
+
injectStyles?: boolean;
|
|
38
|
+
/** 弹窗层级,默认 1100(排在影像集弹窗之上) */
|
|
39
|
+
zIndex?: number;
|
|
40
|
+
/** 初始朝向(方位角,度),默认 0 = 输出图正中(即该组的起始航向) */
|
|
41
|
+
initialYawDeg?: number;
|
|
42
|
+
/** 初始仰角(度),默认 0 = 平视 */
|
|
43
|
+
initialPitchDeg?: number;
|
|
44
|
+
/** 初始垂直视野角(度),默认 75 */
|
|
45
|
+
initialFovDeg?: number;
|
|
46
|
+
/** 垂直视野角上下限,默认 25 ~ 110 */
|
|
47
|
+
minFovDeg?: number;
|
|
48
|
+
maxFovDeg?: number;
|
|
49
|
+
/** 是否提供「下载原图」按钮,默认 true */
|
|
50
|
+
downloadable?: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* 是否提供「导入图片」按钮(从本地选一张等距柱状全景图看球面),默认 false。
|
|
53
|
+
* 影像集弹窗里已有自己的入口,那里不需要;独立打开的查看器(比如 demo 页的按钮)开着才方便。
|
|
54
|
+
*/
|
|
55
|
+
importable?: boolean;
|
|
56
|
+
/** 关闭回调(点 × / 点遮罩 / Esc) */
|
|
57
|
+
onClose?: () => void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* 全景查看器:一张带有球面投影范围的等距柱状图 + 可拖动环视的球面局部或整球。
|
|
61
|
+
*
|
|
62
|
+
* DOM **懒挂载**:构造只记住选项,首次 `open()` 才建节点、注入样式、建 WebGL 上下文;
|
|
63
|
+
* `close()` 把整棵 DOM 与 GL 资源一并拆掉,于是"没打开"时它对页面零影响。
|
|
64
|
+
*/
|
|
65
|
+
export declare class DronePanoramaViewer {
|
|
66
|
+
private readonly options;
|
|
67
|
+
private readonly minFov;
|
|
68
|
+
private readonly maxFov;
|
|
69
|
+
private root;
|
|
70
|
+
private refs;
|
|
71
|
+
private program;
|
|
72
|
+
private gl;
|
|
73
|
+
private observer;
|
|
74
|
+
private source;
|
|
75
|
+
private fileName;
|
|
76
|
+
/** 导入的本地文件对应的 blob 地址(换图 / destroy 时 revoke;close 不 revoke,重开要复用) */
|
|
77
|
+
private importUrl;
|
|
78
|
+
/** 导入文件的文件名(重开时用作标题) */
|
|
79
|
+
private importName;
|
|
80
|
+
private image;
|
|
81
|
+
private projection;
|
|
82
|
+
/** 图片加载序号:onload 回调是异步的,换图 / 关闭后旧回调必须作废 */
|
|
83
|
+
private loadSeq;
|
|
84
|
+
private ready;
|
|
85
|
+
/** 视角状态:两个标量就能完全描述朝向 */
|
|
86
|
+
private yaw;
|
|
87
|
+
private pitch;
|
|
88
|
+
private fov;
|
|
89
|
+
private readonly velocity;
|
|
90
|
+
private readonly pointers;
|
|
91
|
+
private lastPointer;
|
|
92
|
+
private pinchDistance;
|
|
93
|
+
private rafId;
|
|
94
|
+
private dirty;
|
|
95
|
+
private bodyOverflow;
|
|
96
|
+
private destroyed;
|
|
97
|
+
/** 构造球面全景查看器(手写 WebGL 零依赖;可传初始角与导入开关) */
|
|
98
|
+
constructor(options?: DronePanoramaViewerOptions);
|
|
99
|
+
/** 弹窗当前是否打开 */
|
|
100
|
+
get isOpen(): boolean;
|
|
101
|
+
/** 当前朝向(度),便于宿主做联动 */
|
|
102
|
+
get view(): {
|
|
103
|
+
yaw: number;
|
|
104
|
+
pitch: number;
|
|
105
|
+
fov: number;
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* 打开弹窗;`source` 是等距柱状全景图的地址(data URL / blob / http 均可)。
|
|
109
|
+
* 不传 = 只开一个"导入"入口(配 `importable` 用),选了图再进来。
|
|
110
|
+
*/
|
|
111
|
+
open(source?: string | PanoramaStitchResult, title?: string): void;
|
|
112
|
+
/** 关闭弹窗(整个卸载 DOM 并释放 GL 资源) */
|
|
113
|
+
close(): void;
|
|
114
|
+
/** 视角复位到初始状态 */
|
|
115
|
+
reset(): void;
|
|
116
|
+
/** 下载当前这张全景原图 */
|
|
117
|
+
download(): void;
|
|
118
|
+
/** 关闭弹窗并释放 GL 资源与 blob 地址 */
|
|
119
|
+
destroy(): void;
|
|
120
|
+
private mount;
|
|
121
|
+
private unmount;
|
|
122
|
+
private createContext;
|
|
123
|
+
private buildProgram;
|
|
124
|
+
private disposeGL;
|
|
125
|
+
private readonly onContextLost;
|
|
126
|
+
private readonly onContextRestored;
|
|
127
|
+
/** 把图片上传成纹理并开始渲染 */
|
|
128
|
+
private loadImage;
|
|
129
|
+
private uploadTexture;
|
|
130
|
+
/** 没有 WebGL 时的退路:直接把等距柱状长图铺出来(至少能看) */
|
|
131
|
+
private fallbackImage;
|
|
132
|
+
private setNote;
|
|
133
|
+
private syncSize;
|
|
134
|
+
private invalidate;
|
|
135
|
+
private schedule;
|
|
136
|
+
private readonly onFrame;
|
|
137
|
+
private draw;
|
|
138
|
+
private updateHud;
|
|
139
|
+
/** 用户从本地选了一张全景图:转 blob 地址喂给查看器(旧导入的地址一并释放) */
|
|
140
|
+
private readonly onImportFile;
|
|
141
|
+
private readonly onClick;
|
|
142
|
+
private readonly onPointerDown;
|
|
143
|
+
private readonly onPointerMove;
|
|
144
|
+
private readonly onPointerUp;
|
|
145
|
+
private readonly onWheel;
|
|
146
|
+
private readonly onDoubleClick;
|
|
147
|
+
private readonly onKeyDown;
|
|
148
|
+
/**
|
|
149
|
+
* 拖动换算:一屏高恰好对应一个垂直视野,于是"每像素转多少度"= fov / 画布高。
|
|
150
|
+
* 视野越小(放得越大)拖得越慢,手感与真机一致。
|
|
151
|
+
* 符号按"抓住画面拖"约定:右拖 = 画面右移 = 视线左转,下拖 = 画面下移 = 视线抬高。
|
|
152
|
+
*/
|
|
153
|
+
private rotateBy;
|
|
154
|
+
private zoomBy;
|
|
155
|
+
private currentPinchDistance;
|
|
156
|
+
private lockScroll;
|
|
157
|
+
private unlockScroll;
|
|
158
|
+
private slug;
|
|
159
|
+
private query;
|
|
160
|
+
private template;
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=drone-panorama-viewer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drone-panorama-viewer.d.ts","sourceRoot":"","sources":["../../src/lib/drone-camera/drone-panorama-viewer.ts"],"names":[],"mappings":"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"}
|