Optimized objects rendering

*Optimized objects on the map to render only above the specified zoom threshold
This commit is contained in:
izawartka 2025-08-13 14:04:42 +02:00
parent 0ca6f6b9e0
commit f5bc06ad8b
4 changed files with 64 additions and 12 deletions

View File

@ -37,49 +37,56 @@ const ObjectRendererQueue = [
'name': 'isolations-ends',
'category': 'tracks',
'renderer': IsolationEndRenderer,
'cond': (layers) => layers['isolations-ids']
'cond': (layers) => layers['isolations-ids'],
'usesObjectDetails': true
},
{
'name': 'isolations-ids',
'category': ['tracks', 'switches'],
'trackSources': [TrackSource.STANDARD],
'renderer': IsolationIdRenderer,
'cond': (layers) => layers['isolations-ids']
'cond': (layers) => layers['isolations-ids'],
'usesObjectDetails': true
},
{
'name': 'switches-names',
'category': 'switches',
'type': 'Switch',
'renderer': SwitchNameRenderer,
'cond': (layers) => layers['switches-names']
'cond': (layers) => layers['switches-names'],
'usesObjectDetails': true
},
{
'name': 'derailers',
'category': 'track-objects',
'type': 'Derailer',
'renderer': DerailerRenderer,
'cond': (layers) => layers['derailers']
'cond': (layers) => layers['derailers'],
'usesObjectDetails': true
},
{
'name': 'signs',
'category': 'track-objects',
'type': 'Sign',
'renderer': SignRenderer,
'cond': (layers) => layers['signs']
'cond': (layers) => layers['signs'],
'usesObjectDetails': true
},
{
'name': 'nevps',
'category': 'track-objects',
'type': 'NEVP',
'renderer': NEVPRenderer,
'cond': (layers) => layers['nevps']
'cond': (layers) => layers['nevps'],
'usesObjectDetails': true
},
{
'name': 'signals',
'category': 'track-objects',
'type': 'Signal',
'renderer': SignalRenderer,
'cond': (layers) => layers['signals']
'cond': (layers) => layers['signals'],
'usesObjectDetails': true
},
{
'name': 'spawn-points',
@ -87,6 +94,7 @@ const ObjectRendererQueue = [
'type': 'SpawnPoint',
'renderer': SpawnPointRenderer,
'cond': (layers) => layers['spawn-points'],
'usesObjectDetails': true
},
{
'name': 'signalboxes',
@ -106,7 +114,8 @@ const ObjectRendererQueue = [
'category': 'track-objects',
'renderer': TrackObjectRenderer,
'cond': (layers) => layers['track-objects'],
'pointerEvents': true
'pointerEvents': true,
'usesObjectDetails': true
}
]

View File

@ -1,11 +1,22 @@
import React, { useContext, useMemo, memo } from "react";
import { useContext, useMemo, memo, useCallback, useRef, useEffect } from "react";
import SceneryContext from "../../contexts/SceneryContext";
import SettingsContext from "../../contexts/SettingsContext";
import Constants from "../../helpers/constants";
import { mapZoomObjectDetails$ } from "../../services/mapZoomService";
export default function SceneryLayer(props) {
const { queueItem } = props;
const { name, category, type, types, trackSources, cond, renderer: Renderer, additionalComponents: AdditionalComponents } = queueItem;
const {
name,
category,
type,
types,
trackSources,
cond,
renderer: Renderer,
additionalComponents: AdditionalComponents,
usesObjectDetails
} = queueItem;
const { scenery } = useContext(SceneryContext);
const { layers } = useContext(SettingsContext);
@ -38,6 +49,7 @@ export default function SceneryLayer(props) {
trackSources={trackSources}
pointerEvents={pointerEvents}
AdditionalComponents={AdditionalComponents}
usesObjectDetails={usesObjectDetails || false}
/>
);
}
@ -45,9 +57,32 @@ export default function SceneryLayer(props) {
const MemoizedSceneryLayer = memo(StatelessSceneryLayer);
function StatelessSceneryLayer({ name, Renderer, objects, type, types, trackSources, pointerEvents = false, AdditionalComponents = [] }) {
function StatelessSceneryLayer({ name, Renderer, objects, type, types, trackSources, pointerEvents = false, AdditionalComponents = [], usesObjectDetails }) {
const layerRef = useRef(null);
const handleDetailsUpdate = useCallback((details) => {
if (!layerRef.current) return;
if (details) {
layerRef.current.style.display = '';
}
else {
layerRef.current.style.display = 'none';
}
}, []);
useEffect(() => {
if (!usesObjectDetails) return;
const subscription = mapZoomObjectDetails$.subscribe(details => {
handleDetailsUpdate(details);
});
return () => subscription.unsubscribe();
}, [handleDetailsUpdate, usesObjectDetails]);
return (
<g
ref={layerRef}
className={`scenery-layer-${name}`}
pointerEvents={pointerEvents ? "all" : "none"}
>

View File

@ -9,7 +9,8 @@ const Constants = {
forcePointerEvents: false,
platformMaxTilt: 0.5,
showDebugTrackIds: false,
mapZoomTrackDetailsThreshold: 1 / 1.44
mapZoomTrackDetailsThreshold: 1 / 1.44,
mapZoomObjectDetailsThreshold: 0.5
},
parser: {
logSceneryAfterFinished: true,

View File

@ -3,6 +3,8 @@ import Constants from '../helpers/constants';
export const mapZoom$ = new BehaviorSubject(null);
export const mapZoomTrackDetails$ = new BehaviorSubject(true);
export const mapZoomObjectDetails$ = new BehaviorSubject(true);
export function setMapZoom(zoom) {
mapZoom$.next(zoom);
@ -10,4 +12,9 @@ export function setMapZoom(zoom) {
if (mapZoomTrackDetails$.getValue() !== newZoomTrackDetails) {
mapZoomTrackDetails$.next(newZoomTrackDetails);
}
const newZoomObjectDetails = zoom > Constants.map.mapZoomObjectDetailsThreshold;
if (mapZoomObjectDetails$.getValue() !== newZoomObjectDetails) {
mapZoomObjectDetails$.next(newZoomObjectDetails);
}
}