Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

Commit

Permalink
fix: camera property panel bugs (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
rot1024 committed Oct 5, 2021
1 parent 15df163 commit 2c3eaab
Show file tree
Hide file tree
Showing 8 changed files with 137 additions and 87 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,24 +6,24 @@ import { Camera } from "@reearth/util/value";

type Params = {
cameraValue: Camera | undefined;
onSubmit?: (value: Camera) => void;
isCapturing?: boolean;
onIsCapturingChange?: (isCapturing: boolean) => void;
cameraState?: Camera;
onCameraChange?: (camera: Partial<Camera>) => void;
disabled?: boolean;
onlyPose?: boolean;
onSubmit?: (value: Camera) => void;
onIsCapturingChange?: (isCapturing: boolean) => void;
onCameraChange?: (camera: Partial<Camera>) => void;
};

export default ({
cameraValue,
onSubmit,
isCapturing,
onIsCapturingChange,
cameraState,
onCameraChange,
disabled,
onlyPose,
onSubmit,
onIsCapturingChange,
onCameraChange,
}: Params) => {
const camera = isCapturing ? cameraState : cameraValue;
const [open, setOpen] = useState(false);
Expand All @@ -32,6 +32,7 @@ export default ({
const closePopup = useCallback(() => setOpen(false), [setOpen]);

const wrapperRef = useRef<HTMLDivElement>(null);
const initCamera = useRef<Camera>();
const cameraWrapperRef = useRef<HTMLDivElement>(null);
const popperRef = useRef<HTMLUListElement>(null);
const { styles, attributes } = usePopper(cameraWrapperRef.current, popperRef.current, {
Expand Down Expand Up @@ -60,13 +61,15 @@ export default ({

const startCapture = useCallback(() => {
if (disabled) return;
initCamera.current = cameraState;
openPopup();
onIsCapturingChange?.(true);
}, [disabled, onIsCapturingChange, openPopup]);
}, [cameraState, disabled, onIsCapturingChange, openPopup]);

const finishCapture = useCallback(() => {
closePopup();
onIsCapturingChange?.(false);
initCamera.current = undefined;
}, [closePopup, onIsCapturingChange]);

const updateCamera = useCallback(
Expand All @@ -75,8 +78,11 @@ export default ({
);

const cancelCapture = useCallback(() => {
if (initCamera.current) {
updateCamera(initCamera.current);
}
finishCapture();
}, [finishCapture]);
}, [finishCapture, updateCamera]);

const submitCapture = useCallback(() => {
if (disabled) return;
Expand Down Expand Up @@ -108,17 +114,20 @@ export default ({
);

const handleHeadingChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => updateCamera({ heading: Number(e.target.value) }),
(e: React.ChangeEvent<HTMLInputElement>) =>
updateCamera({ heading: (Number(e.target.value) * Math.PI) / 180 }),
[updateCamera],
);

const handlePitchChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => updateCamera({ pitch: Number(e.target.value) }),
(e: React.ChangeEvent<HTMLInputElement>) =>
updateCamera({ pitch: (Number(e.target.value) * Math.PI) / 180 }),
[updateCamera],
);

const handleRollChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement>) => updateCamera({ roll: Number(e.target.value) }),
(e: React.ChangeEvent<HTMLInputElement>) =>
updateCamera({ roll: (Number(e.target.value) * Math.PI) / 180 }),
[updateCamera],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ import useHooks from "./hooks";
export type Props = FieldProps<Camera> & {
onDelete?: () => void;
isCapturing?: boolean;
onIsCapturingChange?: (isCapturing: boolean) => void;
camera?: Camera;
onCameraChange?: (camera: Partial<Camera>) => void;
onlyPose?: boolean;
onIsCapturingChange?: (isCapturing: boolean) => void;
onCameraChange?: (camera: Partial<Camera>) => void;
};

const CameraField: React.FC<Props> = ({
Expand Down Expand Up @@ -61,12 +61,21 @@ const CameraField: React.FC<Props> = ({
onlyPose,
});

const lat = camera?.lat && Math.round(camera?.lat * 1000) / 1000;
const lng = camera?.lng && Math.round(camera?.lng * 1000) / 1000;
const height = camera?.height && Math.round(camera?.height);
const heading = camera?.heading && Math.round(camera?.heading * 1000) / 1000;
const pitch = camera?.pitch && Math.round(camera?.pitch * 1000) / 1000;
const roll = camera?.roll && Math.round(camera?.roll * 1000) / 1000;
const lat = typeof camera?.lat === "number" ? Math.round(camera?.lat * 1000) / 1000 : "";
const lng = typeof camera?.lng === "number" ? Math.round(camera?.lng * 1000) / 1000 : "";
const height = typeof camera?.height === "number" ? Math.round(camera?.height) : "";
const heading =
typeof camera?.heading === "number"
? Math.round(((camera?.heading * 180) / Math.PI) * 1000) / 1000
: "";
const pitch =
typeof camera?.pitch === "number"
? Math.round(((camera?.pitch * 180) / Math.PI) * 1000) / 1000
: "";
const roll =
typeof camera?.roll === "number"
? Math.round(((camera?.roll * 180) / Math.PI) * 1000) / 1000
: "";
const theme = useTheme();
return (
<Wrapper ref={wrapperRef} onClick={value ? undefined : startCapture} data-camera-popup>
Expand Down Expand Up @@ -94,13 +103,25 @@ const CameraField: React.FC<Props> = ({
<FormFieldGroup>
<FormFieldRow>
<FormWrapper>
<Input type="number" value={lat} onChange={handleLatChange} />
<Input
type="number"
value={lat}
step={0.01}
readOnly={!isCapturing}
onChange={handleLatChange}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Latitude" })}
</FloatText>
</FormWrapper>
<FormWrapper>
<Input type="number" value={lng} onChange={handleLngChange} />
<Input
type="number"
value={lng}
step={0.01}
readOnly={!isCapturing}
onChange={handleLngChange}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Longtitude" })}
</FloatText>
Expand All @@ -109,8 +130,9 @@ const CameraField: React.FC<Props> = ({
<Input
type="number"
value={height}
step={1000}
readOnly={!isCapturing}
onChange={handleAltitudeChange}
step={10 ** 6}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Altitude" })}
Expand All @@ -125,19 +147,37 @@ const CameraField: React.FC<Props> = ({
<FormFieldGroup>
<FormFieldRow>
<FormWrapper>
<Input type="number" value={heading} onChange={handleHeadingChange} step="0.01" />
<Input
type="number"
value={heading}
step={1}
readOnly={!isCapturing}
onChange={handleHeadingChange}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Heading" })}
</FloatText>
</FormWrapper>
<FormWrapper>
<Input type="number" value={pitch} onChange={handlePitchChange} step="0.01" />
<Input
type="number"
value={pitch}
step={1}
readOnly={!isCapturing}
onChange={handlePitchChange}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Pitch" })}
</FloatText>
</FormWrapper>
<FormWrapper>
<Input type="number" value={roll} onChange={handleRollChange} step="0.01" />
<Input
type="number"
value={roll}
step={1}
readOnly={!isCapturing}
onChange={handleRollChange}
/>
<FloatText size="2xs" color={theme.properties.contentsFloatText}>
{intl.formatMessage({ defaultMessage: "Roll" })}
</FloatText>
Expand Down
29 changes: 0 additions & 29 deletions src/components/molecules/Visualizer/Engine/Cesium/CameraFlyTo.tsx

This file was deleted.

15 changes: 15 additions & 0 deletions src/components/molecules/Visualizer/Engine/Cesium/Event.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useEffect } from "react";

export type Props = {
onMount?: () => void;
onUnmount?: () => void;
};

export default function Event({ onMount, onUnmount }: Props) {
useEffect(() => {
onMount?.();
return () => onUnmount?.();
}, [onMount, onUnmount]);

return null;
}
39 changes: 26 additions & 13 deletions src/components/molecules/Visualizer/Engine/Cesium/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,20 +85,24 @@ export default ({
// move to initial position at startup
const initialCameraFlight = useRef(false);

useEffect(() => {
if (!property?.default?.camera || initialCameraFlight.current) return;
const handleMount = useCallback(() => {
if (initialCameraFlight.current) return;
initialCameraFlight.current = true;
engineAPI.flyTo(property.default.camera, { duration: 0 });
}, [engineAPI, property?.default?.camera]);

useEffect(() => {
if (initialCameraFlight.current && !property) {
initialCameraFlight.current = false;
if (property?.default?.camera) {
engineAPI.flyTo(property.default.camera, { duration: 0 });
}
const camera = getCamera(cesium?.current?.cesiumElement);
if (camera) {
onCameraChange?.(camera);
}
}, [property]);
}, [engineAPI, onCameraChange, property?.default?.camera]);

const handleUnmount = useCallback(() => {
initialCameraFlight.current = false;
}, []);

// call onCameraChange event after moving camera
const onCameraMoveEnd = useCallback(() => {
const handleCameraMoveEnd = useCallback(() => {
const viewer = cesium?.current?.cesiumElement;
if (!viewer || viewer.isDestroyed()) return;

Expand All @@ -108,6 +112,13 @@ export default ({
}
}, [onCameraChange, camera]);

// camera
useEffect(() => {
if (camera) {
engineAPI.flyTo(camera, { duration: 0 });
}
}, [camera, engineAPI]);

// manage layer selection
useEffect(() => {
const viewer = cesium.current?.cesiumElement;
Expand All @@ -119,7 +130,7 @@ export default ({
viewer.selectedEntity = entity;
}, [cesium, selectedLayerId]);

const onClick = useCallback(
const handleClick = useCallback(
(_: CesiumMovementEvent, target: RootEventTarget) => {
const viewer = cesium.current?.cesiumElement;
if (!viewer || viewer.isDestroyed()) return;
Expand Down Expand Up @@ -171,8 +182,10 @@ export default ({
backgroundColor,
imageryLayers,
cesium,
onClick,
onCameraMoveEnd,
handleMount,
handleUnmount,
handleClick,
handleCameraMoveEnd,
};
};

Expand Down
32 changes: 21 additions & 11 deletions src/components/molecules/Visualizer/Engine/Cesium/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {

import type { EngineProps, Ref as EngineRef } from "..";

import Event from "./Event";
import useHooks from "./hooks";

export type { EngineProps as Props } from "..";
Expand All @@ -36,15 +37,23 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
},
ref,
) => {
const { terrainProvider, backgroundColor, imageryLayers, cesium, onClick, onCameraMoveEnd } =
useHooks({
ref,
property,
camera,
selectedLayerId,
onLayerSelect,
onCameraChange,
});
const {
terrainProvider,
backgroundColor,
imageryLayers,
cesium,
handleMount,
handleUnmount,
handleClick,
handleCameraMoveEnd,
} = useHooks({
ref,
property,
camera,
selectedLayerId,
onLayerSelect,
onCameraChange,
});

return (
<>
Expand Down Expand Up @@ -72,13 +81,14 @@ const Cesium: React.ForwardRefRenderFunction<EngineRef, EngineProps> = (
requestRenderMode={!property?.timeline?.animation}
maximumRenderTimeChange={property?.timeline?.animation ? undefined : Infinity}
shadows={!!property?.atmosphere?.shadows}
onClick={onClick}>
onClick={handleClick}>
<Event onMount={handleMount} onUnmount={handleUnmount} />
<Clock shouldAnimate={!!property?.timeline?.animation} />
<ScreenSpaceEventHandler useDefault>
{/* remove default double click event */}
<ScreenSpaceEvent type={ScreenSpaceEventType.LEFT_DOUBLE_CLICK} />
</ScreenSpaceEventHandler>
<Camera onChange={onCameraMoveEnd} />
<Camera onChange={handleCameraMoveEnd} />
<Scene backgroundColor={backgroundColor} />
<SkyBox show={property?.default?.skybox ?? true} />
<Fog
Expand Down

0 comments on commit 2c3eaab

Please sign in to comment.