@@ -59,27 +59,25 @@ interface CircleInfo {
5959 strokeWidth: number ;
6060}
6161
62+ const TIME_STEPS = [
63+ { unit: ' minute' , factor: 60 },
64+ { unit: ' hour' , factor: 60 },
65+ { unit: ' day' , factor: 24 },
66+ ];
67+
6268function _toSimplifiedTime(millis : number , includeUnit ? : true ): string ;
6369function _toSimplifiedTime(millis : number , includeUnit : false ): number ;
6470function _toSimplifiedTime(millis : number , includeUnit : boolean = true ): number | string {
6571 // find appropriate unit, starting with second
6672 let resultTime = millis / 1000 ;
6773 let resultUnit = ' second' ;
68- const timeSteps = [
69- { unit: ' minute' , factor: 60 },
70- { unit: ' hour' , factor: 60 },
71- { unit: ' day' , factor: 24 },
72- ];
73- for (const { unit, factor } of timeSteps ) {
74- if (resultTime / factor < 1 ) {
75- break ;
76- } else {
77- resultTime /= factor ;
78- resultUnit = unit ;
79- }
74+ for (const { unit, factor } of TIME_STEPS ) {
75+ if (resultTime / factor < 1 ) break ;
76+ resultTime /= factor ;
77+ resultUnit = unit ;
8078 }
8179
82- resultTime = Math .round (resultTime );
80+ resultTime = Math .floor (resultTime );
8381 if (! includeUnit ) {
8482 return resultTime ;
8583 } else {
@@ -215,10 +213,34 @@ class Timer extends Vue {
215213 const circleLengthPixels = this .fullCircleLength * scaleFactor ;
216214 const steps = circleLengthPixels * 3 ; // update every .33 pixel change for smooth transitions
217215 const minInterval = 1000 / 60 ; // up to 60 fps
218- const maxInterval = (this .detailsShown || this .alwaysShowTime ) && this ._timeLeft < 60000
219- ? 500 // when counting down seconds update more regularly
220- : Number .POSITIVE_INFINITY;
221- return Math .max (minInterval , Math .min (maxInterval , this ._totalTime / steps ));
216+ // Constrain interval such that we don't skip time steps in the countdown for the respective time unit.
217+ const timeLeft = this ._timeLeft ;
218+ const totalTime = this ._totalTime ;
219+ const updatesPerTimeStep = 2 ; // multiple updates per time step to avoid skipping a step by a delayed interval
220+ let timeStep = 1000 ; // starting with seconds
221+ let maxInterval = timeStep / updatesPerTimeStep ;
222+ for (const { factor } of TIME_STEPS ) {
223+ const nextTimeStep = timeStep * factor ;
224+ const nextMaxInterval = nextTimeStep / updatesPerTimeStep ;
225+ const nextInterval = Math .min (nextMaxInterval , Math .max (minInterval , totalTime / steps ));
226+ if ((timeLeft - nextInterval ) / nextTimeStep < 1 ) {
227+ // If the time left after nextInterval can't be expressed in nextTimeStep as a value >=1, stop. We check
228+ // for the time after the next interval to avoid jumping for example from 70s (displayed as 1 minute)
229+ // directly to 50s if the interval is 20s. Note that the behavior here resembles the one in
230+ // _toSimplifiedTime.
231+ if (timeLeft / nextTimeStep > 1 ) {
232+ // If the value before the interval is still >1 in the next time unit still allow a larger jump than
233+ // at the smaller time unit but set the maxInterval such that we jump no further than where the
234+ // switch to the smaller unit happens, for example jump from 70s to 60s if the interval is 20s.
235+ maxInterval = timeLeft - nextTimeStep ;
236+ }
237+ break ;
238+ }
239+ timeStep = nextTimeStep ;
240+ maxInterval = nextMaxInterval ;
241+ }
242+
243+ return Math .min (maxInterval , Math .max (minInterval , this ._totalTime / steps ));
222244 }
223245
224246 @Watch (' detailsShown' , { immediate: true })
0 commit comments