on master help sign in
fix for time jumping by introducing a timer offset that hooks into the Time.js library
f612061Michael James
libraries/Native/Signal/Time.js+11−4
@@ -14,8 +14,14 @@ Elm.Native.Time.make = function(elm) {
14 var msPerFrame = 1000 / desiredFPS;
14 var msPerFrame = 1000 / desiredFPS;
15 var prev = Date.now(), curr = prev, diff = 0, wasOn = true;
15 var prev = Date.now(), curr = prev, diff = 0, wasOn = true;
16 var ticker = NS.input(diff);
16 var ticker = NS.input(diff);
17− function tick(zero) { return function() {
17+ function tick(zero) { return function(offset) {
18+ /**
19+ * The offset is used for the debugger module. To pause and
20+ * unpause time in a continuous way (not jumping ahead by seconds)
21+ * or minutes, we introduce a way to offset real time by the amount
22+ * of time spend paused.
23+ */
18− curr = Date.now();
24+ curr = Date.now() - (offset|0 || 0);
19 diff = zero ? 0 : curr - prev;
25 diff = zero ? 0 : curr - prev;
20 prev = curr;
26 prev = curr;
21 elm.notify(ticker.id, diff);
27 elm.notify(ticker.id, diff);
@@ -36,8 +42,9 @@ Elm.Native.Time.make = function(elm) {
36
42
37 function every(t) {
43 function every(t) {
38 var clock = NS.input(Date.now());
44 var clock = NS.input(Date.now());
39− function tellTime() {
45+ function tellTime(offset) {
46+ // Leave the offset. It's for debugging. See above.
40− elm.notify(clock.id, Date.now());
47+ elm.notify(clock.id, Date.now() - (offset|0 || 0));
41 elm.runDelayed(tellTime, t);
48 elm.runDelayed(tellTime, t);
42 }
49 }
43 elm.runDelayed(tellTime, t);
50 elm.runDelayed(tellTime, t);
runtime/Debugger.js+15−5
@@ -40,6 +40,8 @@ function debugModule(module, runtime) {
40 var recordedEvents = [];
40 var recordedEvents = [];
41 var asyncCallbacks = [];
41 var asyncCallbacks = [];
42 var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
42 var watchTracker = Elm.Native.Debug.make(runtime).watchTracker;
43+ var timerOffset = 0;
44+ var now = 0;
43
45
44 function wrapNotify(id, v) {
46 function wrapNotify(id, v) {
45 var timestep = Date.now();
47 var timestep = Date.now();
@@ -68,7 +70,7 @@ function debugModule(module, runtime) {
68 var cbObj = { func:func, delayMs:delayMs, timerId:0, executed:false };
70 var cbObj = { func:func, delayMs:delayMs, timerId:0, executed:false };
69 var timerId = setTimeout(function() {
71 var timerId = setTimeout(function() {
70 cbObj.executed = true;
72 cbObj.executed = true;
71− func();
73+ func(timerOffset);
72 }, delayMs);
74 }, delayMs);
73 cbObj.timerId = timerId;
75 cbObj.timerId = timerId;
74 asyncCallbacks.push(cbObj);
76 asyncCallbacks.push(cbObj);
@@ -108,19 +110,25 @@ function debugModule(module, runtime) {
108 recordedEvents = events.slice();
110 recordedEvents = events.slice();
109 }
111 }
110
112
113+ function resetTimeOffset() {
114+ timerOffset = 0;
115+ }
116+
111 function setPaused() {
117 function setPaused() {
112 programPaused = true;
118 programPaused = true;
113 clearAsyncCallbacks();
119 clearAsyncCallbacks();
114 tracePath.stopRecording();
120 tracePath.stopRecording();
121+ now = Date.now();
115 }
122 }
116
123
117 function setContinue(position) {
124 function setContinue(position) {
125+ timerOffset += Date.now() - now;
118 programPaused = false;
126 programPaused = false;
119 if (position > 0) {
127 if (position > 0) {
120 // If we're not unpausing at the head, then we need to dump the
128 // If we're not unpausing at the head, then we need to dump the
121 // events that are ahead of where we're continuing.
129 // events that are ahead of where we're continuing.
122 recordedEvents = recordedEvents.slice(0,position);
130 recordedEvents = recordedEvents.slice(0,position);
123− executeCallbacks(asyncCallbacks, false);
131+ executeCallbacks(asyncCallbacks, false, timerOffset);
124 }
132 }
125 tracePath.startRecording();
133 tracePath.startRecording();
126 }
134 }
@@ -165,6 +173,7 @@ function debugModule(module, runtime) {
165 getRecordedEventAt: getRecordedEventAt,
173 getRecordedEventAt: getRecordedEventAt,
166 copyRecordedEvents: copyRecordedEvents,
174 copyRecordedEvents: copyRecordedEvents,
167 loadRecordedEvents: loadRecordedEvents,
175 loadRecordedEvents: loadRecordedEvents,
176+ resetTimeOffset: resetTimeOffset,
168 getPaused: getPaused,
177 getPaused: getPaused,
169 setPaused: setPaused,
178 setPaused: setPaused,
170 setContinue: setContinue,
179 setContinue: setContinue,
@@ -188,7 +197,8 @@ function debuggerInit(debugModule, runtime, hotSwapState /* =undefined */) {
188 debugModule.tracePath.clearTraces();
197 debugModule.tracePath.clearTraces();
189 debugModule.clearRecordedEvents();
198 debugModule.clearRecordedEvents();
190 debugModule.setContinue(0);
199 debugModule.setContinue(0);
200+ debugModule.resetTimeOffset();
191− executeCallbacks(debugModule.initialAsyncCallbacks, true);
201+ executeCallbacks(debugModule.initialAsyncCallbacks, true, 0);
192 }
202 }
193
203
194 function pauseProgram() {
204 function pauseProgram() {
@@ -443,12 +453,12 @@ function tracePathInit(runtime, mainNode) {
443}
453}
444
454
445
455
446−function executeCallbacks(callbacks, reexecute) {
456+function executeCallbacks(callbacks, reexecute, offset) {
447 callbacks.forEach(function(timer) {
457 callbacks.forEach(function(timer) {
448 if (reexecute || !timer.executed) {
458 if (reexecute || !timer.executed) {
449 var func = timer.func;
459 var func = timer.func;
450 timer.executed = true;
460 timer.executed = true;
451− func();
461+ func(offset);
452 }
462 }
453 });
463 });
454}
464}