| POS | BIB | ATHLETE (選手名) | DIVISION | CURRENT STAGE & PROGRESS (現在の種目 / 全進捗) | START TIME | TIME (ネットタイム / スプリット) |
|---|---|---|---|---|---|---|
| 「速報更新」ボタンを押すとリアルタイム公式タイムを集計します。 | ||||||
/api/getTagData から取得される「受信検知ログ(JSON)」と、それを解析してリーダーボードを出力する「集計JavaScriptコード」のサンプルです。
[
{
"apiUid": "rXdemo00000001",
"date": "2026-09-01",
"serverTimestamp": 1788220890000,
"stationId": 1,
"tagId": "A1B2C3D4E5F6789012345678",
"time": "09:01:30",
"name": "山崎 翔太",
"number": "101",
"category": "Hyrox Pro Men"
},
{
"apiUid": "rXdemo00000001",
"date": "2026-09-01",
"serverTimestamp": 1788221130000,
"stationId": 2,
"tagId": "A1B2C3D4E5F6789012345678",
"time": "09:05:30",
"name": "山崎 翔太",
"number": "101",
"category": "Hyrox Pro Men"
},
{
"apiUid": "rXdemo00000001",
"date": "2026-09-01",
"serverTimestamp": 1788221340000,
"stationId": 2,
"tagId": "A1B2C3D4E5F6789012345678",
"time": "09:09:00",
"name": "山崎 翔太",
"number": "101",
"category": "Hyrox Pro Men"
}
]
function processHyroxLogs(rawApiLogs) {
const athleteMap = {};
// 1. タグIDごとにログをグループ化
rawApiLogs.forEach(log => {
if (!athleteMap[log.tagId]) {
athleteMap[log.tagId] = {
name: log.name || '未登録',
bib: log.number || log.bibNumber || '-',
category: log.category || 'Hyrox',
logs: []
};
}
athleteMap[log.tagId].logs.push(log);
});
// 2. スタート時間・ネットタイム・区間タイムを計算
return Object.values(athleteMap).map(athlete => {
athlete.logs.sort((a, b) => a.serverTimestamp - b.serverTimestamp);
const startLog = athlete.logs[0];
const lastLog = athlete.logs[athlete.logs.length - 1];
// 総経過時間 (ミリ秒)
const netTimeMs = lastLog.serverTimestamp - startLog.serverTimestamp;
// ワークアウト区間タイム (Station 2〜9 入場〜退場)
const workoutSplits = {};
for (let s = 2; s <= 9; s++) {
const sLogs = athlete.logs.filter(l => l.stationId === s);
if (sLogs.length >= 2) {
workoutSplits[`WORKOUT_${s - 1}`] =
sLogs[sLogs.length - 1].serverTimestamp - sLogs[0].serverTimestamp;
}
}
return {
bib: athlete.bib,
name: athlete.name,
startTime: startLog.time,
netTimeMs: netTimeMs,
workoutSplits: workoutSplits
};
});
}