aboutsummaryrefslogtreecommitdiff
path: root/jb-ui/src/models
diff options
context:
space:
mode:
Diffstat (limited to 'jb-ui/src/models')
-rw-r--r--jb-ui/src/models/grlEventsSlice.ts58
1 files changed, 58 insertions, 0 deletions
diff --git a/jb-ui/src/models/grlEventsSlice.ts b/jb-ui/src/models/grlEventsSlice.ts
new file mode 100644
index 0000000..912c4ca
--- /dev/null
+++ b/jb-ui/src/models/grlEventsSlice.ts
@@ -0,0 +1,58 @@
+import { EventEnvelope } from "@/api_fsb";
+import { RootState } from "@/store";
+import { createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit';
+
+const eventAdapter = createEntityAdapter({
+ selectId: (model: EventEnvelope) => model.event_uuid!,
+ sortComparer: (a, b) => {
+ // ASC by timestamp
+ return a.timestamp!.localeCompare(b.timestamp!);
+ },
+});
+
+
+const grlEventsSlice = createSlice({
+ name: 'grlEvents',
+ initialState: eventAdapter.getInitialState(),
+
+ reducers: {
+ addEvent: eventAdapter.addOne,
+ addEvents: eventAdapter.addMany,
+ upsertEvent: eventAdapter.upsertOne, // Add or Update
+
+ }
+})
+
+
+export const {
+ addEvent, addEvents, upsertEvent
+} = grlEventsSlice.actions;
+
+
+export const eventSelectors = eventAdapter.getSelectors(
+ (state: RootState) => state.events
+);
+
+export const selectAllEvents = (state: RootState): EventEnvelope[] => eventSelectors.selectAll(state);
+
+const BASE_SPEED = 40; // px/sec at idle
+const MAX_SPEED = 380; // px/sec at surge
+
+const RATE_WINDOW_MS = 10_000; // ms window to measure message frequency
+const RATE_TO_SPEED = 55; // px/sec added per msg/sec
+
+
+// --- Speed: derived from arrival rate of recent items ---
+export const selectCurrentSpeed = createSelector(selectAllEvents, (items) => {
+ const now = Date.now();
+
+ const recentCount = items.filter((m) => {
+ const ts = new Date(m.timestamp!).getTime();
+ return now - ts < RATE_WINDOW_MS;
+ }).length;
+
+ const rate = recentCount / (RATE_WINDOW_MS / 1_000); // msgs/sec
+ return Math.min(BASE_SPEED + rate * RATE_TO_SPEED, MAX_SPEED);
+});
+
+export default grlEventsSlice.reducer