@itwin/imodel-components-react 5.18.0 → 5.20.0

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/lib/imodel-components-react/UiIModelComponents.js +1 -1
  3. package/lib/imodel-components-react/UiIModelComponents.js.map +1 -1
  4. package/lib/imodel-components-react/color/AlphaSlider.js +100 -100
  5. package/lib/imodel-components-react/color/AlphaSlider.js.map +1 -1
  6. package/lib/imodel-components-react/editors/ColorEditor.js +20 -23
  7. package/lib/imodel-components-react/editors/ColorEditor.js.map +1 -1
  8. package/lib/imodel-components-react/editors/WeightEditor.js +21 -21
  9. package/lib/imodel-components-react/editors/WeightEditor.js.map +1 -1
  10. package/lib/imodel-components-react/lineweight/WeightPickerButton.js +53 -53
  11. package/lib/imodel-components-react/lineweight/WeightPickerButton.js.map +1 -1
  12. package/lib/imodel-components-react/navigationaids/Cube.js +1 -4
  13. package/lib/imodel-components-react/navigationaids/Cube.js.map +1 -1
  14. package/lib/imodel-components-react/navigationaids/CubeNavigationAid.js +296 -302
  15. package/lib/imodel-components-react/navigationaids/CubeNavigationAid.js.map +1 -1
  16. package/lib/imodel-components-react/navigationaids/DrawingNavigationAid.js +428 -425
  17. package/lib/imodel-components-react/navigationaids/DrawingNavigationAid.js.map +1 -1
  18. package/lib/imodel-components-react/timeline/BaseSolarDataProvider.js +20 -17
  19. package/lib/imodel-components-react/timeline/BaseSolarDataProvider.js.map +1 -1
  20. package/lib/imodel-components-react/timeline/BaseTimelineDataProvider.js +13 -10
  21. package/lib/imodel-components-react/timeline/BaseTimelineDataProvider.js.map +1 -1
  22. package/lib/imodel-components-react/timeline/InlineEdit.js +20 -20
  23. package/lib/imodel-components-react/timeline/InlineEdit.js.map +1 -1
  24. package/lib/imodel-components-react/timeline/SolarTimeline.js +144 -144
  25. package/lib/imodel-components-react/timeline/SolarTimeline.js.map +1 -1
  26. package/lib/imodel-components-react/viewport/ViewportComponentEvents.js +16 -15
  27. package/lib/imodel-components-react/viewport/ViewportComponentEvents.js.map +1 -1
  28. package/package.json +8 -9
@@ -30,384 +30,21 @@ export var MapMode;
30
30
  * @public
31
31
  */
32
32
  export class DrawingNavigationAid extends React.Component {
33
+ _rootElement = React.createRef();
34
+ _viewContainerElement = React.createRef();
35
+ _viewElement = React.createRef();
36
+ _rootOffset = DOMRect.fromRect({
37
+ x: 0,
38
+ y: 0,
39
+ width: 0,
40
+ height: 0,
41
+ });
42
+ _viewport;
43
+ _animationFrame;
44
+ _mounted = false;
45
+ state;
33
46
  constructor(props) {
34
47
  super(props);
35
- this._rootElement = React.createRef();
36
- this._viewContainerElement = React.createRef();
37
- this._viewElement = React.createRef();
38
- this._rootOffset = DOMRect.fromRect({
39
- x: 0,
40
- y: 0,
41
- width: 0,
42
- height: 0,
43
- });
44
- this._mounted = false;
45
- this._isViewport3D = () => {
46
- return this.state.view !== undefined && this.state.view.is3d();
47
- };
48
- this._animation = () => {
49
- const t = Date.now();
50
- const delta = this._lastTime ? t - this._lastTime : 16;
51
- this._lastTime = t;
52
- if (this.state.animation !== 1) {
53
- const animation = Math.min(1, this.state.animation +
54
- delta / (1000 * (this.props.animationTime || 0.4)));
55
- this._updateFrustum();
56
- if (this._mounted) {
57
- this.setState({ animation }, () => {
58
- this._animationFrame = setTimeout(this._animation, 16.667);
59
- });
60
- }
61
- }
62
- else {
63
- this._lastTime = undefined;
64
- this._animationEnd();
65
- }
66
- };
67
- this._animationEnd = () => {
68
- const hasViewportMoved = !this.state.origin.isAlmostEqual(this.state.startOrigin) ||
69
- !this.state.rotation.isAlmostEqual(this.state.startRotation);
70
- const startMapOrigin = Point3d.createFrom(this.state.mapOrigin);
71
- const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
72
- const startDrawingZoom = this.state.drawingZoom;
73
- const startOrigin = this.state.origin;
74
- const startRotation = this.state.rotation;
75
- if (this._mounted) {
76
- this.setState({
77
- startMapOrigin,
78
- startDrawingZoom,
79
- startOrigin,
80
- startRotation,
81
- startMapExtents,
82
- }, () => {
83
- if (this.props.onAnimationEnd)
84
- this.props.onAnimationEnd();
85
- if (hasViewportMoved)
86
- this._updateFrustum(true);
87
- });
88
- }
89
- };
90
- this._panAnimation = () => {
91
- const t = Date.now();
92
- if (this._lastPanTime === undefined)
93
- this._lastPanTime = t - 16.667;
94
- const delta = t - this._lastPanTime;
95
- this._lastPanTime = t;
96
- if (!this.state.panningDirection.isAlmostZero && this.state.isMoving) {
97
- const { panningDirection } = this.state;
98
- const offset = panningDirection.scale(delta / 1000 / this.state.drawingZoom);
99
- const mapOrigin = this.state.mapOrigin.plus(offset);
100
- const origin = this.state.origin.plus(offset);
101
- this._updateFrustum();
102
- if (this._mounted) {
103
- this.setState({ mapOrigin, origin, panningDirection }, () => {
104
- this._animationFrame = setTimeout(this._panAnimation, 16.667);
105
- });
106
- }
107
- }
108
- else {
109
- this._lastPanTime = undefined;
110
- this._updateFrustum(true);
111
- }
112
- };
113
- // Synchronize with rotation coming from the Viewport
114
- this._handleViewRotationChangeEvent = (args) => {
115
- if (!this.state.isMoving &&
116
- !this.state.isPanning &&
117
- this.props.viewport === args.viewport) {
118
- const extents = args.viewport.view.getExtents().clone();
119
- const rotation = args.viewport.view.getRotation().clone();
120
- const halfExtents = extents.scale(0.5);
121
- const offset = this.state.rotateMinimapWithView || this._isViewport3D()
122
- ? rotation.multiplyTransposeVector(halfExtents)
123
- : halfExtents;
124
- const origin = args.viewport.view.getOrigin().plus(offset);
125
- const deltaZoom = (this.state.extents.x - extents.x) / this.state.extents.x;
126
- let drawingZoom = this.state.drawingZoom / (1 - deltaZoom);
127
- const deltaOrigin = origin.minus(this.state.origin);
128
- let mapOrigin = this.state.mapOrigin.plus(deltaOrigin);
129
- mapOrigin = mapOrigin.plus(Vector3d.createFrom(origin.minus(mapOrigin)).scale(deltaZoom));
130
- if (this.state.viewId !== args.viewport.view.id) {
131
- const rect = this.state.rotateMinimapWithView || this._isViewport3D()
132
- ? extents
133
- : DrawingNavigationAid.findRotatedWindowDimensions(extents, rotation);
134
- const maxRectDim = Math.max(rect.y, rect.x);
135
- const maxExtentDim = Math.max(this.state.mapExtents.x, this.state.mapExtents.y);
136
- drawingZoom = maxExtentDim / (3 * maxRectDim);
137
- mapOrigin = origin.clone();
138
- this._viewport = args.viewport;
139
- this.setState({
140
- viewId: args.viewport.view.id,
141
- view: args.viewport.view.clone(),
142
- });
143
- }
144
- if (this._mounted) {
145
- this.setState({
146
- startOrigin: origin,
147
- origin,
148
- extents,
149
- startRotation: rotation,
150
- rotation,
151
- startMapOrigin: mapOrigin,
152
- mapOrigin,
153
- startDrawingZoom: drawingZoom,
154
- drawingZoom,
155
- });
156
- }
157
- }
158
- };
159
- this._updateFrustum = (complete = false) => {
160
- const halfExtents = this.state.extents.scale(0.5);
161
- const offset = this.state.rotateMinimapWithView || this._isViewport3D()
162
- ? this.state.rotation.multiplyTransposeVector(halfExtents)
163
- : halfExtents;
164
- const origin = this.state.origin.minus(offset);
165
- ViewportComponentEvents.setDrawingViewportState(origin, this.state.rotation, complete);
166
- };
167
- this._toggleRotationMode = () => {
168
- const rotateMinimapWithView = !this.state.rotateMinimapWithView;
169
- this.setState({ rotateMinimapWithView }, () => {
170
- if (this._viewport)
171
- this._handleViewRotationChangeEvent({ viewport: this._viewport });
172
- });
173
- };
174
- this._handleKeyUp = (event) => {
175
- if (event.key === Key.Escape.valueOf() &&
176
- this.state.mode === MapMode.Opened) {
177
- this._closeLargeMap();
178
- }
179
- };
180
- this._lastClientXY = Point2d.createZero();
181
- this._handleMouseDown = (event) => {
182
- // Used only to determine if mouse was moved between mousedown and mouseup
183
- const mouseStart = Point2d.create(event.clientX, event.clientY);
184
- this.setState({ mouseStart });
185
- this._lastClientXY = Point2d.create(event.clientX, event.clientY);
186
- };
187
- this._handleDrawingMouseDown = (event) => {
188
- if (this.state.mode === MapMode.Opened) {
189
- event.preventDefault();
190
- this.setState({ isPanning: true });
191
- }
192
- };
193
- this._handleWindowMouseDown = (event) => {
194
- event.preventDefault();
195
- this.setState({ isMoving: true });
196
- };
197
- this._handleMouseDrag = (event) => {
198
- const mouse = Point2d.create(event.clientX, event.clientY);
199
- const movement = mouse.minus(this._lastClientXY);
200
- if (this.state.isMoving) {
201
- // add scaled mouse movement
202
- this._processWindowDrag(movement);
203
- }
204
- else {
205
- if (this.state.isPanning && this.state.mode === MapMode.Opened) {
206
- const vect = Vector3d.create(movement.x / this.state.drawingZoom, -movement.y / this.state.drawingZoom, 0);
207
- const offset = this.state.rotateMinimapWithView || this._isViewport3D()
208
- ? this.state.rotation.multiplyTransposeVector(vect)
209
- : vect;
210
- const mapOrigin = this.state.mapOrigin.minus(offset);
211
- this.setState({ startMapOrigin: mapOrigin, mapOrigin });
212
- }
213
- }
214
- this._lastClientXY = mouse;
215
- };
216
- this._handleMouseDragEnd = (event) => {
217
- const mouse = Point2d.create(event.clientX, event.clientY);
218
- if (mouse.isAlmostEqual(this.state.mouseStart) &&
219
- this.state.mode === MapMode.Closed &&
220
- (event.target === this._viewContainerElement.current ||
221
- event.target === this._viewElement.current)) {
222
- this._openLargeMap();
223
- }
224
- else if (this.state.isMoving) {
225
- this._processWindowEndDrag();
226
- }
227
- else if (this.state.isPanning) {
228
- if (this.state.mode === MapMode.Opened) {
229
- event.stopPropagation();
230
- this.setState({ isPanning: false });
231
- }
232
- }
233
- else if ((!(event.target instanceof Node) ||
234
- (this._rootElement.current &&
235
- !this._rootElement.current.contains(event.target))) &&
236
- mouse.isAlmostEqual(this.state.mouseStart)) {
237
- this._closeLargeMap();
238
- }
239
- this._lastClientXY = Point2d.create(event.clientX, event.clientY);
240
- };
241
- this._handleWindowTouchStart = (event) => {
242
- if (1 !== event.targetTouches.length)
243
- return;
244
- window.addEventListener("touchmove", this._onTouchMove, false);
245
- window.addEventListener("touchend", this._onTouchEnd, false);
246
- const mouseStart = Point2d.create(event.targetTouches[0].clientX, event.targetTouches[0].clientY);
247
- this.setState({ mouseStart });
248
- this._lastClientXY = mouseStart.clone();
249
- this.setState({ isMoving: true });
250
- };
251
- this._onTouchMove = (event) => {
252
- if (1 !== event.targetTouches.length)
253
- return;
254
- const mouse = Point2d.create(event.targetTouches[0].clientX, event.targetTouches[0].clientY);
255
- const movement = mouse.minus(this._lastClientXY);
256
- // add scaled mouse movement
257
- this._processWindowDrag(movement);
258
- this._lastClientXY = mouse;
259
- };
260
- this._onTouchEnd = (event) => {
261
- if (0 !== event.targetTouches.length)
262
- return;
263
- this._processWindowEndDrag();
264
- if (0 !== event.changedTouches.length)
265
- this._lastClientXY = Point2d.create(event.changedTouches[0].clientX, event.changedTouches[0].clientY); // Doesn't seem necessary...but _handleMouseDragEnd sets it...
266
- window.removeEventListener("touchmove", this._onTouchMove);
267
- window.removeEventListener("touchend", this._onTouchEnd);
268
- };
269
- this._getClosedMapSize = () => {
270
- if (this.props.closeSize === undefined)
271
- return DrawingNavigationAid.getDefaultClosedMapSize();
272
- return this.props.closeSize;
273
- };
274
- this._getOpenedMapSize = () => {
275
- if (this.props.openSize === undefined)
276
- return DrawingNavigationAid.getDefaultOpenedMapSize(this._rootOffset.right, this._rootOffset.top);
277
- return this.props.openSize;
278
- };
279
- this._openLargeMap = () => {
280
- if (this.state.mode === MapMode.Closed && this.state.animation === 1.0) {
281
- if (this._rootElement.current) {
282
- const rect = this._rootElement.current.getBoundingClientRect();
283
- this._rootOffset = rect;
284
- }
285
- const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
286
- const mapExtents = this._getOpenedMapSize();
287
- this.setState({
288
- mode: MapMode.Opened,
289
- isMoving: false,
290
- isPanning: false,
291
- mapExtents,
292
- startMapExtents,
293
- animation: 0,
294
- }, () => {
295
- this._animationFrame = setTimeout(this._animation);
296
- });
297
- }
298
- };
299
- this._closeLargeMap = () => {
300
- if (this.state.mode === MapMode.Opened && this.state.animation === 1.0) {
301
- const startMapOrigin = this.state.mapOrigin;
302
- const mapOrigin = this.state.origin.clone();
303
- const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
304
- const mapExtents = this._getClosedMapSize();
305
- const rect = this.state.rotateMinimapWithView || this._isViewport3D()
306
- ? this.state.extents
307
- : DrawingNavigationAid.findRotatedWindowDimensions(this.state.extents, this.state.rotation);
308
- const maxRectDim = Math.max(rect.y, rect.x);
309
- const maxExtentDim = Math.max(mapExtents.x, mapExtents.y);
310
- const drawingZoom = maxExtentDim / (3 * maxRectDim);
311
- const startDrawingZoom = this.state.drawingZoom;
312
- this.setState({
313
- mode: MapMode.Closed,
314
- startMapOrigin,
315
- mapOrigin,
316
- startDrawingZoom,
317
- drawingZoom,
318
- isMoving: false,
319
- isPanning: false,
320
- startMapExtents,
321
- mapExtents,
322
- panningDirection: Vector3d.createZero(),
323
- animation: 0,
324
- }, () => {
325
- this._animationFrame = setTimeout(this._animation, 16.667);
326
- });
327
- }
328
- };
329
- this._getPanVector = () => {
330
- const is3D = this._isViewport3D();
331
- const rect = this.state.rotateMinimapWithView || is3D
332
- ? this.state.extents
333
- : DrawingNavigationAid.findRotatedWindowDimensions(this.state.extents, this.state.rotation);
334
- const mapExtents = this.state.mapExtents.scale(1 / this.state.drawingZoom);
335
- const maxMagnitude = 80; // maximum acceleration
336
- const magnitudeTravel = 30; // How far, in pixels, that magnitude increases from 0 to max acceleration
337
- const diff = Vector3d.createFrom(this.state.origin.minus(this.state.mapOrigin));
338
- const diffVector = this.state.rotateMinimapWithView || is3D
339
- ? this.state.rotation.multiplyVector(diff)
340
- : diff;
341
- // capture any values
342
- const magnitudeVector = Vector3d.create(Math.max(0, Math.abs(diffVector.x) - (mapExtents.x - rect.x) / 2), Math.max(0, Math.abs(diffVector.y) - (mapExtents.y - rect.y) / 2));
343
- if (magnitudeVector.isAlmostZero)
344
- return Vector3d.createZero();
345
- const magnitude = (Math.min(magnitudeVector.magnitude() * this.state.drawingZoom, magnitudeTravel) /
346
- magnitudeTravel) *
347
- maxMagnitude;
348
- const vect = Vector3d.createFrom(this.state.origin.minus(this.state.mapOrigin)); // vect will never be zero or magnitude would also be zero
349
- const norm = vect.normalize();
350
- return norm.scale(magnitude); // norm is only undefined when vect is zero, in which it would have returned at magnitudeVector.isAlmostZero
351
- };
352
- this._handleWheel = (event) => {
353
- if (this.state.mode === MapMode.Opened && this.state.animation === 1) {
354
- const { mapOrigin, drawingZoom } = this.state;
355
- const mapSize = this._getOpenedMapSize();
356
- const mouseX = event.clientX - this._rootOffset.right + mapSize.x / 2;
357
- const mouseY = event.clientY - this._rootOffset.top - mapSize.y / 2;
358
- const is3D = this._isViewport3D();
359
- if (event.deltaY < 0) {
360
- const zoom = drawingZoom * 1.1;
361
- const vect = Vector3d.create((mouseX * 0.1) / zoom, (-mouseY * 0.1) / zoom, 0);
362
- const offset = this.state.rotateMinimapWithView || is3D
363
- ? this.state.rotation.multiplyTransposeVector(vect)
364
- : vect;
365
- const m = mapOrigin.plus(offset);
366
- this.setState({ mapOrigin: m, drawingZoom: zoom });
367
- }
368
- if (event.deltaY > 0) {
369
- const zoom = drawingZoom / 1.1;
370
- const vect = Vector3d.create((mouseX * 0.1) / drawingZoom, (-mouseY * 0.1) / drawingZoom, 0);
371
- const offset = this.state.rotateMinimapWithView || is3D
372
- ? this.state.rotation.multiplyTransposeVector(vect)
373
- : vect;
374
- const m = mapOrigin.minus(offset);
375
- this.setState({ mapOrigin: m, drawingZoom: zoom });
376
- }
377
- }
378
- };
379
- this._handleZoomIn = () => {
380
- const zoom = this.state.drawingZoom * 1.4;
381
- this.setState({ drawingZoom: zoom });
382
- };
383
- this._handleZoomOut = () => {
384
- const zoom = this.state.drawingZoom / 1.4;
385
- this.setState({ drawingZoom: zoom });
386
- };
387
- this._handleUnrotate = () => {
388
- const startRotation = this.state.rotation;
389
- const halfExtents = this.state.extents.scale(0.5);
390
- const offset = this.state.rotateMinimapWithView || this._isViewport3D()
391
- ? Vector3d.createZero()
392
- : this.state.rotation
393
- .multiplyTransposeVector(halfExtents)
394
- .minus(halfExtents);
395
- const startOrigin = this.state.origin;
396
- const origin = this.state.origin.plus(offset);
397
- const startMapOrigin = this.state.mapOrigin;
398
- const mapOrigin = this.state.mapOrigin.plus(offset);
399
- this.setState({
400
- animation: 0,
401
- startOrigin,
402
- origin,
403
- startMapOrigin,
404
- mapOrigin,
405
- startRotation,
406
- rotation: Matrix3d.createIdentity(),
407
- }, () => {
408
- this._animationFrame = setTimeout(this._animation, 16.667);
409
- });
410
- };
411
48
  const mode = props.initialMapMode || MapMode.Closed;
412
49
  const mapExtents = mode === MapMode.Closed
413
50
  ? this._getClosedMapSize()
@@ -527,6 +164,77 @@ export class DrawingNavigationAid extends React.Component {
527
164
  return ReactDOM.createPortal(nodes, drawingPortal);
528
165
  }
529
166
  }
167
+ _isViewport3D = () => {
168
+ return this.state.view !== undefined && this.state.view.is3d();
169
+ };
170
+ _lastTime;
171
+ static _animationFn = (t) => t < 0.5 ? 2 * t ** 2 : -1 + (4 - 2 * t) * t;
172
+ _animation = () => {
173
+ const t = Date.now();
174
+ const delta = this._lastTime ? t - this._lastTime : 16;
175
+ this._lastTime = t;
176
+ if (this.state.animation !== 1) {
177
+ const animation = Math.min(1, this.state.animation +
178
+ delta / (1000 * (this.props.animationTime || 0.4)));
179
+ this._updateFrustum();
180
+ if (this._mounted) {
181
+ this.setState({ animation }, () => {
182
+ this._animationFrame = setTimeout(this._animation, 16.667);
183
+ });
184
+ }
185
+ }
186
+ else {
187
+ this._lastTime = undefined;
188
+ this._animationEnd();
189
+ }
190
+ };
191
+ _animationEnd = () => {
192
+ const hasViewportMoved = !this.state.origin.isAlmostEqual(this.state.startOrigin) ||
193
+ !this.state.rotation.isAlmostEqual(this.state.startRotation);
194
+ const startMapOrigin = Point3d.createFrom(this.state.mapOrigin);
195
+ const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
196
+ const startDrawingZoom = this.state.drawingZoom;
197
+ const startOrigin = this.state.origin;
198
+ const startRotation = this.state.rotation;
199
+ if (this._mounted) {
200
+ this.setState({
201
+ startMapOrigin,
202
+ startDrawingZoom,
203
+ startOrigin,
204
+ startRotation,
205
+ startMapExtents,
206
+ }, () => {
207
+ if (this.props.onAnimationEnd)
208
+ this.props.onAnimationEnd();
209
+ if (hasViewportMoved)
210
+ this._updateFrustum(true);
211
+ });
212
+ }
213
+ };
214
+ _lastPanTime;
215
+ _panAnimation = () => {
216
+ const t = Date.now();
217
+ if (this._lastPanTime === undefined)
218
+ this._lastPanTime = t - 16.667;
219
+ const delta = t - this._lastPanTime;
220
+ this._lastPanTime = t;
221
+ if (!this.state.panningDirection.isAlmostZero && this.state.isMoving) {
222
+ const { panningDirection } = this.state;
223
+ const offset = panningDirection.scale(delta / 1000 / this.state.drawingZoom);
224
+ const mapOrigin = this.state.mapOrigin.plus(offset);
225
+ const origin = this.state.origin.plus(offset);
226
+ this._updateFrustum();
227
+ if (this._mounted) {
228
+ this.setState({ mapOrigin, origin, panningDirection }, () => {
229
+ this._animationFrame = setTimeout(this._panAnimation, 16.667);
230
+ });
231
+ }
232
+ }
233
+ else {
234
+ this._lastPanTime = undefined;
235
+ this._updateFrustum(true);
236
+ }
237
+ };
530
238
  componentDidMount() {
531
239
  this._mounted = true;
532
240
  ViewportComponentEvents.onViewRotationChangeEvent.addListener(this._handleViewRotationChangeEvent);
@@ -550,6 +258,74 @@ export class DrawingNavigationAid extends React.Component {
550
258
  }
551
259
  this._mounted = false;
552
260
  }
261
+ // Synchronize with rotation coming from the Viewport
262
+ _handleViewRotationChangeEvent = (args) => {
263
+ if (!this.state.isMoving &&
264
+ !this.state.isPanning &&
265
+ this.props.viewport === args.viewport) {
266
+ const extents = args.viewport.view.getExtents().clone();
267
+ const rotation = args.viewport.view.getRotation().clone();
268
+ const halfExtents = extents.scale(0.5);
269
+ const offset = this.state.rotateMinimapWithView || this._isViewport3D()
270
+ ? rotation.multiplyTransposeVector(halfExtents)
271
+ : halfExtents;
272
+ const origin = args.viewport.view.getOrigin().plus(offset);
273
+ const deltaZoom = (this.state.extents.x - extents.x) / this.state.extents.x;
274
+ let drawingZoom = this.state.drawingZoom / (1 - deltaZoom);
275
+ const deltaOrigin = origin.minus(this.state.origin);
276
+ let mapOrigin = this.state.mapOrigin.plus(deltaOrigin);
277
+ mapOrigin = mapOrigin.plus(Vector3d.createFrom(origin.minus(mapOrigin)).scale(deltaZoom));
278
+ if (this.state.viewId !== args.viewport.view.id) {
279
+ const rect = this.state.rotateMinimapWithView || this._isViewport3D()
280
+ ? extents
281
+ : DrawingNavigationAid.findRotatedWindowDimensions(extents, rotation);
282
+ const maxRectDim = Math.max(rect.y, rect.x);
283
+ const maxExtentDim = Math.max(this.state.mapExtents.x, this.state.mapExtents.y);
284
+ drawingZoom = maxExtentDim / (3 * maxRectDim);
285
+ mapOrigin = origin.clone();
286
+ this._viewport = args.viewport;
287
+ this.setState({
288
+ viewId: args.viewport.view.id,
289
+ view: args.viewport.view.clone(),
290
+ });
291
+ }
292
+ if (this._mounted) {
293
+ this.setState({
294
+ startOrigin: origin,
295
+ origin,
296
+ extents,
297
+ startRotation: rotation,
298
+ rotation,
299
+ startMapOrigin: mapOrigin,
300
+ mapOrigin,
301
+ startDrawingZoom: drawingZoom,
302
+ drawingZoom,
303
+ });
304
+ }
305
+ }
306
+ };
307
+ _updateFrustum = (complete = false) => {
308
+ const halfExtents = this.state.extents.scale(0.5);
309
+ const offset = this.state.rotateMinimapWithView || this._isViewport3D()
310
+ ? this.state.rotation.multiplyTransposeVector(halfExtents)
311
+ : halfExtents;
312
+ const origin = this.state.origin.minus(offset);
313
+ ViewportComponentEvents.setDrawingViewportState(origin, this.state.rotation, complete);
314
+ };
315
+ _toggleRotationMode = () => {
316
+ const rotateMinimapWithView = !this.state.rotateMinimapWithView;
317
+ this.setState({ rotateMinimapWithView }, () => {
318
+ if (this._viewport)
319
+ this._handleViewRotationChangeEvent({ viewport: this._viewport });
320
+ });
321
+ };
322
+ _handleKeyUp = (event) => {
323
+ if (event.key === Key.Escape.valueOf() &&
324
+ this.state.mode === MapMode.Opened) {
325
+ this._closeLargeMap();
326
+ }
327
+ };
328
+ _lastClientXY = Point2d.createZero();
553
329
  _processWindowDrag(movement) {
554
330
  const vect = Vector3d.create(movement.x / this.state.drawingZoom, -movement.y / this.state.drawingZoom, 0);
555
331
  const offset = this.state.rotateMinimapWithView || this._isViewport3D()
@@ -580,58 +356,275 @@ export class DrawingNavigationAid extends React.Component {
580
356
  }, 0);
581
357
  }
582
358
  }
359
+ _handleMouseDown = (event) => {
360
+ // Used only to determine if mouse was moved between mousedown and mouseup
361
+ const mouseStart = Point2d.create(event.clientX, event.clientY);
362
+ this.setState({ mouseStart });
363
+ this._lastClientXY = Point2d.create(event.clientX, event.clientY);
364
+ };
365
+ _handleDrawingMouseDown = (event) => {
366
+ if (this.state.mode === MapMode.Opened) {
367
+ event.preventDefault();
368
+ this.setState({ isPanning: true });
369
+ }
370
+ };
371
+ _handleWindowMouseDown = (event) => {
372
+ event.preventDefault();
373
+ this.setState({ isMoving: true });
374
+ };
375
+ _handleMouseDrag = (event) => {
376
+ const mouse = Point2d.create(event.clientX, event.clientY);
377
+ const movement = mouse.minus(this._lastClientXY);
378
+ if (this.state.isMoving) {
379
+ // add scaled mouse movement
380
+ this._processWindowDrag(movement);
381
+ }
382
+ else {
383
+ if (this.state.isPanning && this.state.mode === MapMode.Opened) {
384
+ const vect = Vector3d.create(movement.x / this.state.drawingZoom, -movement.y / this.state.drawingZoom, 0);
385
+ const offset = this.state.rotateMinimapWithView || this._isViewport3D()
386
+ ? this.state.rotation.multiplyTransposeVector(vect)
387
+ : vect;
388
+ const mapOrigin = this.state.mapOrigin.minus(offset);
389
+ this.setState({ startMapOrigin: mapOrigin, mapOrigin });
390
+ }
391
+ }
392
+ this._lastClientXY = mouse;
393
+ };
394
+ _handleMouseDragEnd = (event) => {
395
+ const mouse = Point2d.create(event.clientX, event.clientY);
396
+ if (mouse.isAlmostEqual(this.state.mouseStart) &&
397
+ this.state.mode === MapMode.Closed &&
398
+ (event.target === this._viewContainerElement.current ||
399
+ event.target === this._viewElement.current)) {
400
+ this._openLargeMap();
401
+ }
402
+ else if (this.state.isMoving) {
403
+ this._processWindowEndDrag();
404
+ }
405
+ else if (this.state.isPanning) {
406
+ if (this.state.mode === MapMode.Opened) {
407
+ event.stopPropagation();
408
+ this.setState({ isPanning: false });
409
+ }
410
+ }
411
+ else if ((!(event.target instanceof Node) ||
412
+ (this._rootElement.current &&
413
+ !this._rootElement.current.contains(event.target))) &&
414
+ mouse.isAlmostEqual(this.state.mouseStart)) {
415
+ this._closeLargeMap();
416
+ }
417
+ this._lastClientXY = Point2d.create(event.clientX, event.clientY);
418
+ };
419
+ _handleWindowTouchStart = (event) => {
420
+ if (1 !== event.targetTouches.length)
421
+ return;
422
+ window.addEventListener("touchmove", this._onTouchMove, false);
423
+ window.addEventListener("touchend", this._onTouchEnd, false);
424
+ const mouseStart = Point2d.create(event.targetTouches[0].clientX, event.targetTouches[0].clientY);
425
+ this.setState({ mouseStart });
426
+ this._lastClientXY = mouseStart.clone();
427
+ this.setState({ isMoving: true });
428
+ };
429
+ _onTouchMove = (event) => {
430
+ if (1 !== event.targetTouches.length)
431
+ return;
432
+ const mouse = Point2d.create(event.targetTouches[0].clientX, event.targetTouches[0].clientY);
433
+ const movement = mouse.minus(this._lastClientXY);
434
+ // add scaled mouse movement
435
+ this._processWindowDrag(movement);
436
+ this._lastClientXY = mouse;
437
+ };
438
+ _onTouchEnd = (event) => {
439
+ if (0 !== event.targetTouches.length)
440
+ return;
441
+ this._processWindowEndDrag();
442
+ if (0 !== event.changedTouches.length)
443
+ this._lastClientXY = Point2d.create(event.changedTouches[0].clientX, event.changedTouches[0].clientY); // Doesn't seem necessary...but _handleMouseDragEnd sets it...
444
+ window.removeEventListener("touchmove", this._onTouchMove);
445
+ window.removeEventListener("touchend", this._onTouchEnd);
446
+ };
447
+ /** @internal */
448
+ static getDefaultClosedMapSize = () => {
449
+ return Vector3d.create(96, 96);
450
+ };
451
+ /** @internal */
452
+ static getDefaultOpenedMapSize = (paddingX = 0, paddingY = 0) => {
453
+ return Vector3d.create(window.innerWidth / 3 - 2 * (window.innerWidth - paddingX), window.innerHeight / 3 - 2 * paddingY);
454
+ };
455
+ _getClosedMapSize = () => {
456
+ if (this.props.closeSize === undefined)
457
+ return DrawingNavigationAid.getDefaultClosedMapSize();
458
+ return this.props.closeSize;
459
+ };
460
+ _getOpenedMapSize = () => {
461
+ if (this.props.openSize === undefined)
462
+ return DrawingNavigationAid.getDefaultOpenedMapSize(this._rootOffset.right, this._rootOffset.top);
463
+ return this.props.openSize;
464
+ };
465
+ _openLargeMap = () => {
466
+ if (this.state.mode === MapMode.Closed && this.state.animation === 1.0) {
467
+ if (this._rootElement.current) {
468
+ const rect = this._rootElement.current.getBoundingClientRect();
469
+ this._rootOffset = rect;
470
+ }
471
+ const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
472
+ const mapExtents = this._getOpenedMapSize();
473
+ this.setState({
474
+ mode: MapMode.Opened,
475
+ isMoving: false,
476
+ isPanning: false,
477
+ mapExtents,
478
+ startMapExtents,
479
+ animation: 0,
480
+ }, () => {
481
+ this._animationFrame = setTimeout(this._animation);
482
+ });
483
+ }
484
+ };
485
+ _closeLargeMap = () => {
486
+ if (this.state.mode === MapMode.Opened && this.state.animation === 1.0) {
487
+ const startMapOrigin = this.state.mapOrigin;
488
+ const mapOrigin = this.state.origin.clone();
489
+ const startMapExtents = Vector3d.createFrom(this.state.mapExtents);
490
+ const mapExtents = this._getClosedMapSize();
491
+ const rect = this.state.rotateMinimapWithView || this._isViewport3D()
492
+ ? this.state.extents
493
+ : DrawingNavigationAid.findRotatedWindowDimensions(this.state.extents, this.state.rotation);
494
+ const maxRectDim = Math.max(rect.y, rect.x);
495
+ const maxExtentDim = Math.max(mapExtents.x, mapExtents.y);
496
+ const drawingZoom = maxExtentDim / (3 * maxRectDim);
497
+ const startDrawingZoom = this.state.drawingZoom;
498
+ this.setState({
499
+ mode: MapMode.Closed,
500
+ startMapOrigin,
501
+ mapOrigin,
502
+ startDrawingZoom,
503
+ drawingZoom,
504
+ isMoving: false,
505
+ isPanning: false,
506
+ startMapExtents,
507
+ mapExtents,
508
+ panningDirection: Vector3d.createZero(),
509
+ animation: 0,
510
+ }, () => {
511
+ this._animationFrame = setTimeout(this._animation, 16.667);
512
+ });
513
+ }
514
+ };
515
+ _getPanVector = () => {
516
+ const is3D = this._isViewport3D();
517
+ const rect = this.state.rotateMinimapWithView || is3D
518
+ ? this.state.extents
519
+ : DrawingNavigationAid.findRotatedWindowDimensions(this.state.extents, this.state.rotation);
520
+ const mapExtents = this.state.mapExtents.scale(1 / this.state.drawingZoom);
521
+ const maxMagnitude = 80; // maximum acceleration
522
+ const magnitudeTravel = 30; // How far, in pixels, that magnitude increases from 0 to max acceleration
523
+ const diff = Vector3d.createFrom(this.state.origin.minus(this.state.mapOrigin));
524
+ const diffVector = this.state.rotateMinimapWithView || is3D
525
+ ? this.state.rotation.multiplyVector(diff)
526
+ : diff;
527
+ // capture any values
528
+ const magnitudeVector = Vector3d.create(Math.max(0, Math.abs(diffVector.x) - (mapExtents.x - rect.x) / 2), Math.max(0, Math.abs(diffVector.y) - (mapExtents.y - rect.y) / 2));
529
+ if (magnitudeVector.isAlmostZero)
530
+ return Vector3d.createZero();
531
+ const magnitude = (Math.min(magnitudeVector.magnitude() * this.state.drawingZoom, magnitudeTravel) /
532
+ magnitudeTravel) *
533
+ maxMagnitude;
534
+ const vect = Vector3d.createFrom(this.state.origin.minus(this.state.mapOrigin)); // vect will never be zero or magnitude would also be zero
535
+ const norm = vect.normalize();
536
+ return norm.scale(magnitude); // norm is only undefined when vect is zero, in which it would have returned at magnitudeVector.isAlmostZero
537
+ };
538
+ _handleWheel = (event) => {
539
+ if (this.state.mode === MapMode.Opened && this.state.animation === 1) {
540
+ const { mapOrigin, drawingZoom } = this.state;
541
+ const mapSize = this._getOpenedMapSize();
542
+ const mouseX = event.clientX - this._rootOffset.right + mapSize.x / 2;
543
+ const mouseY = event.clientY - this._rootOffset.top - mapSize.y / 2;
544
+ const is3D = this._isViewport3D();
545
+ if (event.deltaY < 0) {
546
+ const zoom = drawingZoom * 1.1;
547
+ const vect = Vector3d.create((mouseX * 0.1) / zoom, (-mouseY * 0.1) / zoom, 0);
548
+ const offset = this.state.rotateMinimapWithView || is3D
549
+ ? this.state.rotation.multiplyTransposeVector(vect)
550
+ : vect;
551
+ const m = mapOrigin.plus(offset);
552
+ this.setState({ mapOrigin: m, drawingZoom: zoom });
553
+ }
554
+ if (event.deltaY > 0) {
555
+ const zoom = drawingZoom / 1.1;
556
+ const vect = Vector3d.create((mouseX * 0.1) / drawingZoom, (-mouseY * 0.1) / drawingZoom, 0);
557
+ const offset = this.state.rotateMinimapWithView || is3D
558
+ ? this.state.rotation.multiplyTransposeVector(vect)
559
+ : vect;
560
+ const m = mapOrigin.minus(offset);
561
+ this.setState({ mapOrigin: m, drawingZoom: zoom });
562
+ }
563
+ }
564
+ };
565
+ _handleZoomIn = () => {
566
+ const zoom = this.state.drawingZoom * 1.4;
567
+ this.setState({ drawingZoom: zoom });
568
+ };
569
+ _handleZoomOut = () => {
570
+ const zoom = this.state.drawingZoom / 1.4;
571
+ this.setState({ drawingZoom: zoom });
572
+ };
573
+ _handleUnrotate = () => {
574
+ const startRotation = this.state.rotation;
575
+ const halfExtents = this.state.extents.scale(0.5);
576
+ const offset = this.state.rotateMinimapWithView || this._isViewport3D()
577
+ ? Vector3d.createZero()
578
+ : this.state.rotation
579
+ .multiplyTransposeVector(halfExtents)
580
+ .minus(halfExtents);
581
+ const startOrigin = this.state.origin;
582
+ const origin = this.state.origin.plus(offset);
583
+ const startMapOrigin = this.state.mapOrigin;
584
+ const mapOrigin = this.state.mapOrigin.plus(offset);
585
+ this.setState({
586
+ animation: 0,
587
+ startOrigin,
588
+ origin,
589
+ startMapOrigin,
590
+ mapOrigin,
591
+ startRotation,
592
+ rotation: Matrix3d.createIdentity(),
593
+ }, () => {
594
+ this._animationFrame = setTimeout(this._animation, 16.667);
595
+ });
596
+ };
597
+ /** @internal */
598
+ static findRotatedWindowDimensions = (extents, rotation) => {
599
+ const cos = rotation.at(0, 0);
600
+ const sin = rotation.at(1, 0);
601
+ // extents.x/y should be divided in half, but we don't have to do that immediately.
602
+ const cosWidth = cos * extents.x;
603
+ const sinHeight = sin * extents.y;
604
+ const sinWidth = cos * extents.x;
605
+ const cosHeight = sin * extents.y;
606
+ const a = Math.atan2(sin, cos);
607
+ if (a % Math.PI >= 0 && a % Math.PI < Math.PI / 2) {
608
+ const y1 = -cosHeight - sinWidth;
609
+ const x2 = cosWidth + sinHeight;
610
+ const y3 = cosHeight + sinWidth;
611
+ const x4 = -cosWidth - sinHeight;
612
+ // Instead, divide total difference
613
+ return Vector3d.create(Math.abs(x2 - x4) / 2, Math.abs(y1 - y3) / 2);
614
+ }
615
+ else {
616
+ const x1 = -cosWidth + sinHeight;
617
+ const y2 = -cosHeight + sinWidth;
618
+ const x3 = cosWidth - sinHeight;
619
+ const y4 = cosHeight - sinWidth;
620
+ return Vector3d.create(Math.abs(x1 - x3) / 2, Math.abs(y2 - y4) / 2);
621
+ }
622
+ };
583
623
  }
584
- DrawingNavigationAid._animationFn = (t) => t < 0.5 ? 2 * t ** 2 : -1 + (4 - 2 * t) * t;
585
- /** @internal */
586
- DrawingNavigationAid.getDefaultClosedMapSize = () => {
587
- return Vector3d.create(96, 96);
588
- };
589
- /** @internal */
590
- DrawingNavigationAid.getDefaultOpenedMapSize = (paddingX = 0, paddingY = 0) => {
591
- return Vector3d.create(window.innerWidth / 3 - 2 * (window.innerWidth - paddingX), window.innerHeight / 3 - 2 * paddingY);
592
- };
593
- /** @internal */
594
- DrawingNavigationAid.findRotatedWindowDimensions = (extents, rotation) => {
595
- const cos = rotation.at(0, 0);
596
- const sin = rotation.at(1, 0);
597
- // extents.x/y should be divided in half, but we don't have to do that immediately.
598
- const cosWidth = cos * extents.x;
599
- const sinHeight = sin * extents.y;
600
- const sinWidth = cos * extents.x;
601
- const cosHeight = sin * extents.y;
602
- const a = Math.atan2(sin, cos);
603
- if (a % Math.PI >= 0 && a % Math.PI < Math.PI / 2) {
604
- const y1 = -cosHeight - sinWidth;
605
- const x2 = cosWidth + sinHeight;
606
- const y3 = cosHeight + sinWidth;
607
- const x4 = -cosWidth - sinHeight;
608
- // Instead, divide total difference
609
- return Vector3d.create(Math.abs(x2 - x4) / 2, Math.abs(y1 - y3) / 2);
610
- }
611
- else {
612
- const x1 = -cosWidth + sinHeight;
613
- const y2 = -cosHeight + sinWidth;
614
- const x3 = cosWidth - sinHeight;
615
- const y4 = cosHeight - sinWidth;
616
- return Vector3d.create(Math.abs(x1 - x3) / 2, Math.abs(y2 - y4) / 2);
617
- }
618
- };
619
624
  /** @internal */
620
625
  export class DrawingNavigationCanvas extends React.Component {
621
- constructor() {
622
- super(...arguments);
623
- this._canvasElement = React.createRef();
624
- this._update = () => {
625
- if (this._vp) {
626
- const max = Math.max(this.props.extents.x, this.props.extents.y);
627
- this._vp.view.extentLimits = { max, min: Constant.oneMillimeter };
628
- this._vp.view.setOrigin(this.props.origin);
629
- this._vp.view.setRotation(this.props.rotation);
630
- this._vp.view.setExtents(this.props.extents);
631
- this._vp.applyViewState(this._vp.view);
632
- }
633
- };
634
- }
626
+ _canvasElement = React.createRef();
627
+ _vp;
635
628
  render() {
636
629
  return (React.createElement("div", { className: "drawing-canvas", "data-testid": "drawing-canvas", ref: this._canvasElement }));
637
630
  }
@@ -657,6 +650,16 @@ export class DrawingNavigationCanvas extends React.Component {
657
650
  if (vp.viewFlags.acsTriad)
658
651
  vp.viewFlags = vp.viewFlags.with("acsTriad", false);
659
652
  }
653
+ _update = () => {
654
+ if (this._vp) {
655
+ const max = Math.max(this.props.extents.x, this.props.extents.y);
656
+ this._vp.view.extentLimits = { max, min: Constant.oneMillimeter };
657
+ this._vp.view.setOrigin(this.props.origin);
658
+ this._vp.view.setRotation(this.props.rotation);
659
+ this._vp.view.setExtents(this.props.extents);
660
+ this._vp.applyViewState(this._vp.view);
661
+ }
662
+ };
660
663
  componentDidUpdate(oldProps) {
661
664
  const viewManager = this.props.viewManagerOverride
662
665
  ? this.props.viewManagerOverride