容器首帧无尺寸时按真实比例重算取景
- 取景原先只在加载完成时按 measureViewport() 的宽高比算一次,隐藏面板里挂载时只能拿到方形兜底值 - 抽出 computeFraming(aspect),ResizeObserver 首次量到非零尺寸后按真实比例重算并复位一次,之后不再覆盖用户的缩放
This commit is contained in:
@@ -272,25 +272,34 @@ export async function createModel3dViewerScene(
|
||||
abortIfNeeded();
|
||||
|
||||
const bounds = new THREE.Box3().setFromObject(model3d);
|
||||
const size = measureViewport();
|
||||
const fitBox = {
|
||||
min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z },
|
||||
max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z },
|
||||
};
|
||||
const fitCenter = computeModel3dViewerBoxCenter(fitBox);
|
||||
const fitSolver = createModel3dViewerFitSolver({
|
||||
center: fitCenter,
|
||||
aspect: size.aspect,
|
||||
fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
|
||||
fallbackRadius: computeModel3dViewerBoxRadius(fitBox),
|
||||
});
|
||||
feedModel3dViewerFitSolver(model3d, (x, y, z) => fitSolver.add(x, y, z));
|
||||
const framing = computeModel3dViewerFraming({
|
||||
box: fitBox,
|
||||
aspect: size.aspect,
|
||||
fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
|
||||
distance: fitSolver.resolve(),
|
||||
});
|
||||
const viewport = measureViewport();
|
||||
|
||||
/**
|
||||
* 按给定宽高比重算取景。容器在隐藏面板里挂载时首帧量不到尺寸,只能先按方形兜底,
|
||||
* 等容器真正有尺寸后必须用真实比例重算,否则模型会按方形取景、被裁掉或显得过小。
|
||||
*/
|
||||
function computeFraming(aspect: number) {
|
||||
const fitBox = {
|
||||
min: { x: bounds.min.x, y: bounds.min.y, z: bounds.min.z },
|
||||
max: { x: bounds.max.x, y: bounds.max.y, z: bounds.max.z },
|
||||
};
|
||||
const fitSolver = createModel3dViewerFitSolver({
|
||||
center: computeModel3dViewerBoxCenter(fitBox),
|
||||
aspect,
|
||||
fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
|
||||
fallbackRadius: computeModel3dViewerBoxRadius(fitBox),
|
||||
});
|
||||
feedModel3dViewerFitSolver(model3d, (x, y, z) => fitSolver.add(x, y, z));
|
||||
return computeModel3dViewerFraming({
|
||||
box: fitBox,
|
||||
aspect,
|
||||
fovDegrees: MODEL3D_VIEWER_CAMERA_FOV_DEGREES,
|
||||
distance: fitSolver.resolve(),
|
||||
});
|
||||
}
|
||||
|
||||
let framing = computeFraming(viewport.aspect);
|
||||
let hasFramedViewport = viewport.width > 0 && viewport.height > 0;
|
||||
|
||||
function measureViewport(): {
|
||||
width: number;
|
||||
@@ -342,6 +351,17 @@ export async function createModel3dViewerScene(
|
||||
if (typeof ResizeObserver !== 'undefined') {
|
||||
resizeObserver = new ResizeObserver(() => {
|
||||
applyViewport();
|
||||
if (disposed || hasFramedViewport) {
|
||||
return;
|
||||
}
|
||||
// 首次拿到非零尺寸:按真实比例重算取景并复位,用户此后的缩放不再被覆盖。
|
||||
const current = measureViewport();
|
||||
if (current.width === 0 || current.height === 0) {
|
||||
return;
|
||||
}
|
||||
hasFramedViewport = true;
|
||||
framing = computeFraming(current.aspect);
|
||||
resetView();
|
||||
});
|
||||
resizeObserver.observe(container);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user