地表附近支持右键环视(以点击点为球心,松开归位)
This commit is contained in:
@@ -114,6 +114,10 @@ function makeStickyNote(text, fontSize, selected = false) {
|
||||
return { canvas: c, scale: 1 / S, width: cw, height: ch, tipX: B, tipY: B + h / 2 };
|
||||
}
|
||||
|
||||
// 右键“环视”手势:放大到地表附近时,右键拖动以点击点为球心环视,松开归位
|
||||
const LOOK_GROUND_MAX_HEIGHT = 1e6; // 相机高度低于 1000 km 才启用
|
||||
const LOOK_RATE = 0.005; // 每像素旋转弧度
|
||||
|
||||
export class CesiumGlobe {
|
||||
constructor({ onPick } = {}) {
|
||||
this.onPick = onPick;
|
||||
@@ -250,6 +254,7 @@ export class CesiumGlobe {
|
||||
|
||||
this._buildMarkers();
|
||||
this._setupPick();
|
||||
this._setupLookAround();
|
||||
this._loadBoundaries();
|
||||
this._buildCityLabels();
|
||||
|
||||
@@ -350,6 +355,98 @@ export class CesiumGlobe {
|
||||
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
|
||||
}
|
||||
|
||||
// 右键环视:地表附近右键拖动,以点击点为球心调整视角,松开归位
|
||||
_setupLookAround() {
|
||||
const viewer = this.viewer;
|
||||
const scene = viewer.scene;
|
||||
const camera = viewer.camera;
|
||||
this._lookState = null;
|
||||
this._orbitScratch = {
|
||||
offset: new Cesium.Cartesian3(),
|
||||
up: new Cesium.Cartesian3(),
|
||||
right: new Cesium.Cartesian3(),
|
||||
qAz: new Cesium.Quaternion(),
|
||||
qEl: new Cesium.Quaternion(),
|
||||
q: new Cesium.Quaternion(),
|
||||
rotMat: new Cesium.Matrix3(),
|
||||
newOffset: new Cesium.Cartesian3(),
|
||||
newPos: new Cesium.Cartesian3(),
|
||||
dir: new Cesium.Cartesian3(),
|
||||
upProj: new Cesium.Cartesian3(),
|
||||
};
|
||||
|
||||
const handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
|
||||
|
||||
handler.setInputAction((movement) => {
|
||||
if (camera.positionCartographic.height > LOOK_GROUND_MAX_HEIGHT) return;
|
||||
const position =
|
||||
scene.pickPosition(movement.position) ||
|
||||
camera.pickEllipsoid(movement.position, scene.globe.ellipsoid);
|
||||
if (!Cesium.defined(position)) return;
|
||||
this._lookState = {
|
||||
pivot: Cesium.Cartesian3.clone(position),
|
||||
position: Cesium.Cartesian3.clone(camera.position),
|
||||
direction: Cesium.Cartesian3.clone(camera.direction),
|
||||
up: Cesium.Cartesian3.clone(camera.up),
|
||||
lastX: movement.position.x,
|
||||
lastY: movement.position.y,
|
||||
};
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_DOWN);
|
||||
|
||||
handler.setInputAction((movement) => {
|
||||
if (!this._lookState) return;
|
||||
const s = this._lookState;
|
||||
const dx = movement.position.x - s.lastX;
|
||||
const dy = movement.position.y - s.lastY;
|
||||
s.lastX = movement.position.x;
|
||||
s.lastY = movement.position.y;
|
||||
this._orbitAroundPivot(s.pivot, dx * LOOK_RATE, dy * LOOK_RATE);
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_DRAG);
|
||||
|
||||
handler.setInputAction(() => {
|
||||
if (!this._lookState) return;
|
||||
const s = this._lookState;
|
||||
camera.setView({
|
||||
destination: s.position,
|
||||
orientation: { direction: s.direction, up: s.up },
|
||||
});
|
||||
this._lookState = null;
|
||||
}, Cesium.ScreenSpaceEventType.RIGHT_UP);
|
||||
|
||||
this._lookHandler = handler;
|
||||
}
|
||||
|
||||
// 围绕 pivot 旋转相机(水平=方位角,垂直=俯仰角)
|
||||
_orbitAroundPivot(pivot, dAzimuth, dElevation) {
|
||||
const camera = this.viewer.camera;
|
||||
const s = this._orbitScratch;
|
||||
const offset = Cesium.Cartesian3.subtract(camera.position, pivot, s.offset);
|
||||
const up = Cesium.Cartesian3.normalize(pivot, s.up); // 球心在原点,pivot 方向即法线
|
||||
const right = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.cross(camera.direction, camera.up, s.right),
|
||||
s.right,
|
||||
);
|
||||
Cesium.Quaternion.fromAxisAngle(up, -dAzimuth, s.qAz);
|
||||
Cesium.Quaternion.fromAxisAngle(right, -dElevation, s.qEl);
|
||||
Cesium.Quaternion.multiply(s.qEl, s.qAz, s.q);
|
||||
Cesium.Matrix3.fromQuaternion(s.q, s.rotMat);
|
||||
Cesium.Matrix3.multiplyByVector(s.rotMat, offset, s.newOffset);
|
||||
Cesium.Cartesian3.add(pivot, s.newOffset, s.newPos);
|
||||
const dir = Cesium.Cartesian3.normalize(
|
||||
Cesium.Cartesian3.subtract(pivot, s.newPos, s.dir),
|
||||
s.dir,
|
||||
);
|
||||
const zDotDir = dir.z;
|
||||
s.upProj.x = -dir.x * zDotDir;
|
||||
s.upProj.y = -dir.y * zDotDir;
|
||||
s.upProj.z = 1 - zDotDir * zDotDir;
|
||||
Cesium.Cartesian3.normalize(s.upProj, s.upProj);
|
||||
camera.setView({
|
||||
destination: s.newPos,
|
||||
orientation: { direction: dir, up: s.upProj },
|
||||
});
|
||||
}
|
||||
|
||||
// 相机平滑飞至某个标记上空并居中:回到与初始一致的高度与北朝上方向,左键拖拽手感不变
|
||||
flyToEntry(index) {
|
||||
const entry = ENTRIES[index];
|
||||
|
||||
Reference in New Issue
Block a user