mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
Have visualizer remember settings
This commit is contained in:
@@ -25,6 +25,7 @@ import {
|
||||
type ContactAdvertPathSummary,
|
||||
} from '../types';
|
||||
import { getRawPacketObservationKey } from '../utils/rawPacketIdentity';
|
||||
import { getVisualizerSettings, saveVisualizerSettings } from '../utils/visualizerSettings';
|
||||
import { Checkbox } from './ui/checkbox';
|
||||
import {
|
||||
type NodeType,
|
||||
@@ -34,7 +35,6 @@ import {
|
||||
COLORS,
|
||||
PARTICLE_COLOR_MAP,
|
||||
PARTICLE_SPEED,
|
||||
DEFAULT_OBSERVATION_WINDOW_SEC,
|
||||
PACKET_LEGEND_ITEMS,
|
||||
parsePacket,
|
||||
getPacketLabel,
|
||||
@@ -1007,19 +1007,55 @@ export function PacketVisualizer3D({
|
||||
const mouseRef = useRef(new THREE.Vector2());
|
||||
|
||||
// Options
|
||||
const [showAmbiguousPaths, setShowAmbiguousPaths] = useState(true);
|
||||
const [showAmbiguousNodes, setShowAmbiguousNodes] = useState(false);
|
||||
const [useAdvertPathHints, setUseAdvertPathHints] = useState(true);
|
||||
const [splitAmbiguousByTraffic, setSplitAmbiguousByTraffic] = useState(true);
|
||||
const [chargeStrength, setChargeStrength] = useState(-200);
|
||||
const [observationWindowSec, setObservationWindowSec] = useState(DEFAULT_OBSERVATION_WINDOW_SEC);
|
||||
const [letEmDrift, setLetEmDrift] = useState(true);
|
||||
const [particleSpeedMultiplier, setParticleSpeedMultiplier] = useState(2);
|
||||
const [showControls, setShowControls] = useState(true);
|
||||
const [autoOrbit, setAutoOrbit] = useState(false);
|
||||
const [pruneStaleNodes, setPruneStaleNodes] = useState(false);
|
||||
const [savedSettings] = useState(getVisualizerSettings);
|
||||
const [showAmbiguousPaths, setShowAmbiguousPaths] = useState(savedSettings.showAmbiguousPaths);
|
||||
const [showAmbiguousNodes, setShowAmbiguousNodes] = useState(savedSettings.showAmbiguousNodes);
|
||||
const [useAdvertPathHints, setUseAdvertPathHints] = useState(savedSettings.useAdvertPathHints);
|
||||
const [splitAmbiguousByTraffic, setSplitAmbiguousByTraffic] = useState(
|
||||
savedSettings.splitAmbiguousByTraffic
|
||||
);
|
||||
const [chargeStrength, setChargeStrength] = useState(savedSettings.chargeStrength);
|
||||
const [observationWindowSec, setObservationWindowSec] = useState(
|
||||
savedSettings.observationWindowSec
|
||||
);
|
||||
const [letEmDrift, setLetEmDrift] = useState(savedSettings.letEmDrift);
|
||||
const [particleSpeedMultiplier, setParticleSpeedMultiplier] = useState(
|
||||
savedSettings.particleSpeedMultiplier
|
||||
);
|
||||
const [showControls, setShowControls] = useState(savedSettings.showControls);
|
||||
const [autoOrbit, setAutoOrbit] = useState(savedSettings.autoOrbit);
|
||||
const [pruneStaleNodes, setPruneStaleNodes] = useState(savedSettings.pruneStaleNodes);
|
||||
const [repeaterAdvertPaths, setRepeaterAdvertPaths] = useState<ContactAdvertPathSummary[]>([]);
|
||||
|
||||
// Persist visualizer controls to localStorage on change
|
||||
useEffect(() => {
|
||||
saveVisualizerSettings({
|
||||
showAmbiguousPaths,
|
||||
showAmbiguousNodes,
|
||||
useAdvertPathHints,
|
||||
splitAmbiguousByTraffic,
|
||||
chargeStrength,
|
||||
observationWindowSec,
|
||||
letEmDrift,
|
||||
particleSpeedMultiplier,
|
||||
pruneStaleNodes,
|
||||
autoOrbit,
|
||||
showControls,
|
||||
});
|
||||
}, [
|
||||
showAmbiguousPaths,
|
||||
showAmbiguousNodes,
|
||||
useAdvertPathHints,
|
||||
splitAmbiguousByTraffic,
|
||||
chargeStrength,
|
||||
observationWindowSec,
|
||||
letEmDrift,
|
||||
particleSpeedMultiplier,
|
||||
pruneStaleNodes,
|
||||
autoOrbit,
|
||||
showControls,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false;
|
||||
|
||||
|
||||
89
frontend/src/utils/visualizerSettings.ts
Normal file
89
frontend/src/utils/visualizerSettings.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
const VISUALIZER_SETTINGS_KEY = 'remoteterm-visualizer-settings';
|
||||
|
||||
export interface VisualizerSettings {
|
||||
showAmbiguousPaths: boolean;
|
||||
showAmbiguousNodes: boolean;
|
||||
useAdvertPathHints: boolean;
|
||||
splitAmbiguousByTraffic: boolean;
|
||||
chargeStrength: number;
|
||||
observationWindowSec: number;
|
||||
letEmDrift: boolean;
|
||||
particleSpeedMultiplier: number;
|
||||
pruneStaleNodes: boolean;
|
||||
autoOrbit: boolean;
|
||||
showControls: boolean;
|
||||
}
|
||||
|
||||
export const VISUALIZER_DEFAULTS: VisualizerSettings = {
|
||||
showAmbiguousPaths: true,
|
||||
showAmbiguousNodes: false,
|
||||
useAdvertPathHints: true,
|
||||
splitAmbiguousByTraffic: true,
|
||||
chargeStrength: -200,
|
||||
observationWindowSec: 15,
|
||||
letEmDrift: true,
|
||||
particleSpeedMultiplier: 2,
|
||||
pruneStaleNodes: false,
|
||||
autoOrbit: false,
|
||||
showControls: true,
|
||||
};
|
||||
|
||||
export function getVisualizerSettings(): VisualizerSettings {
|
||||
try {
|
||||
const raw = localStorage.getItem(VISUALIZER_SETTINGS_KEY);
|
||||
if (!raw) return { ...VISUALIZER_DEFAULTS };
|
||||
const parsed = JSON.parse(raw) as Partial<VisualizerSettings>;
|
||||
return {
|
||||
showAmbiguousPaths:
|
||||
typeof parsed.showAmbiguousPaths === 'boolean'
|
||||
? parsed.showAmbiguousPaths
|
||||
: VISUALIZER_DEFAULTS.showAmbiguousPaths,
|
||||
showAmbiguousNodes:
|
||||
typeof parsed.showAmbiguousNodes === 'boolean'
|
||||
? parsed.showAmbiguousNodes
|
||||
: VISUALIZER_DEFAULTS.showAmbiguousNodes,
|
||||
useAdvertPathHints:
|
||||
typeof parsed.useAdvertPathHints === 'boolean'
|
||||
? parsed.useAdvertPathHints
|
||||
: VISUALIZER_DEFAULTS.useAdvertPathHints,
|
||||
splitAmbiguousByTraffic:
|
||||
typeof parsed.splitAmbiguousByTraffic === 'boolean'
|
||||
? parsed.splitAmbiguousByTraffic
|
||||
: VISUALIZER_DEFAULTS.splitAmbiguousByTraffic,
|
||||
chargeStrength:
|
||||
typeof parsed.chargeStrength === 'number'
|
||||
? parsed.chargeStrength
|
||||
: VISUALIZER_DEFAULTS.chargeStrength,
|
||||
observationWindowSec:
|
||||
typeof parsed.observationWindowSec === 'number'
|
||||
? parsed.observationWindowSec
|
||||
: VISUALIZER_DEFAULTS.observationWindowSec,
|
||||
letEmDrift:
|
||||
typeof parsed.letEmDrift === 'boolean' ? parsed.letEmDrift : VISUALIZER_DEFAULTS.letEmDrift,
|
||||
particleSpeedMultiplier:
|
||||
typeof parsed.particleSpeedMultiplier === 'number'
|
||||
? parsed.particleSpeedMultiplier
|
||||
: VISUALIZER_DEFAULTS.particleSpeedMultiplier,
|
||||
pruneStaleNodes:
|
||||
typeof parsed.pruneStaleNodes === 'boolean'
|
||||
? parsed.pruneStaleNodes
|
||||
: VISUALIZER_DEFAULTS.pruneStaleNodes,
|
||||
autoOrbit:
|
||||
typeof parsed.autoOrbit === 'boolean' ? parsed.autoOrbit : VISUALIZER_DEFAULTS.autoOrbit,
|
||||
showControls:
|
||||
typeof parsed.showControls === 'boolean'
|
||||
? parsed.showControls
|
||||
: VISUALIZER_DEFAULTS.showControls,
|
||||
};
|
||||
} catch {
|
||||
return { ...VISUALIZER_DEFAULTS };
|
||||
}
|
||||
}
|
||||
|
||||
export function saveVisualizerSettings(settings: VisualizerSettings): void {
|
||||
try {
|
||||
localStorage.setItem(VISUALIZER_SETTINGS_KEY, JSON.stringify(settings));
|
||||
} catch {
|
||||
// localStorage may be unavailable
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user