mirror of
https://github.com/cpvalente/ontime.git
synced 2026-08-20 14:39:06 +00:00
fix: relative offset with count to end (#1602)
* refactor merge absolute and relative offset calculation * update test
This commit is contained in:
committed by
GitHub
parent
c4b66a9ed3
commit
1f0cde6d0d
@@ -4,7 +4,6 @@ import { EndAction, Playback, TimeStrategy, TimerPhase, TimerType } from 'ontime
|
|||||||
import {
|
import {
|
||||||
getCurrent,
|
getCurrent,
|
||||||
getExpectedFinish,
|
getExpectedFinish,
|
||||||
getRelativeOffset,
|
|
||||||
getRuntimeOffset,
|
getRuntimeOffset,
|
||||||
getTimerPhase,
|
getTimerPhase,
|
||||||
normaliseEndTime,
|
normaliseEndTime,
|
||||||
@@ -741,8 +740,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(-50);
|
expect(absoluteOffset).toBe(-50);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('added time subtracts time offset (positive offset)', () => {
|
it('added time subtracts time offset (positive offset)', () => {
|
||||||
@@ -764,8 +763,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(-60);
|
expect(absoluteOffset).toBe(-60);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('considers running overtime (negative offset)', () => {
|
it('considers running overtime (negative offset)', () => {
|
||||||
@@ -788,8 +787,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(-10);
|
expect(absoluteOffset).toBe(-10);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('paused time is delayed time (negative offset)', () => {
|
it('paused time is delayed time (negative offset)', () => {
|
||||||
@@ -813,8 +812,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(-25);
|
expect(absoluteOffset).toBe(-25);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('offset doesnt exist if we havent started', () => {
|
it('offset doesnt exist if we havent started', () => {
|
||||||
@@ -851,8 +850,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(0);
|
expect(absoluteOffset).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles loaded event', () => {
|
it('handles loaded event', () => {
|
||||||
@@ -892,8 +891,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(81000000 - 79521653); // clock - timestart
|
expect(absoluteOffset).toBe(81000000 - 79521653); // clock - timestart
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with time-to-end, offsets dont exist if we are not in overtime', () => {
|
it('with time-to-end, offsets dont exist if we are not in overtime', () => {
|
||||||
@@ -945,8 +944,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(0);
|
expect(absoluteOffset).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('with time-to-end, offset is the overtime', () => {
|
it('with time-to-end, offset is the overtime', () => {
|
||||||
@@ -998,8 +997,8 @@ describe('getRuntimeOffset()', () => {
|
|||||||
_timer: { pausedAt: null },
|
_timer: { pausedAt: null },
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(offset).toBe(-400000); // <--- offset is always the overtime
|
expect(absoluteOffset).toBe(-400000); // <--- offset is always the overtime
|
||||||
});
|
});
|
||||||
|
|
||||||
it('handles time-to-end started after the end time', () => {
|
it('handles time-to-end started after the end time', () => {
|
||||||
@@ -1041,9 +1040,9 @@ describe('getRuntimeOffset()', () => {
|
|||||||
|
|
||||||
const updateCurrent = getCurrent(state);
|
const updateCurrent = getCurrent(state);
|
||||||
state.timer.current = updateCurrent;
|
state.timer.current = updateCurrent;
|
||||||
const offset = getRuntimeOffset(state);
|
const { absoluteOffset } = getRuntimeOffset(state);
|
||||||
expect(millisToString(offset)).toBe('-00:16:40');
|
expect(millisToString(absoluteOffset)).toBe('-00:16:40');
|
||||||
expect(offset).toBe(81000000 - 82000000); // <-- planned end - now
|
expect(absoluteOffset).toBe(81000000 - 82000000); // <-- planned end - now
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -1068,10 +1067,9 @@ describe('getRelativeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
state.runtime.offset = getRuntimeOffset(state);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(state);
|
||||||
expect(state.runtime.offset).toBe(0);
|
expect(absoluteOffset).toBe(0);
|
||||||
const relativeOffsetoffset = getRelativeOffset(state);
|
expect(relativeOffset).toBe(0);
|
||||||
expect(relativeOffsetoffset).toBe(0);
|
|
||||||
});
|
});
|
||||||
it('relative offset is 0 when starting after the planed time', () => {
|
it('relative offset is 0 when starting after the planed time', () => {
|
||||||
const state = {
|
const state = {
|
||||||
@@ -1093,10 +1091,9 @@ describe('getRelativeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
state.runtime.offset = getRuntimeOffset(state);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(state);
|
||||||
expect(state.runtime.offset).toBe(-50);
|
expect(absoluteOffset).toBe(-50);
|
||||||
const relativeOffsetoffset = getRelativeOffset(state);
|
expect(relativeOffset).toBe(0);
|
||||||
expect(relativeOffsetoffset).toBe(0);
|
|
||||||
});
|
});
|
||||||
it('relative offset is 0 when starting before the planed time', () => {
|
it('relative offset is 0 when starting before the planed time', () => {
|
||||||
const state = {
|
const state = {
|
||||||
@@ -1118,10 +1115,9 @@ describe('getRelativeOffset()', () => {
|
|||||||
},
|
},
|
||||||
} as RuntimeState;
|
} as RuntimeState;
|
||||||
|
|
||||||
state.runtime.offset = getRuntimeOffset(state);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(state);
|
||||||
expect(state.runtime.offset).toBe(50);
|
expect(absoluteOffset).toBe(50);
|
||||||
const relativeOffsetoffset = getRelativeOffset(state);
|
expect(relativeOffset).toBe(0);
|
||||||
expect(relativeOffsetoffset).toBe(0);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -116,10 +116,10 @@ export function skippedOutOfEvent(state: RuntimeState, previousTime: number, ski
|
|||||||
* Positive offset is time ahead
|
* Positive offset is time ahead
|
||||||
* Negative offset is time delayed
|
* Negative offset is time delayed
|
||||||
*/
|
*/
|
||||||
export function getRuntimeOffset(state: RuntimeState): number {
|
export function getRuntimeOffset(state: RuntimeState): { absoluteOffset: number; relativeOffset: number } {
|
||||||
// nothing to calculate if there are no loaded events or if we havent started
|
// nothing to calculate if there are no loaded events or if we havent started
|
||||||
if (state.eventNow === null || state.runtime.actualStart === null) {
|
if (state.eventNow === null || state.runtime.actualStart === null) {
|
||||||
return 0;
|
return { absoluteOffset: 0, relativeOffset: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
// eslint-disable-next-line no-unused-labels -- dev code path
|
||||||
@@ -133,18 +133,16 @@ export function getRuntimeOffset(state: RuntimeState): number {
|
|||||||
const { clock } = state;
|
const { clock } = state;
|
||||||
const { countToEnd, timeStart } = state.eventNow;
|
const { countToEnd, timeStart } = state.eventNow;
|
||||||
const { addedTime, current, startedAt } = state.timer;
|
const { addedTime, current, startedAt } = state.timer;
|
||||||
|
const { actualStart, plannedStart } = state.runtime;
|
||||||
|
|
||||||
// if we havent started, but the timer is armed
|
// if we havent started, but the timer is armed
|
||||||
// the offset is the difference to the schedule
|
// the offset is the difference to the schedule
|
||||||
if (startedAt === null) {
|
if (startedAt === null) {
|
||||||
return timeStart - clock;
|
return { absoluteOffset: timeStart - clock, relativeOffset: 0 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const overtime = Math.min(current, 0);
|
const overtime = Math.min(current, 0);
|
||||||
// in time-to-end, offset is overtime
|
// in time-to-end, offset is overtime
|
||||||
if (countToEnd) {
|
|
||||||
return overtime;
|
|
||||||
}
|
|
||||||
|
|
||||||
const startOffset = timeStart - startedAt;
|
const startOffset = timeStart - startedAt;
|
||||||
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
const pausedTime = state._timer.pausedAt === null ? 0 : clock - state._timer.pausedAt;
|
||||||
@@ -153,24 +151,20 @@ export function getRuntimeOffset(state: RuntimeState): number {
|
|||||||
// addedTime - time added by user (negative offset)
|
// addedTime - time added by user (negative offset)
|
||||||
// pausedTime - time the playback was paused (negative offset)
|
// pausedTime - time the playback was paused (negative offset)
|
||||||
// overtime - how long the timer has been over-running (negative offset)
|
// overtime - how long the timer has been over-running (negative offset)
|
||||||
return startOffset - addedTime - pausedTime + overtime;
|
const offset = startOffset - addedTime - pausedTime + overtime;
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
// offset between planned rundown start and actual rundown start
|
||||||
* Calculates relative offset
|
const rundownStartOffset = actualStart - plannedStart;
|
||||||
* should always be calculated after the absolute offset
|
|
||||||
*/
|
// offset offset relative to the actual rundown start
|
||||||
export function getRelativeOffset(state: RuntimeState): number {
|
const relativeOffset = offset + rundownStartOffset;
|
||||||
const { actualStart, plannedStart, offset } = state.runtime;
|
|
||||||
// eslint-disable-next-line no-unused-labels -- dev code path
|
// in time-to-end, offset is overtime
|
||||||
DEV: {
|
if (countToEnd) {
|
||||||
// we know actualStart and plannedStart exists as long as a timer is running
|
return { absoluteOffset: overtime, relativeOffset };
|
||||||
if (actualStart === null || plannedStart === null) {
|
|
||||||
throw new Error('timerUtils.calculate: actualStart and plannedStart must be set');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const relativeStartOffset = actualStart - plannedStart;
|
|
||||||
return offset + relativeStartOffset;
|
return { absoluteOffset: offset, relativeOffset };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -28,7 +28,6 @@ import {
|
|||||||
getCurrent,
|
getCurrent,
|
||||||
getExpectedEnd,
|
getExpectedEnd,
|
||||||
getExpectedFinish,
|
getExpectedFinish,
|
||||||
getRelativeOffset,
|
|
||||||
getRuntimeOffset,
|
getRuntimeOffset,
|
||||||
getTimerPhase,
|
getTimerPhase,
|
||||||
} from '../services/timerUtils.js';
|
} from '../services/timerUtils.js';
|
||||||
@@ -89,7 +88,7 @@ export function getState(): Readonly<RuntimeState> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/* clear data related to the current event, but leav in place data about the global run state
|
/* clear data related to the current event, but leave in place data about the global run state
|
||||||
* used when loading a new event but the playback is not interrupted
|
* used when loading a new event but the playback is not interrupted
|
||||||
*/
|
*/
|
||||||
export function clearEventData() {
|
export function clearEventData() {
|
||||||
@@ -214,8 +213,9 @@ export function load(
|
|||||||
const firstStart = initialData?.firstStart;
|
const firstStart = initialData?.firstStart;
|
||||||
if (firstStart === null || typeof firstStart === 'number') {
|
if (firstStart === null || typeof firstStart === 'number') {
|
||||||
runtimeState.runtime.actualStart = firstStart;
|
runtimeState.runtime.actualStart = firstStart;
|
||||||
runtimeState.runtime.offset = getRuntimeOffset(runtimeState);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState);
|
||||||
runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState);
|
runtimeState.runtime.offset = absoluteOffset;
|
||||||
|
runtimeState.runtime.relativeOffset = relativeOffset;
|
||||||
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
||||||
}
|
}
|
||||||
if (typeof initialData.blockStartAt === 'number') {
|
if (typeof initialData.blockStartAt === 'number') {
|
||||||
@@ -420,8 +420,9 @@ export function start(state: RuntimeState = runtimeState): boolean {
|
|||||||
runtimeState.timer.phase = getTimerPhase(runtimeState);
|
runtimeState.timer.phase = getTimerPhase(runtimeState);
|
||||||
|
|
||||||
// update offset
|
// update offset
|
||||||
state.runtime.offset = getRuntimeOffset(state);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState);
|
||||||
state.runtime.relativeOffset = getRelativeOffset(state);
|
runtimeState.runtime.offset = absoluteOffset;
|
||||||
|
runtimeState.runtime.relativeOffset = relativeOffset;
|
||||||
state.runtime.expectedEnd = state.runtime.plannedEnd - state.runtime.offset;
|
state.runtime.expectedEnd = state.runtime.plannedEnd - state.runtime.offset;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -482,8 +483,9 @@ export function addTime(amount: number) {
|
|||||||
runtimeState.timer.current += amount;
|
runtimeState.timer.current += amount;
|
||||||
|
|
||||||
// update runtime delays: over - under
|
// update runtime delays: over - under
|
||||||
runtimeState.runtime.offset = getRuntimeOffset(runtimeState);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState);
|
||||||
runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState);
|
runtimeState.runtime.offset = absoluteOffset;
|
||||||
|
runtimeState.runtime.relativeOffset = relativeOffset;
|
||||||
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -528,8 +530,9 @@ export function update(): UpdateResult {
|
|||||||
runtimeState.timer.elapsed = runtimeState.timer.duration - runtimeState.timer.current;
|
runtimeState.timer.elapsed = runtimeState.timer.duration - runtimeState.timer.current;
|
||||||
|
|
||||||
// update runtime, needs up-to-date timer state
|
// update runtime, needs up-to-date timer state
|
||||||
runtimeState.runtime.offset = getRuntimeOffset(runtimeState);
|
const { absoluteOffset, relativeOffset } = getRuntimeOffset(runtimeState);
|
||||||
runtimeState.runtime.relativeOffset = getRelativeOffset(runtimeState);
|
runtimeState.runtime.offset = absoluteOffset;
|
||||||
|
runtimeState.runtime.relativeOffset = relativeOffset;
|
||||||
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
runtimeState.runtime.expectedEnd = getExpectedEnd(runtimeState);
|
||||||
|
|
||||||
const finishedNow =
|
const finishedNow =
|
||||||
|
|||||||
Reference in New Issue
Block a user