diff options
Diffstat (limited to 'jb-ui/src/models/grlEventsSlice.ts')
| -rw-r--r-- | jb-ui/src/models/grlEventsSlice.ts | 46 |
1 files changed, 28 insertions, 18 deletions
diff --git a/jb-ui/src/models/grlEventsSlice.ts b/jb-ui/src/models/grlEventsSlice.ts index f77bbc1..912c4ca 100644 --- a/jb-ui/src/models/grlEventsSlice.ts +++ b/jb-ui/src/models/grlEventsSlice.ts @@ -1,32 +1,25 @@ import { EventEnvelope } from "@/api_fsb"; import { RootState } from "@/store"; -import { createEntityAdapter, createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { createEntityAdapter, createSelector, createSlice } from '@reduxjs/toolkit'; const eventAdapter = createEntityAdapter({ selectId: (model: EventEnvelope) => model.event_uuid!, sortComparer: (a, b) => { - return b.timestamp!.localeCompare(a.timestamp!); + // ASC by timestamp + return a.timestamp!.localeCompare(b.timestamp!); }, }); const grlEventsSlice = createSlice({ name: 'grlEvents', - // initialState: eventAdapter.getInitialState(), - initialState: eventAdapter.getInitialState({ latestEvent: null as EventEnvelope | null }), + initialState: eventAdapter.getInitialState(), reducers: { + addEvent: eventAdapter.addOne, addEvents: eventAdapter.addMany, - upsertEvent: eventAdapter.upsertOne, // add or update - - // addEvent: eventAdapter.addOne, - addEvent: (state, action: PayloadAction<EventEnvelope>) => { - eventAdapter.addOne(state, action.payload); - const incoming = action.payload.timestamp!; - if (!state.latestEvent || incoming.localeCompare(state.latestEvent.timestamp!) > 0) { - state.latestEvent = action.payload; - } - }, + upsertEvent: eventAdapter.upsertOne, // Add or Update + } }) @@ -35,14 +28,31 @@ export const { addEvent, addEvents, upsertEvent } = grlEventsSlice.actions; -// Add this after the slice, before exports + export const eventSelectors = eventAdapter.getSelectors( (state: RootState) => state.events ); -export const selectLatestEvents = (count: number) => (state: RootState) => - eventSelectors.selectAll(state).slice(0, count); +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 -export const selectLatestEvent = (state: RootState) => state.events.latestEvent; + +// --- 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 |
