@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.
@@ -181,9 +181,10 @@ export class CurrentInputState {
181
181
  ev.viewPoint = ev.viewport.worldToView(ev.rawPoint);
182
182
  }
183
183
  updateDownPoint(ev) { this.button[ev.button].downUorPt = ev.point; }
184
- onButtonDown(button) {
184
+ onButtonDown(button, eventTime) {
185
185
  let isDoubleClick = false;
186
- const now = Date.now();
186
+ // Use event.timeStamp epoch (performance.now) so comparisons are immune to event-loop stalls
187
+ const now = eventTime ?? performance.now();
187
188
  const vp = this.viewport;
188
189
  if (undefined !== vp) {
189
190
  const viewPt = vp.worldToView(this.button[button].downRawPt);
@@ -260,14 +261,15 @@ export class CurrentInputState {
260
261
  }
261
262
  IModelApp.toolAdmin.adjustPoint(this._point, vp, true, applyLocks);
262
263
  }
263
- isStartDrag(button) {
264
+ isStartDrag(button, motionEventTime) {
264
265
  // First make sure we aren't already dragging any button
265
266
  if (this.isAnyDragging())
266
267
  return false;
267
268
  const state = this.button[button];
268
269
  if (!state.isDown)
269
270
  return false;
270
- if ((Date.now() - state.downTime) <= ToolSettings.startDragDelay.milliseconds)
271
+ const elapsed = (motionEventTime ?? performance.now()) - state.downTime;
272
+ if (elapsed <= ToolSettings.startDragDelay.milliseconds)
271
273
  return false;
272
274
  const vp = this.viewport;
273
275
  if (undefined === vp)
@@ -486,7 +488,7 @@ export class ToolAdmin {
486
488
  const pos = this.getMousePosition(event);
487
489
  const button = this.getMouseButton(ev.button);
488
490
  this.currentInputState.setKeyQualifiers(ev);
489
- return isDown ? this.onButtonDown(vp, pos, button, InputSource.Mouse) : this.onButtonUp(vp, pos, button, InputSource.Mouse);
491
+ return isDown ? this.onButtonDown(vp, pos, button, InputSource.Mouse, ev.timeStamp) : this.onButtonUp(vp, pos, button, InputSource.Mouse);
490
492
  }
491
493
  async onWheel(event) {
492
494
  const ev = event.ev;
@@ -923,7 +925,7 @@ export class ToolAdmin {
923
925
  // Pass start drag event to idle tool if active tool doesn't explicitly handle it
924
926
  return this.idleTool.onMouseStartDrag(ev);
925
927
  }
926
- async onMotion(vp, pt2d, inputSource, forceStartDrag = false, movement) {
928
+ async onMotion(vp, pt2d, inputSource, forceStartDrag = false, movement, eventTime) {
927
929
  const current = this.currentInputState;
928
930
  current.onMotion(pt2d);
929
931
  if (this.filterViewport(vp)) {
@@ -945,9 +947,10 @@ export class ToolAdmin {
945
947
  }
946
948
  this._mouseMoveOverTimeout = setTimeout(async () => {
947
949
  await this.onMotionEnd(vp, pt2d, inputSource);
948
- await processMotion();
950
+ // Evaluate drag at the nominal timeout fire time, not the frozen event timestamp.
951
+ await processMotion(eventTime !== undefined ? eventTime + 100 : undefined);
949
952
  }, 100);
950
- const processMotion = async () => {
953
+ const processMotion = async (motionTime) => {
951
954
  // Update event to account for AccuSnap adjustments...
952
955
  current.fromButton(vp, pt2d, inputSource, true);
953
956
  current.toEvent(ev, true);
@@ -956,7 +959,7 @@ export class ToolAdmin {
956
959
  let tool = this.activeTool;
957
960
  const isValidLocation = (undefined !== tool ? tool.isValidLocation(ev, false) : true);
958
961
  this.setIncompatibleViewportCursor(isValidLocation);
959
- if (forceStartDrag || current.isStartDrag(ev.button)) {
962
+ if (forceStartDrag || current.isStartDrag(ev.button, motionTime)) {
960
963
  current.onStartDrag(ev.button);
961
964
  current.changeButtonToDownPoint(ev);
962
965
  ev.isDragging = true;
@@ -979,14 +982,14 @@ export class ToolAdmin {
979
982
  */
980
983
  if (forceStartDrag) {
981
984
  await snapPromise;
982
- return processMotion();
985
+ return processMotion(eventTime);
983
986
  }
984
987
  if (this.isLocateCircleOn)
985
988
  vp.invalidateDecorations();
986
989
  snapPromise.then(async (snapOk) => {
987
990
  if (!snapOk || snapPromise !== this._snapMotionPromise)
988
991
  return;
989
- return processMotion();
992
+ return processMotion(eventTime);
990
993
  }).catch((_) => { });
991
994
  }
992
995
  // Called when we detect that the motion stopped
@@ -1008,7 +1011,7 @@ export class ToolAdmin {
1008
1011
  const buttonMask = event.ev.buttons;
1009
1012
  if (!(buttonMask & 1))
1010
1013
  this.currentInputState.button[BeButton.Data].isDown = false;
1011
- return this.onMotion(vp, pos, InputSource.Mouse, false, mov);
1014
+ return this.onMotion(vp, pos, InputSource.Mouse, false, mov, event.ev.timeStamp);
1012
1015
  }
1013
1016
  adjustPointToACS(pointActive, vp, perpendicular) {
1014
1017
  // The "I don't want ACS lock" flag can be set by tools to override the default behavior
@@ -1160,7 +1163,7 @@ export class ToolAdmin {
1160
1163
  // Update tool dynamics for current cursor location to not require a motion event.
1161
1164
  this.updateDynamics(undefined, undefined, true);
1162
1165
  }
1163
- async onButtonDown(vp, pt2d, button, inputSource) {
1166
+ async onButtonDown(vp, pt2d, button, inputSource, eventTime) {
1164
1167
  const filtered = this.filterViewport(vp);
1165
1168
  if (undefined === this._viewTool && button === BeButton.Data)
1166
1169
  await IModelApp.viewManager.setSelectedView(vp);
@@ -1170,7 +1173,7 @@ export class ToolAdmin {
1170
1173
  const ev = new BeButtonEvent();
1171
1174
  const current = this.currentInputState;
1172
1175
  current.fromButton(vp, pt2d, inputSource, true);
1173
- current.onButtonDown(button);
1176
+ current.onButtonDown(button, eventTime);
1174
1177
  current.toEvent(ev, true);
1175
1178
  current.updateDownPoint(ev);
1176
1179
  return this.sendButtonEvent(ev);