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

Commit

Permalink
feat: support 2d mode in navigator (#360)
Browse files Browse the repository at this point in the history
* feat: support 2d mode in navigator

* fix: use smooth zoom and support columbus mode

* test: add test for 2d
  • Loading branch information
keiya01 committed Dec 13, 2022
1 parent 0dd63e6 commit 595dd53
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 52 deletions.
10 changes: 9 additions & 1 deletion src/components/molecules/Visualizer/Engine/Cesium/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
Ray,
IntersectionTests,
Matrix4,
SceneMode,
} from "cesium";
import { useCallback, MutableRefObject } from "react";

Expand Down Expand Up @@ -380,9 +381,16 @@ export const getCenterCamera = ({
};

export const zoom = (
{ camera, scene, relativeAmount }: { camera: CesiumCamera; scene: Scene; relativeAmount: number },
{ viewer, relativeAmount }: { viewer: Viewer; relativeAmount: number },
options?: CameraOptions,
) => {
const { camera, scene } = viewer;
if (scene.mode !== SceneMode.SCENE3D) {
const pos = getCamera(viewer);
flyTo(camera, { ...pos, height: (pos?.height || 1) * relativeAmount }, { duration: 0.5 });
return;
}

const center = getCenterCamera({ camera, scene });
const target =
center ||
Expand Down
126 changes: 113 additions & 13 deletions src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
Globe,
Ellipsoid,
Matrix4,
SceneMode,
} from "cesium";
import { useRef } from "react";
import type { CesiumComponentRef } from "resium";
Expand Down Expand Up @@ -172,16 +173,17 @@ test("requestRender", () => {
});

test("zoom", async () => {
const viewer = {
scene: {
camera: {},
},
isDestroyed: () => {
return false;
},
} as any;
const { result } = renderHook(() => {
const cesium = useRef<CesiumComponentRef<CesiumViewer>>({
cesiumElement: {
scene: {
camera: {},
},
isDestroyed: () => {
return false;
},
} as any,
cesiumElement: viewer,
});
const engineRef = useRef<EngineRef>(null);
useEngineRef(engineRef, cesium);
Expand All @@ -194,8 +196,7 @@ test("zoom", async () => {
expect(commons.zoom).toHaveBeenCalledTimes(1);
expect(commons.zoom).toHaveBeenCalledWith(
{
camera: {},
scene: { camera: {} },
viewer,
relativeAmount: 0.1,
},
undefined,
Expand All @@ -205,8 +206,7 @@ test("zoom", async () => {
expect(commons.zoom).toHaveBeenCalledTimes(2);
expect(commons.zoom).toHaveBeenCalledWith(
{
camera: {},
scene: { camera: {} },
viewer,
relativeAmount: 20,
},
undefined,
Expand All @@ -217,11 +217,23 @@ test("call orbit when camera focuses on center", async () => {
const { result } = renderHook(() => {
const cesiumElement = {
scene: {
camera: { lookAtTransform: vi.fn(), rotateLeft: vi.fn(), rotateUp: vi.fn(), look: vi.fn() },
camera: {
lookAtTransform: vi.fn(),
rotateLeft: vi.fn(),
rotateUp: vi.fn(),
look: vi.fn(),
move: vi.fn(),
positionCartographic: new Cartesian3(),
},
mode: SceneMode.SCENE3D,
globe: {
ellipsoid: new Ellipsoid(),
pick: () => new Cartesian3(),
},
canvas: {
clientWidth: 100,
clientHeight: 100,
},
},
transform: new Matrix4(),
positionWC: new Cartesian3(),
Expand Down Expand Up @@ -257,12 +269,19 @@ test("call orbit when camera does not focus on center", async () => {
rotateLeft: vi.fn(),
rotateUp: vi.fn(),
look: vi.fn(),
move: vi.fn(),
positionWC: new Cartesian3(),
positionCartographic: new Cartesian3(),
},
mode: SceneMode.SCENE3D,
globe: {
ellipsoid: new Ellipsoid(),
pick: () => undefined,
},
canvas: {
clientWidth: 100,
clientHeight: 100,
},
},
transform: new Matrix4(),
isDestroyed: () => {
Expand All @@ -287,6 +306,48 @@ test("call orbit when camera does not focus on center", async () => {
expect(cesium.current.cesiumElement?.scene.camera.lookAtTransform).toHaveBeenCalledTimes(2);
});

test("orbit on 2D mode", async () => {
const { result } = renderHook(() => {
const cesiumElement = {
scene: {
camera: {
lookAtTransform: vi.fn(),
rotateLeft: vi.fn(),
rotateUp: vi.fn(),
look: vi.fn(),
move: vi.fn(),
positionWC: new Cartesian3(),
positionCartographic: new Cartesian3(),
},
mode: SceneMode.SCENE2D,
globe: {
ellipsoid: new Ellipsoid(),
pick: () => undefined,
},
canvas: {
clientWidth: 100,
clientHeight: 100,
},
},
transform: new Matrix4(),
isDestroyed: () => {
return false;
},
} as any;
const cesium = useRef<CesiumComponentRef<CesiumViewer>>({
cesiumElement,
});
const engineRef = useRef<EngineRef>(null);
useEngineRef(engineRef, cesium);
return [engineRef, cesium] as const;
});

const [engineRef, cesium] = result.current;

engineRef.current?.orbit(90);
expect(cesium.current.cesiumElement?.scene.camera.move).toHaveBeenCalledTimes(1);
});

test("rotateRight", async () => {
const { result } = renderHook(() => {
const cesiumElement = {
Expand All @@ -295,7 +356,10 @@ test("rotateRight", async () => {
lookAtTransform: vi.fn(),
rotateRight: vi.fn(),
positionWC: new Cartesian3(),
twistRight: vi.fn(),
twistLeft: vi.fn(),
},
mode: SceneMode.SCENE3D,
globe: {
ellipsoid: new Ellipsoid(),
},
Expand All @@ -320,6 +384,42 @@ test("rotateRight", async () => {
expect(cesium.current.cesiumElement?.scene.camera.lookAtTransform).toHaveBeenCalledTimes(2);
});

test("rotateRight on 2D mode", async () => {
const { result } = renderHook(() => {
const cesiumElement = {
scene: {
camera: {
lookAtTransform: vi.fn(),
rotateRight: vi.fn(),
positionWC: new Cartesian3(),
twistRight: vi.fn(),
twistLeft: vi.fn(),
},
mode: SceneMode.SCENE2D,
globe: {
ellipsoid: new Ellipsoid(),
},
},
transform: new Matrix4(),
isDestroyed: () => {
return false;
},
} as any;
const cesium = useRef<CesiumComponentRef<CesiumViewer>>({
cesiumElement,
});
const engineRef = useRef<EngineRef>(null);
useEngineRef(engineRef, cesium);
return [engineRef, cesium] as const;
});

const [engineRef, cesium] = result.current;

engineRef.current?.rotateRight(90);
expect(cesium.current.cesiumElement?.scene.camera.twistLeft).toHaveBeenCalled();
expect(cesium.current.cesiumElement?.scene.camera.twistRight).toHaveBeenCalled();
});

test("getClock", () => {
const tickTime = JulianDate.fromIso8601("2022-01-13");
const mockAddEventHandler: any = vi.fn(_cb => {});
Expand Down
29 changes: 19 additions & 10 deletions src/components/molecules/Visualizer/Engine/Cesium/useEngineRef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,16 +125,13 @@ export default function useEngineRef(
zoomIn: (amount, options) => {
const viewer = cesium.current?.cesiumElement;
if (!viewer || viewer.isDestroyed()) return;
const scene = viewer.scene;
const camera = scene.camera;
zoom({ camera, scene, relativeAmount: 1 / amount }, options);
const relativeAmount = 1 / amount;
zoom({ viewer, relativeAmount }, options);
},
zoomOut: (amount, options) => {
const viewer = cesium.current?.cesiumElement;
if (!viewer || viewer.isDestroyed()) return;
const scene = viewer.scene;
const camera = scene.camera;
zoom({ camera, scene, relativeAmount: amount }, options);
zoom({ viewer, relativeAmount: amount }, options);
},
orbit: radian => {
const viewer = cesium.current?.cesiumElement;
Expand All @@ -159,7 +156,14 @@ export default function useEngineRef(

camera.lookAtTransform(frame);

if (center) {
if (viewer.scene.mode !== Cesium.SceneMode.SCENE3D) {
camera.move(
new Cesium.Cartesian3(x, y, 0),
(Math.max(scene.canvas.clientWidth, scene.canvas.clientHeight) / 100) *
camera.positionCartographic.height *
distance,
);
} else if (center) {
camera.rotateLeft(x);
camera.rotateUp(y);
} else {
Expand All @@ -178,9 +182,14 @@ export default function useEngineRef(
camera.positionWC,
scene.globe.ellipsoid,
);
camera.lookAtTransform(frame);
camera.rotateRight(radian - -camera.heading);
camera.lookAtTransform(oldTransform);
if (viewer.scene.mode !== Cesium.SceneMode.SCENE3D) {
camera.twistRight(radian - -camera.heading);
camera.twistLeft(radian - -camera.heading);
} else {
camera.lookAtTransform(frame);
camera.rotateRight(radian - -camera.heading);
camera.lookAtTransform(oldTransform);
}
},
changeSceneMode: (sceneMode, duration = 2) => {
const viewer = cesium.current?.cesiumElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ export type Props = {
};

const NavigatorPresenter: React.FC<Props> = memo(function NavigatorPresenterMemo({
sceneMode,
publishedTheme,
degree,
onRotate,
Expand All @@ -64,33 +63,31 @@ const NavigatorPresenter: React.FC<Props> = memo(function NavigatorPresenterMemo

return (
<Container>
{sceneMode !== "2d" && (
<CompassContainer>
<Compass ref={compassRef}>
<CompassIcon onMouseDown={handleOnMouseDownCompass} publishedTheme={publishedTheme}>
<Icon
icon="compass"
aria-label={t("aria-label-compass")}
size={64}
style={{ transform: `rotate(${compassDegree}deg)` }}
/>
</CompassIcon>
{isMovingAngle && (
<CompassFocusIcon
style={{
transform: `rotate(${compassFocusDegree}deg)`,
}}
data-testid="compassFocus">
<Icon icon="compassFocus" color={publishedTheme?.select} alt="" size={30} />
</CompassFocusIcon>
)}
<AngleIcon onMouseDown={handleOnMouseDownAngle} publishedTheme={publishedTheme}>
<Icon icon="navigatorAngle" aria-label={t("aria-label-adjust-angle")} size={32} />
</AngleIcon>
</Compass>
{onClickHelp && <Help onClick={onClickHelp}>?</Help>}
</CompassContainer>
)}
<CompassContainer>
<Compass ref={compassRef}>
<CompassIcon onMouseDown={handleOnMouseDownCompass} publishedTheme={publishedTheme}>
<Icon
icon="compass"
aria-label={t("aria-label-compass")}
size={64}
style={{ transform: `rotate(${compassDegree}deg)` }}
/>
</CompassIcon>
{isMovingAngle && (
<CompassFocusIcon
style={{
transform: `rotate(${compassFocusDegree}deg)`,
}}
data-testId="compassFocus">
<Icon icon="compassFocus" color={publishedTheme?.select} alt="" size={30} />
</CompassFocusIcon>
)}
<AngleIcon onMouseDown={handleOnMouseDownAngle} publishedTheme={publishedTheme}>
<Icon icon="navigatorAngle" aria-label={t("aria-label-adjust-angle")} size={32} />
</AngleIcon>
</Compass>
{onClickHelp && <Help onClick={onClickHelp}>?</Help>}
</CompassContainer>
<Tool publishedTheme={publishedTheme}>
<ToolIconButton onClick={onZoomIn} publishedTheme={publishedTheme}>
<Icon icon="plus" aria-label={t("aria-label-zoom-in")} size={16} />
Expand Down

0 comments on commit 595dd53

Please sign in to comment.