Compare commits

...

3 Commits

Author SHA1 Message Date
gorbit99
61065eba7f Apply round of suggestions 2025-09-30 22:48:51 +02:00
gorbit99
0e750fd1de Merge branch 'main' into tracker-graph 2025-09-30 01:30:32 +02:00
gorbit99
7aabdbe724 Add tracker graph to tracker settings page 2025-09-30 01:25:44 +02:00
6 changed files with 236 additions and 0 deletions

View File

@@ -26,6 +26,7 @@
"@tweenjs/tween.js": "^25.0.0",
"@twemoji/svg": "^15.0.0",
"browser-fs-access": "^0.35.0",
"chart.js": "^4.5.0",
"classnames": "^2.5.1",
"flatbuffers": "22.10.26",
"intl-pluralrules": "^2.0.1",
@@ -33,6 +34,7 @@
"jotai": "^2.12.2",
"prompts": "^2.4.2",
"react": "^18.3.1",
"react-chartjs-2": "^5.3.0",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-helmet": "^6.1.0",

View File

@@ -390,6 +390,10 @@ tracker-settings-update-blocked = Update not available. No other releases availa
tracker-settings-update-available = { $versionName } is now available
tracker-settings-update = Update now
tracker-settings-update-title = Firmware version
tracker-settings-graph-acceleration-title = Tracker Acceleration
tracker-settings-graph-position-title = Tracker Position
tracker-settings-graph-show-title = Show Tracker Graph
tracker-settings-graph-hide-title = Hide Tracker Graph
## Tracker part card info
tracker-part_card-no_name = No name

View File

@@ -61,6 +61,16 @@ import { FirmwareUpdate } from './components/firmware-update/FirmwareUpdate';
import { ConnectionLost } from './components/onboarding/pages/ConnectionLost';
import { VRCWarningsPage } from './components/vrc/VRCWarningsPage';
import { StayAlignedSetup } from './components/onboarding/pages/stay-aligned/StayAlignedSetup';
import {
Chart as ChartJS,
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement,
} from 'chart.js';
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
export const VersionContext = createContext('');
@@ -73,6 +83,16 @@ function Layout() {
const { isMobile } = useBreakpoint('mobile');
useDiscordPresence();
ChartJS.register(
Title,
Tooltip,
Legend,
CategoryScale,
LinearScale,
PointElement,
LineElement
);
return (
<>
<SerialDetectionModal></SerialDetectionModal>

View File

@@ -0,0 +1,177 @@
import { useLocalization } from '@fluent/react';
import { useEffect, useState } from 'react';
import { Line } from 'react-chartjs-2';
import { TrackerDataT } from 'solarxr-protocol';
import { Button } from '@/components/commons/Button';
import { useConfig } from '@/hooks/config';
export function TrackerGraph({ tracker }: { tracker: TrackerDataT }) {
const { l10n } = useLocalization();
const { config } = useConfig();
type AxisData = {
x: number;
y: number;
time: number;
};
type ChartData = {
x: AxisData[];
y: AxisData[];
z: AxisData[];
};
const [chartData, setChartData] = useState<ChartData>({
x: [],
y: [],
z: [],
});
const [showTrackerGraph, setShowTrackerGraph] = useState(false);
const secondDuration = 60;
useEffect(() => {
if (!showTrackerGraph) {
return;
}
const newValue = tracker.info?.isImu
? tracker.linearAcceleration
: tracker.position;
if (!newValue) {
return;
}
const currentTime = new Date().getTime() / 1000;
const startTime = currentTime - secondDuration;
const updateData = (data: AxisData[], newSample: number) => {
const remapped = data
.filter((value) => value.time >= startTime)
.map((value) => ({ ...value, x: value.time - startTime }));
remapped.push({
time: currentTime,
x: secondDuration,
y: newSample,
});
return remapped;
};
const newData = {
x: updateData(chartData.x, newValue.x),
y: updateData(chartData.y, newValue.y),
z: updateData(chartData.z, newValue.z),
};
setChartData(newData);
}, [tracker]);
useEffect(() => {
if (!showTrackerGraph) {
setChartData({ x: [], y: [], z: [] });
}
}, [showTrackerGraph]);
return (
<>
<Button
variant="tertiary"
className="self-start"
onClick={() => setShowTrackerGraph(!showTrackerGraph)}
>
{l10n.getString(
showTrackerGraph
? 'tracker-settings-graph-hide-title'
: 'tracker-settings-graph-show-title'
)}
</Button>
{showTrackerGraph && (
<div className="h-96">
<Line
options={{
responsive: true,
animation: false,
font: {
family: config?.fonts.map((font) => `"${font}"`).join(','),
size: config?.textSize,
},
plugins: {
title: {
display: true,
text: l10n.getString(
tracker?.info?.isImu
? 'tracker-settings-graph-acceleration-title'
: 'tracker-settings-graph-position-title'
),
color: 'white',
},
tooltip: {
mode: 'index',
intersect: false,
animation: false,
callbacks: {
title: () => '',
},
},
legend: {
labels: {
color: 'white',
},
},
},
scales: {
x: {
type: 'linear',
min: 0,
max: secondDuration,
ticks: {
color: 'white',
},
},
y: {
min: -4,
max: 4,
ticks: {
color: 'white',
},
},
},
elements: {
point: {
radius: 0,
},
},
parsing: false,
normalized: true,
maintainAspectRatio: false,
}}
data={{
labels: ['X', 'Y', 'Z'],
datasets: [
{
label: 'X',
data: chartData.x,
borderColor: 'rgb(200, 50, 50)',
backgroundColor: 'rgb(200, 100, 100)',
},
{
label: 'Y',
data: chartData.y,
borderColor: 'rgb(50, 200, 50)',
backgroundColor: 'rgb(100, 200, 100)',
},
{
label: 'Z',
data: chartData.z,
borderColor: 'rgb(50, 50, 200)',
backgroundColor: 'rgb(100, 100, 200)',
},
],
}}
id="tracker-graph"
/>
</div>
)}
</>
);
}

View File

@@ -40,6 +40,7 @@ import semver from 'semver';
import { useSetAtom } from 'jotai';
import { ignoredTrackersAtom } from '@/store/app-store';
import { checkForUpdate } from '@/hooks/firmware-update';
import { TrackerGraph } from './TrackerGraph';
const rotationsLabels: [Quaternion, string][] = [
[rotationToQuatMap.BACK, 'tracker-rotation-back'],
@@ -505,6 +506,7 @@ export function TrackerSettingsPage() {
</Button>
</div>
)}
{tracker && <TrackerGraph tracker={tracker.tracker} />}
</div>
</div>
</form>

31
pnpm-lock.yaml generated
View File

@@ -83,6 +83,9 @@ importers:
browser-fs-access:
specifier: ^0.35.0
version: 0.35.0
chart.js:
specifier: ^4.5.0
version: 4.5.0
classnames:
specifier: ^2.5.1
version: 2.5.1
@@ -104,6 +107,9 @@ importers:
react:
specifier: ^18.3.1
version: 18.3.1
react-chartjs-2:
specifier: ^5.3.0
version: 5.3.0(chart.js@4.5.0)(react@18.3.1)
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
@@ -720,6 +726,9 @@ packages:
'@jridgewell/trace-mapping@0.3.25':
resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==}
'@kurkle/color@0.3.4':
resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==}
'@mediapipe/tasks-vision@0.10.8':
resolution: {integrity: sha512-Rp7ll8BHrKB3wXaRFKhrltwZl1CiXGdibPxuWXvqGnKTnv8fqa/nvftYNuSbf+pbJWKYCXdBtYTITdAUTGGh0Q==}
@@ -1780,6 +1789,10 @@ packages:
character-reference-invalid@2.0.1:
resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==}
chart.js@4.5.0:
resolution: {integrity: sha512-aYeC/jDgSEx8SHWZvANYMioYMZ2KX02W6f6uVfyteuCGcadDLcYVHdfdygsTQkQ4TKn5lghoojAsPj5pu0SnvQ==}
engines: {pnpm: '>=8'}
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -2470,6 +2483,7 @@ packages:
got-fetch@5.1.10:
resolution: {integrity: sha512-Gwj/A2htjvLEcY07PKDItv0WCPEs3dV2vWeZ+9TVBSKSTuWEZ4oXaMD0ZAOsajwx2orahQWN4HI0MfRyWSZsbg==}
engines: {node: '>=14.0.0'}
deprecated: please use built-in fetch in nodejs
peerDependencies:
got: ^12.0.0
@@ -3542,6 +3556,12 @@ packages:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
react-chartjs-2@5.3.0:
resolution: {integrity: sha512-UfZZFnDsERI3c3CZGxzvNJd02SHjaSJ8kgW1djn65H1KK8rehwTjyrRKOG3VTMG8wtHZ5rgAO5oTHtHi9GCCmw==}
peerDependencies:
chart.js: ^4.1.1
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
react-composer@5.0.3:
resolution: {integrity: sha512-1uWd07EME6XZvMfapwZmc7NgCZqDemcvicRi3wMJzXsQLvZ3L7fTHVyPy1bZdnWXM4iPjYuNE+uJ41MLKeTtnA==}
peerDependencies:
@@ -4959,6 +4979,8 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.4.15
'@kurkle/color@0.3.4': {}
'@mediapipe/tasks-vision@0.10.8': {}
'@mgit-at/typescript-flatbuffers-codegen@0.1.3':
@@ -6072,6 +6094,10 @@ snapshots:
character-reference-invalid@2.0.1: {}
chart.js@4.5.0:
dependencies:
'@kurkle/color': 0.3.4
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -8159,6 +8185,11 @@ snapshots:
quick-lru@5.1.1: {}
react-chartjs-2@5.3.0(chart.js@4.5.0)(react@18.3.1):
dependencies:
chart.js: 4.5.0
react: 18.3.1
react-composer@5.0.3(react@18.3.1):
dependencies:
prop-types: 15.8.1