Skip to content

Commit

Permalink
feat(globe): add auto rotate on initial load
Browse files Browse the repository at this point in the history
  • Loading branch information
mrMetalWood committed Aug 26, 2020
1 parent 85047d1 commit 1419e2a
Show file tree
Hide file tree
Showing 8 changed files with 148 additions and 10 deletions.
13 changes: 13 additions & 0 deletions src/scripts/actions/set-globe-spinning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const SET_GLOBE_SPINNING = 'SET_GLOBE_SPINNING';

export interface SetGlobeSpinningAction {
type: typeof SET_GLOBE_SPINNING;
spinning: boolean;
}

const setGlobeSpinningAction = (spinning: boolean): SetGlobeSpinningAction => ({
type: SET_GLOBE_SPINNING,
spinning
});

export default setGlobeSpinningAction;
60 changes: 58 additions & 2 deletions src/scripts/components/main/globe/globe.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import React, {FunctionComponent, useRef, useEffect, useState} from 'react';
import 'cesium/Build/Cesium/Widgets/widgets.css';
import {Viewer, SceneMode, Color, TileMapServiceImageryProvider} from 'cesium';
import {
Cartesian3,
Color,
EventHelper,
SceneMode,
ScreenSpaceEventHandler,
ScreenSpaceEventType,
TileMapServiceImageryProvider,
Viewer
} from 'cesium';

import {
getGlobeView,
Expand Down Expand Up @@ -45,13 +54,15 @@ interface Props {
projectionState: GlobeProjectionState;
imageLayer: GlobeImageLayerData | null;
basemap: BasemapId | null;
spinning: boolean;
flyTo: GlobeView | null;
markers?: Marker[];
backgroundColor: string;
onMouseEnter: () => void;
onTouchStart: () => void;
onChange: (view: GlobeView) => void;
onMoveEnd: (view: GlobeView) => void;
onMouseDown: () => void;
}

// keep a reference to the current basemap layer
Expand All @@ -67,19 +78,23 @@ function getBasemapUrl(id: BasemapId | null) {
return isElectron() ? config.basemapUrlsOffline[id] : config.basemapUrls[id];
}

const spinningEventHelper = new EventHelper();

const Globe: FunctionComponent<Props> = ({
view,
projectionState,
imageLayer,
basemap,
spinning,
active,
flyTo,
markers = [],
backgroundColor,
onMouseEnter,
onTouchStart,
onChange,
onMoveEnd
onMoveEnd,
onMouseDown
}) => {
const [viewer, setViewer] = useState<Viewer | null>(null);
const ref = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -176,6 +191,22 @@ const Globe: FunctionComponent<Props> = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [ref, onChange, onMoveEnd]);

// update mousedown handler
useEffect(() => {
if (!viewer) {
return;
}

const handler = new ScreenSpaceEventHandler(
viewer.scene.canvas as HTMLCanvasElement
);
handler.setInputAction(onMouseDown, ScreenSpaceEventType.LEFT_DOWN);

return () => {
handler.destroy();
};
}, [viewer, onMouseDown]);

// switch projections
useEffect(() => {
if (!viewer) {
Expand Down Expand Up @@ -241,6 +272,31 @@ const Globe: FunctionComponent<Props> = ({
flyToGlobeView(viewer, flyTo);
}, [viewer, flyTo]);

// update spinning
useEffect(() => {
if (!viewer) {
return;
}

if (spinning) {
setTimeout(() => {
let lastNow = Date.now();

const spin = () => {
const now = Date.now();
const spinRate = 0.08;
const delta = (now - lastNow) / 1000;
lastNow = now;
viewer.scene.camera.rotate(Cartesian3.UNIT_Z, spinRate * delta);
};

spinningEventHelper.add(viewer.clock.onTick, spin);
}, projectionState.morphTime * 1000);
} else {
spinningEventHelper.removeAll();
}
}, [spinning, viewer]);

useMarkers(viewer, markers);

return (
Expand Down
12 changes: 12 additions & 0 deletions src/scripts/components/main/globes/globes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ import {getImageLayerData} from '../../../libs/get-image-layer-data';
import {State} from '../../../reducers';
import {layerDetailsSelector} from '../../../selectors/layers/layer-details';
import {selectedLayerIdsSelector} from '../../../selectors/layers/selected-ids';
import {globeSpinningSelector} from '../../../selectors/globe/Spinning';

import {GlobeView} from '../../../types/globe-view';
import {Marker} from '../../../types/marker-type';

import styles from './globes.styl';
import setGlobeSpinningAction from '../../../actions/set-globe-spinning';

interface Props {
backgroundColor: string;
Expand All @@ -35,6 +37,7 @@ const Globes: FunctionComponent<Props> = ({backgroundColor, markers = []}) => {
const selectedLayerIds = useSelector(selectedLayerIdsSelector);
const projectionState = useSelector(projectionSelector);
const globalGlobeView = useSelector(globeViewSelector);
const globeSpinning = useSelector(globeSpinningSelector);
const {mainId, compareId} = selectedLayerIds;
const mainLayerDetails = useSelector((state: State) =>
layerDetailsSelector(state, mainId)
Expand Down Expand Up @@ -64,6 +67,11 @@ const Globes: FunctionComponent<Props> = ({backgroundColor, markers = []}) => {
[dispatch]
);

const onMouseDownHandler = useCallback(
() => globeSpinning && dispatch(setGlobeSpinningAction(false)),
[dispatch, globeSpinning]
);

const mainImageLayer = useMemo(
() => getImageLayerData(mainLayerDetails, time),
[mainLayerDetails, time]
Expand Down Expand Up @@ -104,11 +112,13 @@ const Globes: FunctionComponent<Props> = ({backgroundColor, markers = []}) => {
projectionState={projectionState}
imageLayer={mainImageLayer}
basemap={mainLayerDetails?.basemap || null}
spinning={globeSpinning}
flyTo={flyTo}
onMouseEnter={() => setIsMainActive(true)}
onTouchStart={() => setIsMainActive(true)}
onChange={onChangeHandler}
onMoveEnd={onMoveEndHandler}
onMouseDown={onMouseDownHandler}
/>

{compareLayer && (
Expand All @@ -119,11 +129,13 @@ const Globes: FunctionComponent<Props> = ({backgroundColor, markers = []}) => {
projectionState={projectionState}
imageLayer={compareImageLayer}
basemap={compareLayerDetails?.basemap || null}
spinning={globeSpinning}
flyTo={flyTo}
onMouseEnter={() => setIsMainActive(false)}
onTouchStart={() => setIsMainActive(false)}
onChange={onChangeHandler}
onMoveEnd={onMoveEndHandler}
onMouseDown={onMouseDownHandler}
/>
)}
</div>
Expand Down
3 changes: 2 additions & 1 deletion src/scripts/config/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ const globeState: GlobeState = {
pitch: -90,
roll: 0
}
}
},
spinning: true
};

// @ts-ignore - injected via webpack's define plugin
Expand Down
22 changes: 16 additions & 6 deletions src/scripts/libs/globe-url-parameter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function parseUrl(): UrlHashState | null {

const splitted = globeParam.split(char);

if (splitted.length !== 10) {
if (splitted.length !== 11) {
return null;
}

Expand All @@ -37,14 +37,14 @@ export function parseUrl(): UrlHashState | null {
}

// globe view values
const values = splitted.slice(1, 8).map(str => parseFloat(str));
const values = splitted.slice(1, 9).map(str => parseFloat(str));

if (values.some(num => isNaN(num))) {
return null;
}

// selected main and compare layer ids
const layerIds = splitted.slice(8, 10).map(id => id || null);
const layerIds = splitted.slice(9, 11).map(id => id || null);

return {
globeState: {
Expand All @@ -64,7 +64,8 @@ export function parseUrl(): UrlHashState | null {
projection: GlobeProjection.Sphere,
morphTime: 2
},
time: values[6]
time: values[6],
spinning: Boolean(Number(values[7]))
},
layerIds: {
mainId: layerIds[0],
Expand All @@ -78,11 +79,20 @@ export function getParamString(
mainId: string | null,
compareId: string | null
): string | null {
const {view, projectionState, time} = globeState;
const {view, projectionState, time, spinning} = globeState;
const {position, orientation} = view;
const {longitude, latitude, height} = position;
const {heading, pitch, roll} = orientation;
const values = [longitude, latitude, height, heading, pitch, roll, time];
const values = [
longitude,
latitude,
height,
heading,
pitch,
roll,
time,
spinning ? 1 : 0
];

if (values.some(num => isNaN(num))) {
return null;
Expand Down
4 changes: 3 additions & 1 deletion src/scripts/reducers/globe/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import {combineReducers} from 'redux';
import projectionReducer from './projection';
import viewReducer from './view';
import timeReducer from './time';
import spinningReducer from './spinning';

const globeReducer = combineReducers({
view: viewReducer,
projectionState: projectionReducer,
time: timeReducer
time: timeReducer,
spinning: spinningReducer
});

export default globeReducer;
Expand Down
39 changes: 39 additions & 0 deletions src/scripts/reducers/globe/spinning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import {
SET_GLOBE_SPINNING,
SetGlobeSpinningAction
} from '../../actions/set-globe-spinning';
import {
SET_GLOBE_PROJECTION,
SetGlobeProjectionAction
} from '../../actions/set-globe-projection';
import {SET_FLY_TO, SetFlyToAction} from '../../actions/set-fly-to';

import {GlobeProjection} from '../../types/globe-projection';
import config from '../../config/main';
import {parseUrl} from '../../libs/globe-url-parameter';

// get initial state from url or fallback to default state in config
console.log(parseUrl());

const globeState = parseUrl()?.globeState || config.globe;
const initialState = globeState.spinning;

console.log(initialState);

function spinningReducer(
state: boolean = initialState,
action: SetGlobeSpinningAction | SetGlobeProjectionAction | SetFlyToAction
): boolean {
switch (action.type) {
case SET_GLOBE_SPINNING:
return action.spinning;
case SET_GLOBE_PROJECTION:
return action.projection === GlobeProjection.Sphere;
case SET_FLY_TO:
return false;
default:
return state;
}
}

export default spinningReducer;
5 changes: 5 additions & 0 deletions src/scripts/selectors/globe/spinning.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import {State} from '../../reducers/index';

export function globeSpinningSelector(state: State): boolean {
return state.globe.spinning;
}

0 comments on commit 1419e2a

Please sign in to comment.