@itwin/core-frontend 5.13.0-dev.2 → 5.13.0-dev.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -187,9 +187,10 @@ class CurrentInputState {
187
187
  ev.viewPoint = ev.viewport.worldToView(ev.rawPoint);
188
188
  }
189
189
  updateDownPoint(ev) { this.button[ev.button].downUorPt = ev.point; }
190
- onButtonDown(button) {
190
+ onButtonDown(button, eventTime) {
191
191
  let isDoubleClick = false;
192
- const now = Date.now();
192
+ // Use event.timeStamp epoch (performance.now) so comparisons are immune to event-loop stalls
193
+ const now = eventTime ?? performance.now();
193
194
  const vp = this.viewport;
194
195
  if (undefined !== vp) {
195
196
  const viewPt = vp.worldToView(this.button[button].downRawPt);
@@ -266,14 +267,15 @@ class CurrentInputState {
266
267
  }
267
268
  IModelApp_1.IModelApp.toolAdmin.adjustPoint(this._point, vp, true, applyLocks);
268
269
  }
269
- isStartDrag(button) {
270
+ isStartDrag(button, motionEventTime) {
270
271
  // First make sure we aren't already dragging any button
271
272
  if (this.isAnyDragging())
272
273
  return false;
273
274
  const state = this.button[button];
274
275
  if (!state.isDown)
275
276
  return false;
276
- if ((Date.now() - state.downTime) <= ToolSettings_1.ToolSettings.startDragDelay.milliseconds)
277
+ const elapsed = (motionEventTime ?? performance.now()) - state.downTime;
278
+ if (elapsed <= ToolSettings_1.ToolSettings.startDragDelay.milliseconds)
277
279
  return false;
278
280
  const vp = this.viewport;
279
281
  if (undefined === vp)
@@ -493,7 +495,7 @@ class ToolAdmin {
493
495
  const pos = this.getMousePosition(event);
494
496
  const button = this.getMouseButton(ev.button);
495
497
  this.currentInputState.setKeyQualifiers(ev);
496
- return isDown ? this.onButtonDown(vp, pos, button, Tool_1.InputSource.Mouse) : this.onButtonUp(vp, pos, button, Tool_1.InputSource.Mouse);
498
+ return isDown ? this.onButtonDown(vp, pos, button, Tool_1.InputSource.Mouse, ev.timeStamp) : this.onButtonUp(vp, pos, button, Tool_1.InputSource.Mouse);
497
499
  }
498
500
  async onWheel(event) {
499
501
  const ev = event.ev;
@@ -930,7 +932,7 @@ class ToolAdmin {
930
932
  // Pass start drag event to idle tool if active tool doesn't explicitly handle it
931
933
  return this.idleTool.onMouseStartDrag(ev);
932
934
  }
933
- async onMotion(vp, pt2d, inputSource, forceStartDrag = false, movement) {
935
+ async onMotion(vp, pt2d, inputSource, forceStartDrag = false, movement, eventTime) {
934
936
  const current = this.currentInputState;
935
937
  current.onMotion(pt2d);
936
938
  if (this.filterViewport(vp)) {
@@ -952,9 +954,10 @@ class ToolAdmin {
952
954
  }
953
955
  this._mouseMoveOverTimeout = setTimeout(async () => {
954
956
  await this.onMotionEnd(vp, pt2d, inputSource);
955
- await processMotion();
957
+ // Evaluate drag at the nominal timeout fire time, not the frozen event timestamp.
958
+ await processMotion(eventTime !== undefined ? eventTime + 100 : undefined);
956
959
  }, 100);
957
- const processMotion = async () => {
960
+ const processMotion = async (motionTime) => {
958
961
  // Update event to account for AccuSnap adjustments...
959
962
  current.fromButton(vp, pt2d, inputSource, true);
960
963
  current.toEvent(ev, true);
@@ -963,7 +966,7 @@ class ToolAdmin {
963
966
  let tool = this.activeTool;
964
967
  const isValidLocation = (undefined !== tool ? tool.isValidLocation(ev, false) : true);
965
968
  this.setIncompatibleViewportCursor(isValidLocation);
966
- if (forceStartDrag || current.isStartDrag(ev.button)) {
969
+ if (forceStartDrag || current.isStartDrag(ev.button, motionTime)) {
967
970
  current.onStartDrag(ev.button);
968
971
  current.changeButtonToDownPoint(ev);
969
972
  ev.isDragging = true;
@@ -986,14 +989,14 @@ class ToolAdmin {
986
989
  */
987
990
  if (forceStartDrag) {
988
991
  await snapPromise;
989
- return processMotion();
992
+ return processMotion(eventTime);
990
993
  }
991
994
  if (this.isLocateCircleOn)
992
995
  vp.invalidateDecorations();
993
996
  snapPromise.then(async (snapOk) => {
994
997
  if (!snapOk || snapPromise !== this._snapMotionPromise)
995
998
  return;
996
- return processMotion();
999
+ return processMotion(eventTime);
997
1000
  }).catch((_) => { });
998
1001
  }
999
1002
  // Called when we detect that the motion stopped
@@ -1015,7 +1018,7 @@ class ToolAdmin {
1015
1018
  const buttonMask = event.ev.buttons;
1016
1019
  if (!(buttonMask & 1))
1017
1020
  this.currentInputState.button[Tool_1.BeButton.Data].isDown = false;
1018
- return this.onMotion(vp, pos, Tool_1.InputSource.Mouse, false, mov);
1021
+ return this.onMotion(vp, pos, Tool_1.InputSource.Mouse, false, mov, event.ev.timeStamp);
1019
1022
  }
1020
1023
  adjustPointToACS(pointActive, vp, perpendicular) {
1021
1024
  // The "I don't want ACS lock" flag can be set by tools to override the default behavior
@@ -1167,7 +1170,7 @@ class ToolAdmin {
1167
1170
  // Update tool dynamics for current cursor location to not require a motion event.
1168
1171
  this.updateDynamics(undefined, undefined, true);
1169
1172
  }
1170
- async onButtonDown(vp, pt2d, button, inputSource) {
1173
+ async onButtonDown(vp, pt2d, button, inputSource, eventTime) {
1171
1174
  const filtered = this.filterViewport(vp);
1172
1175
  if (undefined === this._viewTool && button === Tool_1.BeButton.Data)
1173
1176
  await IModelApp_1.IModelApp.viewManager.setSelectedView(vp);
@@ -1177,7 +1180,7 @@ class ToolAdmin {
1177
1180
  const ev = new Tool_1.BeButtonEvent();
1178
1181
  const current = this.currentInputState;
1179
1182
  current.fromButton(vp, pt2d, inputSource, true);
1180
- current.onButtonDown(button);
1183
+ current.onButtonDown(button, eventTime);
1181
1184
  current.toEvent(ev, true);
1182
1185
  current.updateDownPoint(ev);
1183
1186
  return this.sendButtonEvent(ev);