diff --git a/src/components/map/object-renderers/RouteRenderer.jsx b/src/components/map/object-renderers/RouteRenderer.jsx index cb8bb78..f17b80a 100644 --- a/src/components/map/object-renderers/RouteRenderer.jsx +++ b/src/components/map/object-renderers/RouteRenderer.jsx @@ -1,9 +1,13 @@ +import { useRef, useCallback, useEffect } from 'react'; import { ReactSVG } from "react-svg"; import AlwaysUpText from "../text/AlwaysUpText"; import AngleHelper from "../../../helpers/angleHelper"; +import { useCameraSubscriber } from '../../../hooks/useZoomPubSub'; +import Constants from '../../../helpers/constants'; export default function RouteRenderer(props) { const { object } = props; + const textRef = useRef(null); const [startX, startY] = object.pos.toSVGCoords(); const startAngle = object.rot.y; @@ -14,6 +18,18 @@ export default function RouteRenderer(props) { const offY = object.track_count === 2 ? -22 : -20; const arrowOffset = - object.track_offset - 37.8; + const handleZoomTransparrency = useCallback((camera) => { + if (!textRef.current?.style || !camera) return; + + const min = Constants.map.routeTextMinZoom; + const max = Constants.map.routeTextMaxZoom; + const value = (max - camera.zoom) / (max - min); + const opacity = Math.pow(Math.min(Math.max(value, 0), 1), 2); + textRef.current.style.opacity = opacity; + }, [textRef]); + + useCameraSubscriber(handleZoomTransparrency); + return (<> diff --git a/src/components/map/text/AlwaysUpText.jsx b/src/components/map/text/AlwaysUpText.jsx index de970e2..86ce396 100644 --- a/src/components/map/text/AlwaysUpText.jsx +++ b/src/components/map/text/AlwaysUpText.jsx @@ -2,10 +2,20 @@ import { useCallback, useEffect, useRef } from "react"; import AngleHelper from "../../../helpers/angleHelper"; import { mapRotation$ } from "../../../services/mapRotationService"; -export default function AlwaysUpText(props) { - const { baseRot, additionalRot, additionalPreRot, text, reverseAnchor, offsetX, offsetY, textProps } = props; +export default function AlwaysUpText({ + baseRot, + additionalRot, + additionalPreRot, + text, + reverseAnchor, + offsetX, + offsetY, + textProps, + textRef +}) { const gRef = useRef(null); - const textRef = useRef(null); + const ownTextRef = useRef(null); + if(!textRef) textRef = ownTextRef; const getTransformString = useCallback((upsideDown) => { const upsideDownRot = upsideDown ? 180 : 0; diff --git a/src/helpers/constants.js b/src/helpers/constants.js index 7505389..2d15c9d 100644 --- a/src/helpers/constants.js +++ b/src/helpers/constants.js @@ -15,7 +15,9 @@ const Constants = { showDebugTrackIds: false, mapZoomTrackDetailsThreshold: 1 / 1.44, mapZoomObjectDetailsThreshold: 0.5, - distanceMeterMaxMovePx: 10 + distanceMeterMaxMovePx: 10, + routeTextMinZoom: 1.5, + routeTextMaxZoom: 3 }, parser: { logSceneryAfterFinished: readEnvBool('VITE_DO_LOG_SCENERY') ?? false, diff --git a/src/hooks/useZoomPubSub.js b/src/hooks/useZoomPubSub.js index d4115c5..7f23e75 100644 --- a/src/hooks/useZoomPubSub.js +++ b/src/hooks/useZoomPubSub.js @@ -37,6 +37,15 @@ export function useZoomPanSubscriber(setCamera, onAlign) { }, [onAlign]); } +export function useCameraSubscriber(onCameraUpdate) { + useEffect(() => { + const sub = camera$.subscribe((camera) => { + onCameraUpdate(camera); + }); + return () => sub.unsubscribe(); + }, [onCameraUpdate]); +} + export function useZoomPanEmitter() { return { setCamera: (x, y, rot = null, zoom = null) => {