动态创建的 CesiumJS 引脚未在查看器中实时更新

CesiumJS Pins Created Dynamically Not Updating in Real-Time in Viewer

提问人:Pratik Singh 提问时间:10/29/2023 更新时间:10/29/2023 访问量:19

问:

我在使用基于 CesiumJS 的地图应用程序时遇到了问题。我有一个自定义库,它利用 CesiumJS 在地图上创建图钉。这些引脚已成功创建,并且我能够通过设置 setPinCreationCallback 函数动态获取纬度和经度值。但是,尽管图钉已成功创建,但它们不会立即反映在查看器中。

**Pin Manager Class**

    import * as Cesium from "cesium";
import { createPin } from "./utils/PinUtility";
import {
  PinManagerInterface,
  PinOptions,
  PinCreationCallback,
} from "./interfaces/PinManagerInterfaces";
import { ViewerInterface } from "./interfaces/RuasViewerInterfaces";

export class PinManager implements PinManagerInterface {
  private _pinBuilder: Cesium.PinBuilder;
  private _isHandlerAttached: boolean = false;
  private _clickHandler: Cesium.ScreenSpaceEventHandler | null = null;
  private _loadedPins: Cesium.Entity[] = [];
  private _pinCreationCallback: PinCreationCallback | null = null;

  constructor() {
    this._pinBuilder = new Cesium.PinBuilder();
  }

  public enablePinCreation(ruasViewer: ViewerInterface): void {
    if (!this._isHandlerAttached) {
      this._clickHandler = new Cesium.ScreenSpaceEventHandler(
        ruasViewer.getViewer().scene.canvas
      );

      this._clickHandler.setInputAction((movement: any) => {
        this.handlePinCreation(ruasViewer, movement);
      }, Cesium.ScreenSpaceEventType.LEFT_CLICK);

      this._isHandlerAttached = true;
    }
  }

  public disablePinCreation(): void {
    if (this._isHandlerAttached && this._clickHandler !== null) {
      this._clickHandler.destroy();
      this._isHandlerAttached = false;
    }
  }

  // Method to create pins for an array of locations
  public createPins(ruasViewer: ViewerInterface, locations: PinOptions[]): void {
    // Clear existing pins before adding new ones
    this.clearPins(ruasViewer);
    locations.forEach((location) => {
      const pinEntity = createPin(
        ruasViewer.getViewer(),
        this._pinBuilder,
        location
      );
      this._loadedPins.push(pinEntity);
      ruasViewer.requestRender();
    });
  }

  // Method to clear all pins from the viewer
  public clearPins(ruasViewer: ViewerInterface): void {
    // Remove pins from the viewer's entities collection
    this._loadedPins.forEach((pin) => {
      ruasViewer.getViewer().entities.remove(pin);
    });
    // Clear the internal data structures
    this._loadedPins = [];
  }

  public setPinCreationCallback(callback: PinCreationCallback): void {
    this._pinCreationCallback = callback;
  }

  private notifyPinCreation(latitude: number, longitude: number): void {
    if (this._pinCreationCallback) {
      this._pinCreationCallback(latitude, longitude);
    }
  }

  public handlePinCreation(ruasViewer: ViewerInterface, movement: any): void {
    // Check if movement contains a valid position
    if (movement && movement.position) {
      const windowPosition = movement.position;
      const ray = ruasViewer.getViewer().camera.getPickRay(windowPosition);

      // Ensure ray is defined before proceeding
      if (Cesium.defined(ray)) {
        const clickedPosition = ruasViewer
          .getViewer()
          .scene.globe.pick(ray, ruasViewer.getViewer().scene);

        if (Cesium.defined(clickedPosition)) {
          // Notify the callback function with clickedPosition
          const cartographicPosition =
            Cesium.Cartographic.fromCartesian(clickedPosition);
          const latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
          const longitude = Cesium.Math.toDegrees(
            cartographicPosition.longitude
          );

          this.notifyPinCreation(latitude, longitude);

          const pinOptions: PinOptions[] = [{ latitude, longitude }];

          // Clear existing pins and create new pins based on pinOptions
          this.createPins(ruasViewer, pinOptions);
          // Request a render update to see the changes
          ruasViewer.getViewer().scene.requestRender();
        }
      }
    } else {
      console.error("Invalid movement or position");
    }
  }
}

**PinsViewer Component:**

// Import necessary modules and dependencies
import React, { useEffect, useRef } from "react";
import { useDispatch } from "react-redux";
import { setViewer } from "../../redux/features/viewer/viewerSlice";
import { useCesiumViewer } from "../../hooks/useCesiumViewer";
import { Location } from "../../interfaces/project.interface";

// Define the props expected by the PinsViewer component
interface PinsViewerProps {
  location?: Location[];
  setLocation?: React.Dispatch<React.SetStateAction<Location>>; // Function to set location state
}

// Create the PinsViewer React functional component
const PinsViewer: React.FC<PinsViewerProps> = ({ location, setLocation }) => {
  // Initialize Redux dispatch
  const dispatch = useDispatch();

  // Create a reference to the viewer container div
  const viewerRef = useRef<HTMLDivElement>(null); // Unique ID for the viewer container

  // Use the useCesiumViewer hook to obtain the viewer and pinManager
  const { viewer, pinManager } = useCesiumViewer("pinsViewer");

  // Set up the effect to manage pins and update the viewer
  useEffect(() => {
    if (viewer && pinManager) {
      if (location?.length && location[0].latitude && location[0].longitude) {
        pinManager.createPins(viewer, location);
        pinManager.enablePinCreation(viewer);
        // Create pins and set up a pin creation callback
        pinManager.setPinCreationCallback(
          (latitude: number, longitude: number) => {
            pinManager.createPins(viewer, [{ latitude, longitude, height: 0 }]);
            if (setLocation) {
              setLocation({ ...location, latitude, longitude, height: 0 });
            }
          },
        );
      } else if (location) {
        // location.latitude is 0
        pinManager.enablePinCreation(viewer);
        pinManager.setPinCreationCallback(
          (latitude: number, longitude: number) => {
            if (setLocation) {
              setLocation({ ...location, latitude, longitude, height: 0 });
            }
          },
        );
      }
    }

    // Dispatch the initialized viewer to Redux state
    dispatch(setViewer(viewer));
  }, [viewer, pinManager, location, setLocation, dispatch]);

  return <div ref={viewerRef} id="pinsViewer"></div>;
};

export default PinsViewer;

问题:在我的 PinsViewer 组件中,我使用 pinManager.setPinCreationCallback 函数在用户单击地图时动态创建图钉。引脚创建成功,并正确获取纬度和经度值。但是,这些图钉不会在查看器中实时更新。只有当我摇晃地图或手动移动地球时,查看器才会更新。

预期行为:

我希望图钉在创建后立即在查看器中更新,而无需进行手动交互,例如摇晃地图或移动地球

尝试解决:

  1. 手动查看器更新:我尝试调用viewer.scene.requestRender() 创建图钉后,但这并不能解决问题。
  2. 检查内部实现:我验证了内部 在我的库中实现 createPins 函数。引脚 已成功创建,但查看器未反映更改 立即。

问题:

CesiumJS 中是否有我应该使用的特定方法或更新函数来确保在我的库中创建的引脚立即反映在查看器中,而无需手动交互?此外,我的 React 应用程序中是否缺少任何特定的配置或设置,尤其是与使用 webpack 集成 CesiumJS 相关的配置或设置?

我正在寻找一种解决方案,可以在创建引脚后立即在查看器中进行实时更新。

对此问题的任何帮助或指导将不胜感激。谢谢!

reactjs react-hooks webpack-5 铯JS

评论


答: 暂无答案