Use ZoomPanEmitter/Subscriber instead of a context for aligning the view
This commit is contained in:
parent
2e1947a7d4
commit
de6d3aa5dc
@ -3,7 +3,6 @@ import './ZoomPanWrapper.css';
|
||||
import Constants from '../../helpers/constants';
|
||||
import { useZoomPanSubscriber, viewBox$, clientRect$, camera$ } from '../../hooks/useZoomPubSub';
|
||||
import {mapRotation$} from '../../services/mapRotationService';
|
||||
import ZoomPanContext from "../../contexts/ZoomPanContext";
|
||||
import AngleHelper from "../../helpers/angleHelper";
|
||||
|
||||
export default function ZoomPanWrapper({children}) {
|
||||
@ -91,8 +90,19 @@ export default function ZoomPanWrapper({children}) {
|
||||
scheduleCameraUpdate();
|
||||
}, [scheduleCameraUpdate]);
|
||||
|
||||
// Subscribe to any external "center" calls
|
||||
useZoomPanSubscriber(centerOn);
|
||||
const alignView = (angleDeg) => {
|
||||
// Find such relative rotation in the range [-45, 45] degrees that aligns the track
|
||||
// with y rotation angleDeg to the X or Y screen axis.
|
||||
const angleDifference = -angleDeg - cameraRef.current.rotation;
|
||||
let deltaAngle = AngleHelper.normalizeDegAngle(angleDifference, 90);
|
||||
if (deltaAngle > 45) deltaAngle -= 90;
|
||||
|
||||
cameraRef.current.rotation += deltaAngle;
|
||||
scheduleCameraUpdate();
|
||||
};
|
||||
|
||||
// Subscribe to any external `center` and `alignView` calls
|
||||
useZoomPanSubscriber(centerOn, alignView);
|
||||
|
||||
const onWheel = (e) => {
|
||||
const { left, top } = clientRectRef.current;
|
||||
@ -149,20 +159,7 @@ export default function ZoomPanWrapper({children}) {
|
||||
isMouseDownRef.current = false;
|
||||
};
|
||||
|
||||
// `event` could be used in the future to perform the rotation around the click position
|
||||
const alignView = (angleDeg, _event) => {
|
||||
// Find such relative rotation in the range [-45, 45] degrees that aligns the track
|
||||
// with y rotation angleDeg to the X or Y screen axis.
|
||||
const angleDifference = -angleDeg - cameraRef.current.rotation;
|
||||
let deltaAngle = AngleHelper.normalizeDegAngle(angleDifference, 90);
|
||||
if (deltaAngle > 45) deltaAngle -= 90;
|
||||
|
||||
cameraRef.current.rotation += deltaAngle;
|
||||
scheduleCameraUpdate();
|
||||
};
|
||||
|
||||
return (
|
||||
<ZoomPanContext.Provider value={{alignView}}>
|
||||
<div className="zoom-pan-wrapper" ref={wrapperRef}>
|
||||
<svg
|
||||
ref={svgRef}
|
||||
@ -178,6 +175,5 @@ export default function ZoomPanWrapper({children}) {
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
</ZoomPanContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
@ -3,18 +3,18 @@ import SettingsContext from "../../../contexts/SettingsContext";
|
||||
import Constants from "../../../helpers/constants";
|
||||
import {ElectrificationStatus} from "../../../model/electrification-status";
|
||||
import {setHoveredTrack, unsetHoveredTrack} from "../../../services/trackHoverInfoService";
|
||||
import ZoomPanContext from "../../../contexts/ZoomPanContext";
|
||||
import GradientsContext from "../../../contexts/GradientsContext";
|
||||
import MiscHelper from "../../../helpers/miscHelper";
|
||||
import {useZoomPanEmitter} from "../../../hooks/useZoomPubSub";
|
||||
|
||||
export default function TrackRenderer(props) {
|
||||
const {object} = props;
|
||||
const {trackColorMode} = useContext(SettingsContext);
|
||||
const {gradientDefs} = useContext(GradientsContext);
|
||||
const {alignView} = useContext(ZoomPanContext);
|
||||
const { alignView } = useZoomPanEmitter();
|
||||
|
||||
const onAlign = (event) => {
|
||||
alignView(object.rot.y, event);
|
||||
const onAlign = () => {
|
||||
alignView(object.rot.y);
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -1,4 +0,0 @@
|
||||
import { createContext } from 'react';
|
||||
|
||||
const ZoomPanContext = createContext();
|
||||
export default ZoomPanContext;
|
||||
@ -2,6 +2,7 @@ import { useEffect } from 'react';
|
||||
import { Subject, BehaviorSubject } from 'rxjs';
|
||||
|
||||
const zoomCenter$ = new Subject();
|
||||
const viewAlign$ = new Subject();
|
||||
|
||||
// BehaviorSubjects to store current viewBox, clientRect and camera transform
|
||||
export const viewBox$ = new BehaviorSubject(null);
|
||||
@ -32,17 +33,27 @@ export function getCurrentCamera() {
|
||||
/**
|
||||
* useZoomPanSubscriber
|
||||
*
|
||||
* Registers a callback (onCenter) that will be invoked whenever
|
||||
* Registers an `onCenter` callback that will be invoked whenever
|
||||
* someone calls `center(x, y)` via the emitter. You should pass
|
||||
* a function that takes (x, y) and recenters your viewBox accordingly.
|
||||
*
|
||||
* Similarly, registers an `onAlign` callback that will be invoked
|
||||
* when someone calls `alignView(angleDeg)`.
|
||||
*/
|
||||
export function useZoomPanSubscriber(onCenter) {
|
||||
export function useZoomPanSubscriber(onCenter, onAlign) {
|
||||
useEffect(() => {
|
||||
const sub = zoomCenter$.subscribe(({ x, y }) => {
|
||||
onCenter(x, y);
|
||||
});
|
||||
return () => sub.unsubscribe();
|
||||
}, [onCenter]);
|
||||
|
||||
useEffect(() => {
|
||||
const sub = viewAlign$.subscribe((angleDeg) => {
|
||||
onAlign(angleDeg);
|
||||
});
|
||||
return () => sub.unsubscribe();
|
||||
}, [onAlign]);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,5 +68,8 @@ export function useZoomPanEmitter() {
|
||||
center: (x, y) => {
|
||||
zoomCenter$.next({ x, y });
|
||||
},
|
||||
alignView: (angleDeg) => {
|
||||
viewAlign$.next(angleDeg);
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user