You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Resium(Cesium-React)实现相机跟踪目标时保持自定义缩放高度

问题描述

我有一个基于Resium的React组件,相机可以根据数据动态移动。当前代码能跟踪目标点,但每次更新时都会重置相机高度。我想实现跟踪目标点的同时允许自由缩放,且不重置相机高度,请问该怎么修改?

原代码如下:

const imgProvider = new OpenStreetMapImageryProvider({ url : 'https://a.tile.openstreetmap.org/' });
function TrackingMap(props) {
  const [data, setData] = React.useState({longitude: 4.3571, latitude: 52.0116});
  const startCoordinates = Cartesian3.fromDegrees(data.longitude, data.latitude, 10000);
  const pointCoordinates = Cartesian3.fromDegrees(data.longitude, data.latitude, 0);
  function move() {
    setData((old) => {
      return {longitude: old.longitude+0.00025, latitude: old.latitude};
    })
  }
  setTimeout(move, 200);
  return <div>
    <Viewer full resolutionScale={0.5} baseLayerPicker={true} fullscreenButton={false} homeButton={false} sceneModePicker={true} selectionIndicator={true} timeline={false} animation={false} geocoder={false} imageryProvider={imgProvider} >
      <Camera />
      <CameraFlyTo destination={startCoordinates} duration={0} />
    </Viewer>
  </div>
}
解决方案

你的核心问题有两个:一是每次用<CameraFlyTo>时硬编码了固定高度(10000),导致更新时强制重置高度;二是setTimeout直接放在组件函数里,会在每次渲染时都创建新的定时器,导致数据更新过于频繁且不可控。

下面是修改后的代码,我会逐一解释关键改动:

import { Cartesian3, Viewer, Camera, OpenStreetMapImageryProvider } from 'resium';
import React, { useState, useEffect, useRef } from 'react';

const imgProvider = new OpenStreetMapImageryProvider({ url: 'https://a.tile.openstreetmap.org/' });

function TrackingMap(props) {
  const [data, setData] = useState({ longitude: 4.3571, latitude: 52.0116 });
  // 保存相机实例的ref,用于获取当前相机的状态
  const cameraRef = useRef(null);
  // 保存定时器ID,用于清理
  const timerRef = useRef(null);

  // 处理定时移动逻辑,用useEffect确保只在组件挂载时启动一次
  useEffect(() => {
    timerRef.current = setInterval(() => {
      setData(old => ({
        longitude: old.longitude + 0.00025,
        latitude: old.latitude
      }));
    }, 200);

    // 组件卸载时清理定时器
    return () => clearInterval(timerRef.current);
  }, []);

  // 当目标点更新时,调整相机位置但保留当前高度
  useEffect(() => {
    if (!cameraRef.current) return;

    const camera = cameraRef.current;
    // 获取当前相机的高度(从椭球面到相机的距离)
    const currentHeight = Cartesian3.magnitude(camera.position);
    
    // 计算新的目标位置:使用更新后的经纬度,保留当前高度
    const newDestination = Cartesian3.fromDegrees(data.longitude, data.latitude, currentHeight);
    
    // 平滑移动相机,duration可以根据需求调整,设为0就是瞬间移动
    camera.flyTo({
      destination: newDestination,
      duration: 0.2, // 稍微加一点动画会更自然,不需要可以设为0
      easingFunction: Cesium.EasingFunction.LINEAR
    });
  }, [data]);

  return (
    <div>
      <Viewer
        full
        resolutionScale={0.5}
        baseLayerPicker={true}
        fullscreenButton={false}
        homeButton={false}
        sceneModePicker={true}
        selectionIndicator={true}
        timeline={false}
        animation={false}
        geocoder={false}
        imageryProvider={imgProvider}
      >
        {/* 通过ref获取相机实例 */}
        <Camera ref={cameraRef} />
        {/* 移除原来的CameraFlyTo组件,改用手动控制相机 */}
      </Viewer>
    </div>
  );
}

export default TrackingMap;

关键改动说明:

  • 使用useRef保存相机实例:通过<Camera ref={cameraRef}>获取相机对象,这样我们能随时读取当前相机的位置和高度,而不是每次都用固定值。
  • 用setInterval替代重复的setTimeout:把定时逻辑放在useEffect里,确保组件挂载时只启动一次定时器,避免每次渲染都创建新的定时器导致数据疯狂更新,同时在组件卸载时清理定时器防止内存泄漏。
  • 动态保留当前相机高度:当目标点data更新时,先获取当前相机的高度(通过Cartesian3.magnitude(camera.position)计算),然后用这个高度构建新的目标位置,这样缩放后的高度就会被保留。
  • 手动调用相机的flyTo方法:不再依赖<CameraFlyTo>组件(它每次渲染都会触发一次飞行动作,容易覆盖手动调整的状态),而是直接调用相机实例的flyTo方法,更灵活地控制相机行为。

这样修改后,你就能实现:目标点移动时相机自动跟踪,同时手动缩放调整的高度会被保留,不会被强制重置。

内容的提问来源于stack exchange,提问作者paul23

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 11:22:54