@inweb/viewer-visualize 26.10.6 → 26.12.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 (41) hide show
  1. package/README.md +6 -4
  2. package/dist/viewer-visualize.js +659 -496
  3. package/dist/viewer-visualize.js.map +1 -1
  4. package/dist/viewer-visualize.min.js +1 -1
  5. package/dist/viewer-visualize.module.js +585 -484
  6. package/dist/viewer-visualize.module.js.map +1 -1
  7. package/lib/Viewer/Commands/GetSelected2.d.ts +2 -0
  8. package/lib/Viewer/Commands/SetSelected.d.ts +1 -1
  9. package/lib/Viewer/Commands/SetSelected2.d.ts +2 -0
  10. package/lib/Viewer/Components/index.d.ts +8 -7
  11. package/lib/Viewer/Draggers/MeasureLineDragger/MeasureLineItem.d.ts +5 -1
  12. package/lib/Viewer/Draggers/MeasureLineDragger/index.d.ts +3 -2
  13. package/lib/Viewer/Loaders/VSFXCloudLoader.d.ts +1 -1
  14. package/lib/Viewer/Loaders/VSFXCloudPartialLoader.d.ts +1 -1
  15. package/lib/Viewer/Loaders/index.d.ts +14 -9
  16. package/lib/Viewer/Models/IModelImpl.d.ts +5 -0
  17. package/lib/Viewer/Models/ModelImpl.d.ts +5 -0
  18. package/lib/Viewer/Viewer.d.ts +130 -136
  19. package/package.json +5 -5
  20. package/src/Viewer/Commands/ClearSelected.ts +3 -1
  21. package/src/Viewer/Commands/GetSelected2.ts +33 -0
  22. package/src/Viewer/Commands/HideSelected.ts +3 -1
  23. package/src/Viewer/Commands/SelectModel.ts +2 -3
  24. package/src/Viewer/Commands/SetSelected.ts +5 -2
  25. package/src/Viewer/Commands/SetSelected2.ts +39 -0
  26. package/src/Viewer/Commands/index.ts +4 -0
  27. package/src/Viewer/Components/index.ts +8 -7
  28. package/src/Viewer/Draggers/Common/OdBaseDragger.ts +3 -2
  29. package/src/Viewer/Draggers/MeasureLineDragger/MeasureLineItem.ts +44 -13
  30. package/src/Viewer/Draggers/MeasureLineDragger/index.ts +53 -18
  31. package/src/Viewer/Draggers/OdJoyStickDragger.ts +2 -2
  32. package/src/Viewer/Loaders/VSFCloudLoader.ts +6 -0
  33. package/src/Viewer/Loaders/VSFFileLoader.ts +7 -1
  34. package/src/Viewer/Loaders/VSFXCloudLoader.ts +7 -1
  35. package/src/Viewer/Loaders/VSFXCloudPartialLoader.ts +8 -2
  36. package/src/Viewer/Loaders/VSFXCloudStreamingLoader.ts +7 -1
  37. package/src/Viewer/Loaders/VSFXFileLoader.ts +7 -1
  38. package/src/Viewer/Loaders/index.ts +14 -9
  39. package/src/Viewer/Models/IModelImpl.ts +29 -0
  40. package/src/Viewer/Models/ModelImpl.ts +32 -0
  41. package/src/Viewer/Viewer.ts +784 -775
@@ -30,11 +30,14 @@ import {
30
30
  FileSource,
31
31
  IClippingPlane,
32
32
  IComponent,
33
- IEntity,
34
33
  IDragger,
34
+ IEntity,
35
+ IInfo,
35
36
  ILoader,
37
+ Info,
36
38
  IOrthogonalCamera,
37
39
  IOptions,
40
+ IPerspectiveCamera,
38
41
  IPoint,
39
42
  IViewer,
40
43
  IViewpoint,
@@ -48,6 +51,7 @@ import { draggers } from "./Draggers";
48
51
  import { commands } from "./Commands";
49
52
  import { components } from "./Components";
50
53
  import { loaders } from "./Loaders";
54
+ import { IModelImpl } from "./Models/IModelImpl";
51
55
 
52
56
  import { loadVisualizeJs } from "./utils";
53
57
  import { MarkupFactory, MarkupType } from "./Markup/MarkupFactory";
@@ -57,36 +61,39 @@ const OVERLAY_VIEW_NAME = "$OVERLAY_VIEW_NAME";
57
61
  const isExist = (value) => value !== undefined && value !== null;
58
62
 
59
63
  /**
60
- * 3D viewer powered by {@link https://cloud.opendesign.com/docs/index.html#/visualizejs | VisualizeJS}
61
- * library.
64
+ * 3D viewer powered by {@link https://cloud.opendesign.com/docs/index.html#/visualizejs | VisualizeJS}.
62
65
  */
63
66
  export class Viewer
64
67
  extends EventEmitter2<ViewerEventMap & CanvasEventMap & OptionsEventMap>
65
68
  implements IViewer, IWorldTransform
66
69
  {
70
+ public client: Client | undefined;
71
+ public options: IOptions;
72
+ public canvas: HTMLCanvasElement | undefined;
73
+ public canvasEvents: string[];
74
+ public loaders: ILoader[];
75
+ public models: IModelImpl[];
76
+ public info: IInfo;
77
+
78
+ private canvaseventlistener: (event: Event) => void;
79
+
80
+ private _visualizeJsUrl = "";
81
+ private _visualizeJs: any;
82
+ private _visualizeTimestamp: number;
83
+ private _viewer: any;
84
+ private _crossOrigin;
85
+
67
86
  private _activeDragger: IDragger | null;
68
- private _components: Array<IComponent>;
69
- private _enableAutoUpdate: boolean;
87
+ private _components: IComponent[];
88
+
70
89
  private _renderNeeded: boolean;
71
90
  private _renderTime: DOMHighResTimeStamp;
91
+ private _enableAutoUpdate: boolean;
72
92
  private _isRunAsyncUpdate: boolean;
73
93
 
74
- protected _options: Options;
75
- protected _visualizeJsUrl = "";
76
- protected _visualizeJs: any;
77
- protected _visualizeTimestamp: number;
78
- protected _viewer: any;
79
- protected _crossOrigin;
80
-
81
- private canvaseventlistener: (event: Event) => void;
94
+ public _abortControllerForReferences: AbortController | undefined;
82
95
 
83
- public canvasEvents: string[];
84
96
  private _markup: IMarkup;
85
- public canvas: HTMLCanvasElement | undefined;
86
-
87
- public _abortControllerForReferences: AbortController | undefined;
88
- public client: Client | undefined;
89
- public loaders: Array<ILoader>;
90
97
 
91
98
  /**
92
99
  * @param client - The `Client` instance that is used to load model reference files from the Open Cloud
@@ -113,21 +120,21 @@ export class Viewer
113
120
  super();
114
121
  this.configure(params);
115
122
 
116
- this._options = new Options(this);
117
-
118
123
  this.client = client;
124
+ this.options = new Options(this);
119
125
  this.loaders = [];
126
+ this.models = [];
127
+ this.info = new Info();
128
+
129
+ this.canvasEvents = CANVAS_EVENTS.slice();
130
+ this.canvaseventlistener = (event: Event) => this.emit(event);
120
131
 
121
132
  this._activeDragger = null;
122
133
  this._components = [];
123
134
 
135
+ this._renderNeeded = false;
124
136
  this._renderTime = 0;
125
-
126
- this.canvasEvents = CANVAS_EVENTS.slice();
127
- this.canvaseventlistener = (event: Event) => this.emit(event);
128
-
129
137
  this._enableAutoUpdate = params.enableAutoUpdate ?? true;
130
- this._renderNeeded = false;
131
138
  this._isRunAsyncUpdate = false;
132
139
 
133
140
  this.render = this.render.bind(this);
@@ -136,13 +143,6 @@ export class Viewer
136
143
  this._markup = MarkupFactory.createMarkup(params.markupType);
137
144
  }
138
145
 
139
- /**
140
- * Viewer options.
141
- */
142
- get options(): IOptions {
143
- return this._options;
144
- }
145
-
146
146
  /**
147
147
  * `VisualizeJS` library URL. Use {@link configure | configure()} to change library URL.
148
148
  *
@@ -152,6 +152,30 @@ export class Viewer
152
152
  return this._visualizeJsUrl;
153
153
  }
154
154
 
155
+ /**
156
+ * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/visualizejs_api | module}
157
+ * instance.
158
+ */
159
+ get visualizeJs(): any {
160
+ return this._visualizeJs;
161
+ }
162
+
163
+ /**
164
+ * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/visualizejs_api | module}
165
+ * instance.
166
+ */
167
+ visLib(): any {
168
+ return this._visualizeJs;
169
+ }
170
+
171
+ /**
172
+ * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/vis/Viewer | Viewer}
173
+ * instance.
174
+ */
175
+ visViewer(): any {
176
+ return this._viewer;
177
+ }
178
+
155
179
  /**
156
180
  * 2D markup core instance used to create markups.
157
181
  *
@@ -179,6 +203,16 @@ export class Viewer
179
203
  return this;
180
204
  }
181
205
 
206
+ // IViewer
207
+
208
+ get draggers(): string[] {
209
+ return [...draggers.getDraggers().keys()];
210
+ }
211
+
212
+ get components(): string[] {
213
+ return [...components.getComponents().keys()];
214
+ }
215
+
182
216
  /**
183
217
  * Loads the `VisualizeJS` module and initializes it with the specified canvas. Call
184
218
  * {@link dispose | dispose()} to release allocated resources.
@@ -197,12 +231,13 @@ export class Viewer
197
231
  async initialize(canvas: HTMLCanvasElement, onProgress?: (event: ProgressEvent) => void): Promise<this> {
198
232
  this.addEventListener("optionschange", (event) => this.syncOptions(event.data));
199
233
 
234
+ const pixelRatio = window.devicePixelRatio;
200
235
  const rect = canvas.parentElement.getBoundingClientRect();
201
236
  const width = rect.width || 1;
202
237
  const height = rect.height || 1;
203
238
 
204
- canvas.width = Math.round(width * window.devicePixelRatio);
205
- canvas.height = Math.round(height * window.devicePixelRatio);
239
+ canvas.width = Math.round(width * pixelRatio);
240
+ canvas.height = Math.round(height * pixelRatio);
206
241
 
207
242
  canvas.style.width = width + "px";
208
243
  canvas.style.height = height + "px";
@@ -306,28 +341,7 @@ export class Viewer
306
341
  this.emitEvent({ type: "resize", width, height });
307
342
  }
308
343
 
309
- // internal render/resize routines
310
-
311
- public render(time?: DOMHighResTimeStamp) {
312
- if (!this.visualizeJs) return;
313
- if (this._isRunAsyncUpdate) return;
314
-
315
- const renderNeeded = this.visViewer().isRunningAnimation() || this._renderNeeded;
316
- if (!renderNeeded) return;
317
-
318
- if (!time) time = performance.now();
319
- const deltaTime = (time - this._renderTime) / 1000;
320
-
321
- this._renderTime = time;
322
- this._renderNeeded = !this.visViewer().getActiveDevice().isValid();
323
-
324
- this.visViewer().update();
325
- this._activeDragger?.updatePreview?.();
326
-
327
- this.emitEvent({ type: "render", time, deltaTime });
328
- }
329
-
330
- public resize(): this {
344
+ resize(): this {
331
345
  console.warn(
332
346
  "Viewer.resize() has been deprecated since 26.9 and will be removed in a future release, use Viewer.setSize() instead."
333
347
  );
@@ -365,515 +379,76 @@ export class Viewer
365
379
  this.emitEvent({ type: "update", data: force });
366
380
  }
367
381
 
368
- private scheduleUpdateAsync(maxScheduleUpdateTimeInMs = 50): Promise<void> {
369
- return new Promise<void>((resolve, reject) => {
370
- setTimeout(() => {
371
- try {
372
- if (this._enableAutoUpdate) {
373
- this.visViewer()?.update(maxScheduleUpdateTimeInMs);
374
- this._activeDragger?.updatePreview?.();
375
- }
376
- this.emitEvent({ type: "update", data: false });
377
- resolve();
378
- } catch (e) {
379
- console.error(e);
380
- reject();
381
- }
382
- }, 0);
383
- });
384
- }
382
+ // Internal render routines
385
383
 
386
- /**
387
- * Updates the viewer asynchronously without locking the user interface. Used to update the viewer
388
- * after changes that require a long rendering time.
389
- *
390
- * Do nothing if the auto-update mode is disabled in the constructor. In this case, register an
391
- * `update` event handler and update the `VisualizeJS` viewer and active dragger manually.
392
- *
393
- * Fires:
394
- *
395
- * - {@link UpdateEvent | update}
396
- *
397
- * @param maxScheduleUpdateTimeInMs - Maximum time for one update, default 30 ms.
398
- * @param maxScheduleUpdateCount - Maximum count of scheduled updates.
399
- */
400
- async updateAsync(maxScheduleUpdateTimeInMs = 50, maxScheduleUpdateCount = 50): Promise<void> {
384
+ render(time?: DOMHighResTimeStamp) {
401
385
  if (!this.visualizeJs) return;
386
+ if (this._isRunAsyncUpdate) return;
402
387
 
403
- this._isRunAsyncUpdate = true;
404
- try {
405
- const device = this.visViewer().getActiveDevice();
406
- for (let iterationCount = 0; !device.isValid() && iterationCount < maxScheduleUpdateCount; iterationCount++) {
407
- await this.scheduleUpdateAsync(maxScheduleUpdateTimeInMs);
408
- }
409
- await this.scheduleUpdateAsync(maxScheduleUpdateTimeInMs);
410
- } catch (e) {
411
- console.error(e);
412
- } finally {
413
- this._isRunAsyncUpdate = false;
414
- }
415
- }
388
+ const renderNeeded = this.visViewer().isRunningAnimation() || this._renderNeeded;
389
+ if (!renderNeeded) return;
416
390
 
417
- /**
418
- * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/visualizejs_api | module}
419
- * instance.
420
- */
421
- get visualizeJs(): any {
422
- return this._visualizeJs;
423
- }
391
+ if (!time) time = performance.now();
392
+ const deltaTime = (time - this._renderTime) / 1000;
424
393
 
425
- /**
426
- * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/visualizejs_api | module}
427
- * instance.
428
- */
429
- visLib(): any {
430
- return this._visualizeJs;
431
- }
394
+ this._renderTime = time;
395
+ this._renderNeeded = !this.visViewer().getActiveDevice().isValid();
432
396
 
433
- /**
434
- * Returns `VisualizeJS` {@link https://cloud.opendesign.com/docs/index.html#/vis/Viewer | Viewer}
435
- * instance.
436
- */
437
- visViewer(): any {
438
- return this._viewer;
397
+ this.visViewer().update();
398
+ this._activeDragger?.updatePreview?.();
399
+
400
+ this.emitEvent({ type: "render", time, deltaTime });
439
401
  }
440
402
 
441
- // update the VisualizeJS options
403
+ // Internal loading routines
442
404
 
443
- syncOpenCloudVisualStyle(): this {
405
+ async loadReferences(model: Model | File | Assembly): Promise<this> {
444
406
  if (!this.visualizeJs) return this;
407
+ if (!this.client) return this;
408
+ if (!model.getReferences) return this;
445
409
 
446
- const visLib = this.visLib();
447
- const visViewer = this.visViewer();
448
-
449
- const device = visViewer.getActiveDevice();
450
- if (device.isNull()) return this;
451
-
452
- const view = device.getActiveView();
453
-
454
- view.enableDefaultLighting(true, visLib.DefaultLightingType.kTwoLights);
455
- view.setDefaultLightingIntensity(1.25);
456
-
457
- // Visualize.js 25.11 and earlier threw an exception if the style did not exist.
458
- let visualStyleId;
459
- try {
460
- visualStyleId = visViewer.findVisualStyle("OpenCloud");
461
- } catch {
462
- visualStyleId = undefined;
463
- }
410
+ const abortController = new AbortController();
464
411
 
465
- if (!visualStyleId || visualStyleId.isNull()) {
466
- visualStyleId = visViewer.createVisualStyle("OpenCloud");
412
+ this._abortControllerForReferences?.abort();
413
+ this._abortControllerForReferences = abortController;
467
414
 
468
- const colorDef = new visLib.OdTvColorDef(66, 66, 66);
469
- const shadedVsId = visViewer.findVisualStyle("Realistic");
415
+ let references: any[] = [];
416
+ await model
417
+ .getReferences(abortController.signal)
418
+ .then((data) => (references = data.references))
419
+ .catch((e) => console.error("Cannot load model references.", e));
470
420
 
471
- const visualStylePtr = visualStyleId.openObject();
472
- visualStylePtr.copyFrom(shadedVsId);
473
- visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kFaceModifiers, 0, visLib.VisualStyleOperations.kSet);
474
- visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeModel, 2, visLib.VisualStyleOperations.kSet);
475
- visualStylePtr.setOptionDouble(visLib.VisualStyleOptions.kEdgeCreaseAngle, 60, visLib.VisualStyleOperations.kSet);
476
- visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeStyles, 0, visLib.VisualStyleOperations.kSet);
477
- visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeModifiers, 8, visLib.VisualStyleOperations.kSet);
478
- visualStylePtr.setOptionColor(
479
- visLib.VisualStyleOptions.kEdgeColorValue,
480
- colorDef,
481
- visLib.VisualStyleOperations.kSet
482
- );
483
- visualStylePtr.delete();
421
+ for (const file of references) {
422
+ await this.client
423
+ .downloadFile(file.id, undefined, abortController.signal)
424
+ .then((arrayBuffer) => this.visualizeJs?.getViewer().addEmbeddedFile(file.name, new Uint8Array(arrayBuffer)))
425
+ .catch((e) => console.error(`Cannot load reference file ${file.name}.`, e));
484
426
  }
485
427
 
486
- view.visualStyle = visualStyleId;
487
-
488
- view.delete();
489
- device.delete();
490
-
491
428
  return this;
492
429
  }
493
430
 
494
- syncOptions(options: IOptions = this.options): this {
495
- if (!this.visualizeJs) return this;
431
+ applyModelTransformMatrix(model: Model | Assembly) {
432
+ this.executeCommand("applyModelTransform", model);
433
+ }
496
434
 
497
- this.syncOpenCloudVisualStyle();
435
+ applySceneGraphSettings(options = this.options) {
436
+ if (!this.visualizeJs) return;
498
437
 
499
438
  const visLib = this.visLib();
500
439
  const visViewer = this.visViewer();
501
440
 
502
441
  const device = visViewer.getActiveDevice();
503
- if (device.isNull()) return this;
504
-
505
- if (options.showWCS !== visViewer.getEnableWCS()) {
506
- visViewer.setEnableWCS(options.showWCS);
507
- }
508
- if (options.cameraAnimation !== visViewer.getEnableAnimation()) {
509
- visViewer.setEnableAnimation(options.cameraAnimation);
510
- }
511
-
512
- const antialiasing = options.antialiasing === true || options.antialiasing === "fxaa";
513
- if (antialiasing !== visViewer.fxaaAntiAliasing3d) {
514
- visViewer.fxaaAntiAliasing3d = antialiasing;
515
- visViewer.fxaaQuality = 5;
516
- }
517
-
518
- if (options.shadows !== visViewer.shadows) {
519
- visViewer.shadows = options.shadows;
520
-
521
- const canvas = visLib.canvas;
522
- device.invalidate([0, canvas.width, canvas.height, 0]);
442
+ if (isExist(options.sceneGraph)) {
443
+ device.setOptionBool(visLib.DeviceOptions.kDelaySceneGraphProc, !options.sceneGraph);
523
444
  }
445
+ // if (options.enablePartialMode && visLib.HpTrc.Usd >= visViewer.memoryLimit) {
446
+ // device.setOptionBool(visLib.DeviceOptions.kDelaySceneGraphProc, true);
447
+ // }
448
+ device.delete();
524
449
 
525
- if (options.groundShadow !== visViewer.groundShadow) {
526
- visViewer.groundShadow = options.groundShadow;
527
- }
528
-
529
- if (options.ambientOcclusion !== device.getOptionBool(visLib.DeviceOptions.kSSAOEnable)) {
530
- device.setOptionBool(visLib.DeviceOptions.kSSAOEnable, options.ambientOcclusion);
531
- device.setOptionBool(visLib.DeviceOptions.kSSAODynamicRadius, true);
532
- device.setOptionDouble(visLib.DeviceOptions.kSSAORadius, 1);
533
- device.setOptionInt32(visLib.DeviceOptions.kSSAOLoops, 32);
534
- device.setOptionDouble(visLib.DeviceOptions.kSSAOPower, 2);
535
- device.setOptionInt32(visLib.DeviceOptions.kSSAOBlurRadius, 2);
536
-
537
- const activeView = visViewer.activeView;
538
- activeView.setSSAOEnabled(options.ambientOcclusion);
539
- activeView.delete();
540
- }
541
-
542
- if (isExist(options.edgeModel)) {
543
- const activeView = device.getActiveView();
544
-
545
- const visualStyleId = visViewer.findVisualStyle("OpenCloud");
546
- const visualStylePtr = visualStyleId.openObject();
547
-
548
- visualStylePtr.setOptionInt32(
549
- visLib.VisualStyleOptions.kEdgeModel,
550
- options.edgeModel ? 2 : 0,
551
- visLib.VisualStyleOperations.kSet
552
- );
553
-
554
- activeView.visualStyle = visualStyleId;
555
-
556
- visualStylePtr.delete();
557
- visualStyleId.delete();
558
- activeView.delete();
559
- }
560
-
561
- device.delete();
562
-
563
- this.syncHighlightingOptions(options);
564
- this.update();
565
-
566
- return this;
567
- }
568
-
569
- syncHighlightingOptions(options: IOptions = this.options): this {
570
- if (!this.visualizeJs) return this;
571
-
572
- const params = options.enableCustomHighlight ? options : Options.defaults();
573
-
574
- const visLib = this.visLib();
575
- const visViewer = this.visViewer();
576
- const { Entry, OdTvRGBColorDef } = visLib;
577
-
578
- const highlightStyleId = visViewer.findHighlightStyle("Web_Default");
579
- const highlightStylePtr = highlightStyleId.openObject();
580
-
581
- if (isExist(params.facesColor)) {
582
- const color = new OdTvRGBColorDef(params.facesColor.r, params.facesColor.g, params.facesColor.b);
583
- highlightStylePtr.setFacesColor(Entry.k3D.value | Entry.k3DTop.value, color);
584
- color.delete();
585
- }
586
-
587
- if (isExist(params.facesOverlap)) {
588
- highlightStylePtr.setFacesVisibility(Entry.k3DTop.value, params.facesOverlap);
589
- }
590
- if (isExist(params.facesTransparancy)) {
591
- highlightStylePtr.setFacesTransparency(Entry.k3D.value | Entry.k3DTop.value, params.facesTransparancy);
592
- }
593
-
594
- if (isExist(params.edgesColor)) {
595
- const color = new OdTvRGBColorDef(params.edgesColor.r, params.edgesColor.g, params.edgesColor.b);
596
- highlightStylePtr.setEdgesColor(
597
- Entry.k3DTop.value | Entry.k3D.value | Entry.k2D.value | Entry.k2DTop.value,
598
- color
599
- );
600
- color.delete();
601
- }
602
-
603
- if (isExist(params.edgesVisibility)) {
604
- highlightStylePtr.setEdgesVisibility(
605
- Entry.k2D.value | Entry.k2DTop.value | Entry.k3DTop.value | Entry.k3D.value,
606
- params.edgesVisibility
607
- );
608
- }
609
- if (isExist(params.edgesOverlap)) {
610
- const visibility = !isExist(params.edgesVisibility) ? true : params.edgesVisibility;
611
- highlightStylePtr.setEdgesVisibility(Entry.k2DTop.value | Entry.k3DTop.value, params.edgesOverlap && visibility);
612
- }
613
-
614
- const device = visViewer.getActiveDevice();
615
- if (!device.isNull()) {
616
- const canvas = visLib.canvas;
617
-
618
- device.invalidate([0, canvas.width, canvas.height, 0]);
619
- device.delete();
620
- }
621
-
622
- return this;
623
- }
624
-
625
- get draggers(): string[] {
626
- return [...draggers.getDraggers().keys()];
627
- }
628
-
629
- get components(): string[] {
630
- return [...components.getComponents().keys()];
631
- }
632
-
633
- /**
634
- * Deprecated since `25.12`. Use {@link draggers.registerDragger} instead.
635
- */
636
- public registerDragger(name: string, dragger: typeof Dragger): void {
637
- console.warn(
638
- "Viewer.registerDragger() has been deprecated since 25.12 and will be removed in a future release, use draggers('visualizejs').registerDragger() instead."
639
- );
640
- draggers.registerDragger(name, (viewer: IViewer) => new dragger(viewer));
641
- }
642
-
643
- activeDragger(): IDragger | null {
644
- return this._activeDragger;
645
- }
646
-
647
- setActiveDragger(name = ""): IDragger | null {
648
- if (!this._activeDragger || this._activeDragger.name !== name) {
649
- const oldDragger = this._activeDragger;
650
- let newDragger = null;
651
-
652
- if (this._activeDragger) {
653
- this._activeDragger.dispose();
654
- this._activeDragger = null;
655
- }
656
- if (this.visualizeJs) {
657
- newDragger = draggers.createDragger(name, this);
658
- if (newDragger) {
659
- this._activeDragger = newDragger;
660
- this._activeDragger.initialize?.();
661
- }
662
- }
663
- const canvas = this.canvas;
664
- if (canvas) {
665
- if (oldDragger) canvas.classList.remove(`oda-cursor-${oldDragger.name.toLowerCase()}`);
666
- if (newDragger) canvas.classList.add(`oda-cursor-${newDragger.name.toLowerCase()}`);
667
- }
668
-
669
- this.emitEvent({ type: "changeactivedragger", data: name });
670
- this.update();
671
- }
672
- return this._activeDragger;
673
- }
674
-
675
- resetActiveDragger(): void {
676
- const dragger = this._activeDragger;
677
- if (dragger) {
678
- this.setActiveDragger();
679
- this.setActiveDragger(dragger.name);
680
- }
681
- }
682
-
683
- getComponent(name: string): IComponent {
684
- return this._components.find((component) => component.name === name);
685
- }
686
-
687
- clearSlices(): void {
688
- if (!this.visualizeJs) return;
689
-
690
- const visViewer = this.visViewer();
691
- const activeView = visViewer.activeView;
692
- activeView.removeCuttingPlanes();
693
- activeView.delete();
694
-
695
- this.update();
696
- }
697
-
698
- clearOverlay(): void {
699
- if (!this.visualizeJs) return;
700
-
701
- this._markup.clearOverlay();
702
- this.update();
703
- }
704
-
705
- syncOverlay(): void {
706
- if (!this.visualizeJs) return;
707
-
708
- const visViewer = this.visViewer();
709
- const activeView = visViewer.activeView;
710
-
711
- let overlayView = visViewer.getViewByName(OVERLAY_VIEW_NAME);
712
- if (!overlayView) {
713
- const markupModel = visViewer.getMarkupModel();
714
- const pDevice = visViewer.getActiveDevice();
715
-
716
- overlayView = pDevice.createView(OVERLAY_VIEW_NAME, false);
717
- overlayView.addModel(markupModel);
718
-
719
- activeView.addSibling(overlayView);
720
- pDevice.addView(overlayView);
721
- }
722
-
723
- overlayView.viewPosition = activeView.viewPosition;
724
- overlayView.viewTarget = activeView.viewTarget;
725
- overlayView.upVector = activeView.upVector;
726
- overlayView.viewFieldWidth = activeView.viewFieldWidth;
727
- overlayView.viewFieldHeight = activeView.viewFieldHeight;
728
-
729
- const viewPort = overlayView.getViewport();
730
- overlayView.setViewport(viewPort.lowerLeft, viewPort.upperRight);
731
- overlayView.vportRect = activeView.vportRect;
732
-
733
- this._markup.syncOverlay();
734
- this.update();
735
- }
736
-
737
- is3D(): boolean {
738
- if (!this.visualizeJs) return false;
739
-
740
- const visViewer = this.visViewer();
741
- const ext = visViewer.getActiveExtents();
742
- const min = ext.min();
743
- const max = ext.max();
744
- const extHeight = max[2] - min[2];
745
- return extHeight !== 0;
746
-
747
- //return visViewer.activeView.upVector[1] >= 0.95;
748
- }
749
-
750
- screenToWorld(position: { x: number; y: number }): { x: number; y: number; z: number } {
751
- if (!this.visualizeJs) return { x: position.x, y: position.y, z: 0 };
752
-
753
- const activeView = this.visViewer().activeView;
754
- const worldPoint = activeView.transformScreenToWorld(
755
- position.x * window.devicePixelRatio,
756
- position.y * window.devicePixelRatio
757
- );
758
-
759
- const result = { x: worldPoint[0], y: worldPoint[1], z: worldPoint[2] };
760
-
761
- activeView.delete();
762
-
763
- return result;
764
- }
765
-
766
- worldToScreen(position: { x: number; y: number; z: number }): { x: number; y: number } {
767
- if (!this.visualizeJs) return { x: position.x, y: position.y };
768
-
769
- const activeView = this.visViewer().activeView;
770
- const devicePoint = activeView.transformWorldToScreen(position.x, position.y, position.z);
771
-
772
- const result = { x: devicePoint[0] / window.devicePixelRatio, y: devicePoint[1] / window.devicePixelRatio };
773
-
774
- activeView.delete();
775
-
776
- return result;
777
- }
778
-
779
- getScale(): { x: number; y: number; z: number } {
780
- const result = { x: 1.0, y: 1.0, z: 1.0 };
781
-
782
- const projMatrix = this.visViewer().activeView.projectionMatrix;
783
- const tolerance = 1.0e-6;
784
-
785
- const x = projMatrix.get(0, 0);
786
- if (x > tolerance || x < -tolerance) result.x = 1 / x;
787
-
788
- const y = projMatrix.get(1, 1);
789
- if (y > tolerance || y < -tolerance) result.y = 1 / y;
790
-
791
- const z = projMatrix.get(2, 2);
792
- if (z > tolerance || z < -tolerance) result.z = 1 / z;
793
-
794
- return result;
795
- }
796
-
797
- getSelected(): string[] {
798
- return this.executeCommand("getSelected");
799
- }
800
-
801
- setSelected(handles?: string[]): void {
802
- this.executeCommand("setSelected", handles);
803
- }
804
-
805
- clearSelected(): void {
806
- this.executeCommand("clearSelected");
807
- }
808
-
809
- hideSelected(): void {
810
- this.executeCommand("hideSelected");
811
- }
812
-
813
- isolateSelected(): void {
814
- this.executeCommand("isolateSelected");
815
- }
816
-
817
- showAll(): void {
818
- this.executeCommand("showAll");
819
- }
820
-
821
- explode(index = 0): void {
822
- this.executeCommand("explode", index);
823
- }
824
-
825
- collect(): void {
826
- this.executeCommand("collect");
827
- }
828
-
829
- // Internal loading routines
830
-
831
- async loadReferences(model: Model | File | Assembly): Promise<this> {
832
- if (!this.visualizeJs) return this;
833
- if (!this.client) return this;
834
- if (!model.getReferences) return this;
835
-
836
- const abortController = new AbortController();
837
- this._abortControllerForReferences?.abort();
838
- this._abortControllerForReferences = abortController;
839
-
840
- let references: any[] = [];
841
- await model
842
- .getReferences(abortController.signal)
843
- .then((data) => (references = data.references))
844
- .catch((e) => console.error("Cannot load model references.", e));
845
-
846
- for (const file of references) {
847
- await this.client
848
- .downloadFile(file.id, undefined, abortController.signal)
849
- .then((arrayBuffer) => this.visualizeJs?.getViewer().addEmbeddedFile(file.name, new Uint8Array(arrayBuffer)))
850
- .catch((e) => console.error(`Cannot load reference file ${file.name}.`, e));
851
- }
852
-
853
- return this;
854
- }
855
-
856
- applyModelTransformMatrix(model: Model | Assembly) {
857
- this.executeCommand("applyModelTransform", model);
858
- }
859
-
860
- applySceneGraphSettings(options = this.options) {
861
- if (!this.visualizeJs) return;
862
-
863
- const visLib = this.visLib();
864
- const visViewer = this.visViewer();
865
-
866
- const device = visViewer.getActiveDevice();
867
- if (isExist(options.sceneGraph)) {
868
- device.setOptionBool(visLib.DeviceOptions.kDelaySceneGraphProc, !options.sceneGraph);
869
- }
870
- // if (options.enablePartialMode && visLib.HpTrc.Usd >= visViewer.memoryLimit) {
871
- // device.setOptionBool(visLib.DeviceOptions.kDelaySceneGraphProc, true);
872
- // }
873
- device.delete();
874
-
875
- this.update();
876
- }
450
+ this.update();
451
+ }
877
452
 
878
453
  /**
879
454
  * Loads a file into the viewer.
@@ -890,8 +465,8 @@ export class Viewer
890
465
  * thrown.
891
466
  *
892
467
  * For URLs, the file extension is used to determine the file format. For a `ArrayBuffer` and `Data
893
- * URL`, a file format must be specified using `params.format` parameter (see below). If no appropriate
894
- * loader is found for the specified format, an exception will be thrown.
468
+ * URL`, a file format must be specified using `params.format` parameter. If no appropriate loader is
469
+ * found for the specified format, an exception will be thrown.
895
470
  *
896
471
  * If there was an active dragger before opening the file, it will be deactivated. After opening the
897
472
  * file, you must manually activate the required dragger.
@@ -908,6 +483,8 @@ export class Viewer
908
483
  *
909
484
  * Fires:
910
485
  *
486
+ * - {@link CancelEvent | cancel}
487
+ * - {@link ClearEvent | clear}
911
488
  * - {@link OpenEvent | open}
912
489
  * - {@link GeometryStartEvent | geometrystart}
913
490
  * - {@link GeometryProgressEvent | geometryprogress}
@@ -916,19 +493,20 @@ export class Viewer
916
493
  * - {@link GeometryEndEvent | geometryend}
917
494
  * - {@link GeometryErrorEvent | geometryerror}
918
495
  *
919
- * @param file - File to load. Can be one of:
496
+ * @param file - File to load. Can be:
920
497
  *
921
498
  * - `File`, `Assembly` or `Model` instance from the Open Cloud Server
922
- * - File `URL` string
499
+ * - `URL` string
923
500
  * - {@link https://developer.mozilla.org/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | Data URL} string
924
- * - {@link https://developer.mozilla.org/docs/Web/API/File | Web API File} object
501
+ * - {@link https://developer.mozilla.org/docs/Web/API/File | Web API dFile} object
925
502
  * - {@link https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer | ArrayBuffer}
926
503
  * object
927
504
  *
928
505
  * @param params - Loading parameters.
929
- * @param params.format - File format string. Required when loading a file as `ArrayBuffer` or `Data
930
- * URL`.
506
+ * @param params.format - File format. Can be one of `vsf` or `vsfx`. Required when loading a file as
507
+ * `ArrayBuffer` or `Data URL`.
931
508
  * @param params.mode - Reserved for future use.
509
+ * @param params.modelId - Reserved for future use.
932
510
  * @param params.requestHeader - The
933
511
  * {@link https://developer.mozilla.org/docs/Glossary/Request_header | request header} used in HTTP
934
512
  * request.
@@ -942,227 +520,529 @@ export class Viewer
942
520
  params: {
943
521
  format?: string;
944
522
  mode?: string;
523
+ modelId?: string;
945
524
  requestHeader?: HeadersInit;
946
525
  withCredentials?: boolean;
947
526
  } = {}
948
527
  ): Promise<this> {
949
528
  if (!this.visualizeJs) return this;
950
529
 
951
- this.cancel();
952
- this.clear();
530
+ this.cancel();
531
+ this.clear();
532
+
533
+ this.emitEvent({ type: "open", mode: "file", file });
534
+
535
+ let model: any = file;
536
+ if (model && typeof model.getModels === "function") {
537
+ const models = await model.getModels();
538
+ model = models.find((model: Model) => model.default) || models[0] || file;
539
+ }
540
+ if (model && typeof model.database === "string") {
541
+ file = model.file;
542
+ }
543
+ if (!model) throw new Error(`Format not supported`);
544
+
545
+ let format = params.format;
546
+ if (!format && typeof file["type"] === "string") format = file["type"].split(".").pop();
547
+ if (!format && typeof file === "string") format = file.split(".").pop();
548
+ if (!format && file instanceof globalThis.File) format = file.name.split(".").pop();
549
+
550
+ const loader = loaders.createLoader(this, model, format);
551
+ if (!loader) throw new Error(`Format not supported`);
552
+ this.loaders.push(loader);
553
+
554
+ this.emitEvent({ type: "geometrystart", file, model });
555
+ try {
556
+ await this.loadReferences(model);
557
+ await loader.load(model, format, params);
558
+ } catch (error: any) {
559
+ this.emitEvent({ type: "geometryerror", data: error, file, model });
560
+ throw error;
561
+ }
562
+ this.emitEvent({ type: "geometryend", file, model });
563
+
564
+ if (this.visualizeJs) {
565
+ this.applyModelTransformMatrix(model);
566
+ this.applySceneGraphSettings();
567
+ }
568
+
569
+ return this;
570
+ }
571
+
572
+ /**
573
+ * Deprecated since `26.4`. Use {@link open | open()} instead.
574
+ *
575
+ * @deprecated
576
+ */
577
+ openVsfFile(buffer: Uint8Array | ArrayBuffer): this {
578
+ console.warn(
579
+ "Viewer.openVsfFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead."
580
+ );
581
+
582
+ if (!this.visualizeJs) return this;
583
+
584
+ this.cancel();
585
+ this.clear();
586
+
587
+ this.emitEvent({ type: "open", mode: "file", file: "", buffer });
588
+
589
+ const visViewer = this.visViewer();
590
+
591
+ this.emitEvent({ type: "geometrystart", file: "", buffer });
592
+ try {
593
+ const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
594
+ visViewer.parseFile(data);
595
+
596
+ this.syncOptions();
597
+ this.syncOverlay();
598
+ this.update(true);
599
+
600
+ this.emitEvent({ type: "geometryprogress", data: 1, file: "", buffer });
601
+ this.emitEvent({ type: "databasechunk", data, file: "", buffer });
602
+ } catch (error: any) {
603
+ this.emitEvent({ type: "geometryerror", data: error, file: "", buffer });
604
+ throw error;
605
+ }
606
+ this.emitEvent({ type: "geometryend", file: "", buffer });
607
+
608
+ return this;
609
+ }
610
+
611
+ /**
612
+ * Deprecated since `26.4`. Use {@link open | open()} instead.
613
+ *
614
+ * @deprecated
615
+ */
616
+ openVsfxFile(buffer: Uint8Array | ArrayBuffer): this {
617
+ console.warn(
618
+ "Viewer.openVsfxFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead."
619
+ );
620
+
621
+ if (!this.visualizeJs) return this;
622
+
623
+ this.cancel();
624
+ this.clear();
625
+
626
+ this.emitEvent({ type: "open", mode: "file", file: "", buffer });
627
+
628
+ const visViewer = this.visViewer();
629
+
630
+ this.emitEvent({ type: "geometrystart", file: "", buffer });
631
+ try {
632
+ const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
633
+ visViewer.parseVsfx(data);
634
+
635
+ this.syncOptions();
636
+ this.syncOverlay();
637
+ this.update(true);
638
+
639
+ this.emitEvent({ type: "geometryprogress", data: 1, file: "", buffer });
640
+ this.emitEvent({ type: "databasechunk", data, file: "", buffer });
641
+ } catch (error: any) {
642
+ this.emitEvent({ type: "geometryerror", data: error, file: "", buffer });
643
+ throw error;
644
+ }
645
+ this.emitEvent({ type: "geometryend", file: "", buffer });
646
+
647
+ return this;
648
+ }
649
+
650
+ cancel(): this {
651
+ this._abortControllerForReferences?.abort();
652
+ this._abortControllerForReferences = undefined;
653
+
654
+ this.loaders.forEach((loader) => loader.cancel());
655
+
656
+ this.emitEvent({ type: "cancel" });
657
+ return this;
658
+ }
659
+
660
+ clear(): this {
661
+ if (!this.visualizeJs) return this;
662
+
663
+ const visViewer = this.visViewer();
664
+
665
+ this.setActiveDragger();
666
+ this.clearSlices();
667
+ this.clearOverlay();
668
+ this.clearSelected();
669
+
670
+ this.loaders.forEach((loader) => loader.dispose());
671
+ this.loaders = [];
672
+
673
+ this.models.forEach((model) => model.dispose());
674
+ this.models = [];
675
+
676
+ visViewer.clear();
677
+ visViewer.createLocalDatabase();
678
+
679
+ this.syncOptions();
680
+ this.syncOverlay();
681
+ this.update(true);
682
+
683
+ this.emitEvent({ type: "clear" });
684
+
685
+ return this;
686
+ }
687
+
688
+ is3D(): boolean {
689
+ if (!this.visualizeJs) return false;
690
+
691
+ const visViewer = this.visViewer();
692
+ const ext = visViewer.getActiveExtents();
693
+ const min = ext.min();
694
+ const max = ext.max();
695
+ const extHeight = max[2] - min[2];
696
+ return extHeight !== 0;
697
+
698
+ //return visViewer.activeView.upVector[1] >= 0.95;
699
+ }
700
+
701
+ syncOptions(options: IOptions = this.options): this {
702
+ if (!this.visualizeJs) return this;
703
+
704
+ const visLib = this.visLib();
705
+ const visViewer = this.visViewer();
706
+
707
+ const device = visViewer.getActiveDevice();
708
+ if (device.isNull()) return this;
709
+
710
+ // sync Open Cloud visual style
711
+
712
+ const view = device.getActiveView();
713
+
714
+ view.enableDefaultLighting(true, visLib.DefaultLightingType.kTwoLights);
715
+ view.setDefaultLightingIntensity(1.25);
716
+
717
+ let visualStyleId: any;
718
+ try {
719
+ visualStyleId = visViewer.findVisualStyle("OpenCloud");
720
+ } catch {
721
+ // Visualize.js 25.11 and earlier threw an exception if the style did not exist.
722
+ visualStyleId = undefined;
723
+ }
724
+
725
+ if (!visualStyleId || visualStyleId.isNull()) {
726
+ visualStyleId = visViewer.createVisualStyle("OpenCloud");
727
+
728
+ const colorDef = new visLib.OdTvColorDef(66, 66, 66);
729
+ const shadedVsId = visViewer.findVisualStyle("Realistic");
730
+
731
+ const visualStylePtr = visualStyleId.openObject();
732
+ visualStylePtr.copyFrom(shadedVsId);
733
+ visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kFaceModifiers, 0, visLib.VisualStyleOperations.kSet);
734
+ visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeModel, 2, visLib.VisualStyleOperations.kSet);
735
+ visualStylePtr.setOptionDouble(visLib.VisualStyleOptions.kEdgeCreaseAngle, 60, visLib.VisualStyleOperations.kSet);
736
+ visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeStyles, 0, visLib.VisualStyleOperations.kSet);
737
+ visualStylePtr.setOptionInt32(visLib.VisualStyleOptions.kEdgeModifiers, 8, visLib.VisualStyleOperations.kSet);
738
+ visualStylePtr.setOptionColor(
739
+ visLib.VisualStyleOptions.kEdgeColorValue,
740
+ colorDef,
741
+ visLib.VisualStyleOperations.kSet
742
+ );
743
+ visualStylePtr.delete();
744
+ }
745
+
746
+ view.visualStyle = visualStyleId;
747
+
748
+ // sync Visualize options
749
+
750
+ if (options.showWCS !== visViewer.getEnableWCS()) {
751
+ visViewer.setEnableWCS(options.showWCS);
752
+ }
753
+ if (options.cameraAnimation !== visViewer.getEnableAnimation()) {
754
+ visViewer.setEnableAnimation(options.cameraAnimation);
755
+ }
756
+
757
+ const antialiasing = options.antialiasing === true || options.antialiasing === "fxaa";
758
+ if (antialiasing !== visViewer.fxaaAntiAliasing3d) {
759
+ visViewer.fxaaAntiAliasing3d = antialiasing;
760
+ visViewer.fxaaQuality = 5;
761
+ }
762
+
763
+ if (options.shadows !== visViewer.shadows) {
764
+ visViewer.shadows = options.shadows;
765
+
766
+ // const canvas = visLib.canvas;
767
+ // device.invalidate([0, canvas.width, canvas.height, 0]);
768
+ }
769
+
770
+ if (options.groundShadow !== visViewer.groundShadow) {
771
+ visViewer.groundShadow = options.groundShadow;
772
+ }
773
+
774
+ if (options.ambientOcclusion !== device.getOptionBool(visLib.DeviceOptions.kSSAOEnable)) {
775
+ device.setOptionBool(visLib.DeviceOptions.kSSAOEnable, options.ambientOcclusion);
776
+ device.setOptionBool(visLib.DeviceOptions.kSSAODynamicRadius, true);
777
+ device.setOptionDouble(visLib.DeviceOptions.kSSAORadius, 1);
778
+ device.setOptionInt32(visLib.DeviceOptions.kSSAOLoops, 32);
779
+ device.setOptionDouble(visLib.DeviceOptions.kSSAOPower, 2);
780
+ device.setOptionInt32(visLib.DeviceOptions.kSSAOBlurRadius, 2);
781
+
782
+ const activeView = visViewer.activeView;
783
+ activeView.setSSAOEnabled(options.ambientOcclusion);
784
+ activeView.delete();
785
+ }
953
786
 
954
- this.emitEvent({ type: "open", file });
787
+ if (isExist(options.edgeModel)) {
788
+ const activeView = device.getActiveView();
955
789
 
956
- let model: any = file;
957
- if (model && typeof model.getModels === "function") {
958
- const models = await model.getModels();
959
- model = models.find((model: Model) => model.default) || models[0] || file;
790
+ const visualStyleId = visViewer.findVisualStyle("OpenCloud");
791
+ const visualStylePtr = visualStyleId.openObject();
792
+
793
+ visualStylePtr.setOptionInt32(
794
+ visLib.VisualStyleOptions.kEdgeModel,
795
+ options.edgeModel ? 2 : 0,
796
+ visLib.VisualStyleOperations.kSet
797
+ );
798
+
799
+ activeView.visualStyle = visualStyleId;
800
+
801
+ visualStylePtr.delete();
802
+ visualStyleId.delete();
803
+ activeView.delete();
960
804
  }
961
- if (!model) throw new Error(`Format not supported`);
962
805
 
963
- let format = params.format;
964
- if (!format && typeof model.type === "string") format = model.type.split(".").pop();
965
- if (!format && typeof file === "string") format = file.split(".").pop();
966
- if (!format && file instanceof globalThis.File) format = file.name.split(".").pop();
806
+ // sync highlighting options
967
807
 
968
- const loader = loaders.createLoader(this, model, format);
969
- if (!loader) throw new Error(`Format not supported`);
970
- this.loaders.push(loader);
808
+ const params = options.enableCustomHighlight ? options : Options.defaults();
971
809
 
972
- this.emitEvent({ type: "geometrystart", file, model });
973
- try {
974
- await this.loadReferences(model);
975
- await loader.load(model, format, params);
976
- } catch (error: any) {
977
- this.emitEvent({ type: "geometryerror", data: error, file, model });
978
- throw error;
810
+ const { Entry, OdTvRGBColorDef } = visLib;
811
+
812
+ const highlightStyleId = visViewer.findHighlightStyle("Web_Default");
813
+ const highlightStylePtr = highlightStyleId.openObject();
814
+
815
+ if (isExist(params.facesColor)) {
816
+ const color = new OdTvRGBColorDef(params.facesColor.r, params.facesColor.g, params.facesColor.b);
817
+ highlightStylePtr.setFacesColor(Entry.k3D.value | Entry.k3DTop.value, color);
818
+ color.delete();
979
819
  }
980
- this.emitEvent({ type: "geometryend", file, model });
981
820
 
982
- if (this.visualizeJs) {
983
- this.applyModelTransformMatrix(model);
984
- this.applySceneGraphSettings();
821
+ if (isExist(params.facesOverlap)) {
822
+ highlightStylePtr.setFacesVisibility(Entry.k3DTop.value, params.facesOverlap);
823
+ }
824
+ if (isExist(params.facesTransparancy)) {
825
+ highlightStylePtr.setFacesTransparency(Entry.k3D.value | Entry.k3DTop.value, params.facesTransparancy);
985
826
  }
986
827
 
987
- return this;
988
- }
828
+ if (isExist(params.edgesColor)) {
829
+ const color = new OdTvRGBColorDef(params.edgesColor.r, params.edgesColor.g, params.edgesColor.b);
830
+ highlightStylePtr.setEdgesColor(
831
+ Entry.k3DTop.value | Entry.k3D.value | Entry.k2D.value | Entry.k2DTop.value,
832
+ color
833
+ );
834
+ color.delete();
835
+ }
989
836
 
990
- /**
991
- * Deprecated since `26.4`. Use {@link open | open()} instead.
992
- *
993
- * @deprecated
994
- */
995
- openVsfFile(buffer: Uint8Array | ArrayBuffer): this {
996
- console.warn(
997
- "Viewer.openVsfFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead."
998
- );
837
+ if (isExist(params.edgesVisibility)) {
838
+ highlightStylePtr.setEdgesVisibility(
839
+ Entry.k2D.value | Entry.k2DTop.value | Entry.k3DTop.value | Entry.k3D.value,
840
+ params.edgesVisibility
841
+ );
842
+ }
843
+ if (isExist(params.edgesOverlap)) {
844
+ const visibility = !isExist(params.edgesVisibility) ? true : params.edgesVisibility;
845
+ highlightStylePtr.setEdgesVisibility(Entry.k2DTop.value | Entry.k3DTop.value, params.edgesOverlap && visibility);
846
+ }
999
847
 
1000
- if (!this.visualizeJs) return this;
848
+ // const canvas = visLib.canvas;
849
+ // device.invalidate([0, canvas.width, canvas.height, 0]);
1001
850
 
1002
- this.cancel();
1003
- this.clear();
851
+ view.delete();
852
+ device.delete();
853
+
854
+ this.update();
855
+
856
+ return this;
857
+ }
1004
858
 
1005
- this.emitEvent({ type: "open", file: "", buffer });
859
+ syncOverlay(): void {
860
+ if (!this.visualizeJs) return;
1006
861
 
1007
862
  const visViewer = this.visViewer();
863
+ const activeView = visViewer.activeView;
1008
864
 
1009
- this.emitEvent({ type: "geometrystart", file: "", buffer });
1010
- try {
1011
- const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
1012
- visViewer.parseFile(data);
865
+ let overlayView = visViewer.getViewByName(OVERLAY_VIEW_NAME);
866
+ if (!overlayView) {
867
+ const markupModel = visViewer.getMarkupModel();
868
+ const pDevice = visViewer.getActiveDevice();
1013
869
 
1014
- this.syncOptions();
1015
- this.syncOverlay();
1016
- this.update(true);
870
+ overlayView = pDevice.createView(OVERLAY_VIEW_NAME, false);
871
+ overlayView.addModel(markupModel);
1017
872
 
1018
- this.emitEvent({ type: "geometryprogress", data: 1, file: "", buffer });
1019
- this.emitEvent({ type: "databasechunk", data, file: "", buffer });
1020
- } catch (error: any) {
1021
- this.emitEvent({ type: "geometryerror", data: error, file: "", buffer });
1022
- throw error;
873
+ activeView.addSibling(overlayView);
874
+ pDevice.addView(overlayView);
1023
875
  }
1024
- this.emitEvent({ type: "geometryend", file: "", buffer });
1025
876
 
1026
- return this;
1027
- }
877
+ overlayView.viewPosition = activeView.viewPosition;
878
+ overlayView.viewTarget = activeView.viewTarget;
879
+ overlayView.upVector = activeView.upVector;
880
+ overlayView.viewFieldWidth = activeView.viewFieldWidth;
881
+ overlayView.viewFieldHeight = activeView.viewFieldHeight;
1028
882
 
1029
- /**
1030
- * Deprecated since `26.4`. Use {@link open | open()} instead.
1031
- *
1032
- * @deprecated
1033
- */
1034
- openVsfxFile(buffer: Uint8Array | ArrayBuffer): this {
1035
- console.warn(
1036
- "Viewer.openVsfxFile() has been deprecated since 26.4 and will be removed in a future release, use Viewer.open() instead."
1037
- );
883
+ const viewPort = overlayView.getViewport();
884
+ overlayView.setViewport(viewPort.lowerLeft, viewPort.upperRight);
885
+ overlayView.vportRect = activeView.vportRect;
1038
886
 
1039
- if (!this.visualizeJs) return this;
887
+ this._markup.syncOverlay();
888
+ this.update();
889
+ }
1040
890
 
1041
- this.cancel();
1042
- this.clear();
891
+ clearOverlay(): void {
892
+ if (!this.visualizeJs) return;
893
+
894
+ this._markup.clearOverlay();
895
+ this.update();
896
+ }
1043
897
 
1044
- this.emitEvent({ type: "open", file: "", buffer });
898
+ clearSlices(): void {
899
+ if (!this.visualizeJs) return;
1045
900
 
1046
901
  const visViewer = this.visViewer();
902
+ const activeView = visViewer.activeView;
903
+ activeView.removeCuttingPlanes();
904
+ activeView.delete();
1047
905
 
1048
- this.emitEvent({ type: "geometrystart", file: "", buffer });
1049
- try {
1050
- const data = buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);
1051
- visViewer.parseVsfx(data);
906
+ this.update();
907
+ }
1052
908
 
1053
- this.syncOptions();
1054
- this.syncOverlay();
1055
- this.update(true);
909
+ getSelected(): string[] {
910
+ return this.executeCommand("getSelected");
911
+ }
1056
912
 
1057
- this.emitEvent({ type: "geometryprogress", data: 1, file: "", buffer });
1058
- this.emitEvent({ type: "databasechunk", data, file: "", buffer });
1059
- } catch (error: any) {
1060
- this.emitEvent({ type: "geometryerror", data: error, file: "", buffer });
1061
- throw error;
1062
- }
1063
- this.emitEvent({ type: "geometryend", file: "", buffer });
913
+ setSelected(handles?: string[]): void {
914
+ this.executeCommand("setSelected", handles);
915
+ }
1064
916
 
1065
- return this;
917
+ getSelected2(): string[] {
918
+ return this.executeCommand("getSelected2");
1066
919
  }
1067
920
 
1068
- cancel(): this {
1069
- this._abortControllerForReferences?.abort();
1070
- this._abortControllerForReferences = undefined;
921
+ setSelected2(handles?: string[]): void {
922
+ this.executeCommand("setSelected2", handles);
923
+ }
1071
924
 
1072
- this.loaders.forEach((loader) => loader.cancel());
925
+ clearSelected(): void {
926
+ this.executeCommand("clearSelected");
927
+ }
1073
928
 
1074
- this.emitEvent({ type: "cancel" });
1075
- return this;
929
+ hideSelected(): void {
930
+ this.executeCommand("hideSelected");
1076
931
  }
1077
932
 
1078
- clear(): this {
1079
- if (!this.visualizeJs) return this;
933
+ isolateSelected(): void {
934
+ this.executeCommand("isolateSelected");
935
+ }
1080
936
 
1081
- const visViewer = this.visViewer();
937
+ showAll(): void {
938
+ this.executeCommand("showAll");
939
+ }
1082
940
 
1083
- this.setActiveDragger();
1084
- this.clearSlices();
1085
- this.clearOverlay();
1086
- this.clearSelected();
941
+ explode(index = 0): void {
942
+ this.executeCommand("explode", index);
943
+ }
1087
944
 
1088
- this.loaders.forEach((loader) => loader.dispose());
1089
- this.loaders = [];
945
+ collect(): void {
946
+ this.executeCommand("collect");
947
+ }
1090
948
 
1091
- visViewer.clear();
1092
- visViewer.createLocalDatabase();
949
+ /**
950
+ * Deprecated since `25.12`. Use {@link draggers.registerDragger} instead.
951
+ */
952
+ public registerDragger(name: string, dragger: typeof Dragger): void {
953
+ console.warn(
954
+ "Viewer.registerDragger() has been deprecated since 25.12 and will be removed in a future release, use draggers('visualizejs').registerDragger() instead."
955
+ );
956
+ draggers.registerDragger(name, (viewer: IViewer) => new dragger(viewer));
957
+ }
1093
958
 
1094
- this.syncOptions();
1095
- this.syncOverlay();
1096
- this.update(true);
959
+ activeDragger(): IDragger | null {
960
+ return this._activeDragger;
961
+ }
1097
962
 
1098
- this.emitEvent({ type: "clear" });
963
+ setActiveDragger(name = ""): IDragger | null {
964
+ if (!this._activeDragger || this._activeDragger.name !== name) {
965
+ const oldDragger = this._activeDragger;
966
+ let newDragger = null;
1099
967
 
1100
- return this;
1101
- }
968
+ if (this._activeDragger) {
969
+ this._activeDragger.dispose();
970
+ this._activeDragger = null;
971
+ }
972
+ if (this.visualizeJs) {
973
+ newDragger = draggers.createDragger(name, this);
974
+ if (newDragger) {
975
+ this._activeDragger = newDragger;
976
+ this._activeDragger.initialize?.();
977
+ }
978
+ }
979
+ const canvas = this.canvas;
980
+ if (canvas) {
981
+ if (oldDragger) canvas.classList.remove(`oda-cursor-${oldDragger.name.toLowerCase()}`);
982
+ if (newDragger) canvas.classList.add(`oda-cursor-${newDragger.name.toLowerCase()}`);
983
+ }
1102
984
 
1103
- /**
1104
- * Deprecated since `25.11`. Use {@link IMarkup.getMarkupColor | markup.getMarkupColor()} instead.
1105
- */
1106
- getMarkupColor(): { r: number; g: number; b: number } {
1107
- console.warn(
1108
- "Viewer.getMarkupColor() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.getMarkupColor() instead."
1109
- );
1110
- return this._markup.getMarkupColor();
985
+ this.emitEvent({ type: "changeactivedragger", data: name });
986
+ this.update();
987
+ }
988
+ return this._activeDragger;
1111
989
  }
1112
990
 
1113
- /**
1114
- * Deprecated since `25.11`. Use {@link IMarkup.setMarkupColor | markup.setMarkupColor()} instead.
1115
- */
1116
- setMarkupColor(r = 255, g = 0, b = 0): void {
1117
- console.warn(
1118
- "Viewer.setMarkupColor() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.setMarkupColor() instead."
1119
- );
1120
- this._markup.setMarkupColor(r, g, b);
991
+ resetActiveDragger(): void {
992
+ const dragger = this._activeDragger;
993
+ if (dragger) {
994
+ this.setActiveDragger();
995
+ this.setActiveDragger(dragger.name);
996
+ }
1121
997
  }
1122
998
 
1123
- /**
1124
- * Deprecated since `25.11`. Use {@link IMarkup.colorizeAllMarkup | markup.colorizeAllMarkup()} instead.
1125
- */
1126
- colorizeAllMarkup(r = 255, g = 0, b = 0): void {
1127
- console.warn(
1128
- "Viewer.colorizeAllMarkup() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.colorizeAllMarkup() instead."
1129
- );
1130
- this._markup.colorizeAllMarkup(r, g, b);
999
+ getComponent(name: string): IComponent {
1000
+ return this._components.find((component) => component.name === name);
1131
1001
  }
1132
1002
 
1133
- /**
1134
- * Deprecated since `25.11`. Use
1135
- * {@link IMarkup.colorizeSelectedMarkups | markup.colorizeSelectedMarkups()} instead.
1136
- */
1137
- colorizeSelectedMarkups(r = 255, g = 0, b = 0): void {
1138
- this._markup.colorizeSelectedMarkups(r, g, b);
1139
- }
1003
+ drawViewpoint(viewpoint: IViewpoint): void {
1004
+ if (!this.visualizeJs) return;
1140
1005
 
1141
- /**
1142
- * Adds an empty `Visualize` markup entity to the overlay.
1143
- */
1144
- addMarkupEntity(entityName: string) {
1145
- if (!this.visualizeJs) return null;
1006
+ const visViewer = this.visViewer();
1007
+ const activeView = visViewer.activeView;
1146
1008
 
1147
- this.syncOverlay();
1009
+ const getPoint3dAsArray = (point3d: IPoint): number[] => {
1010
+ return [point3d.x, point3d.y, point3d.z];
1011
+ };
1148
1012
 
1149
- const visViewer = this.visViewer();
1150
- const model = visViewer.getMarkupModel();
1151
- const entityId = model.appendEntity(entityName);
1152
- const entityPtr = entityId.openObject();
1013
+ const setOrthogonalCamera = (orthogonal_camera: IOrthogonalCamera) => {
1014
+ if (orthogonal_camera) {
1015
+ activeView.setView(
1016
+ getPoint3dAsArray(orthogonal_camera.view_point),
1017
+ getPoint3dAsArray(orthogonal_camera.direction),
1018
+ getPoint3dAsArray(orthogonal_camera.up_vector),
1019
+ orthogonal_camera.field_width,
1020
+ orthogonal_camera.field_height,
1021
+ true
1022
+ );
1153
1023
 
1154
- const color = this.getMarkupColor();
1155
- entityPtr.setColor(color.r, color.g, color.b);
1156
- entityPtr.setLineWeight(2);
1157
- entityPtr.delete();
1024
+ this.syncOverlay();
1025
+ this.emitEvent({ type: "changecameramode", mode: "orthographic" });
1026
+ }
1027
+ };
1158
1028
 
1159
- this.update();
1029
+ const setPerspectiveCamera = (perspective_camera: IPerspectiveCamera) => {};
1160
1030
 
1161
- return entityId;
1162
- }
1031
+ const setClippingPlanes = (clipping_planes: IClippingPlane[]) => {
1032
+ if (clipping_planes) {
1033
+ for (const clipping_plane of clipping_planes) {
1034
+ const cuttingPlane = new (this.visLib().OdTvPlane)();
1035
+ cuttingPlane.set(getPoint3dAsArray(clipping_plane.location), getPoint3dAsArray(clipping_plane.direction));
1163
1036
 
1164
- drawViewpoint(viewpoint: IViewpoint): void {
1165
- if (!this.visualizeJs) return;
1037
+ activeView.addCuttingPlane(cuttingPlane);
1038
+ activeView.setEnableCuttingPlaneFill(true, 0x66, 0x66, 0x66);
1039
+ }
1040
+ }
1041
+ };
1042
+
1043
+ const setSelection = (selection: IEntity[]) => {
1044
+ if (selection) this.setSelected(selection.map((component) => component.handle));
1045
+ };
1166
1046
 
1167
1047
  const draggerName = this._activeDragger?.name;
1168
1048
 
@@ -1174,9 +1054,10 @@ export class Viewer
1174
1054
  this.showAll();
1175
1055
  this.explode();
1176
1056
 
1177
- this.setOrthogonalCameraSettings(viewpoint.orthogonal_camera);
1178
- this.setClippingPlanes(viewpoint.clipping_planes);
1179
- this.setSelection(viewpoint.selection);
1057
+ setOrthogonalCamera(viewpoint.orthogonal_camera);
1058
+ setPerspectiveCamera(viewpoint.perspective_camera);
1059
+ setClippingPlanes(viewpoint.clipping_planes);
1060
+ setSelection(viewpoint.custom_fields?.selection2 || viewpoint.selection);
1180
1061
  this._markup.setViewpoint(viewpoint);
1181
1062
 
1182
1063
  this.setActiveDragger(draggerName);
@@ -1187,103 +1068,119 @@ export class Viewer
1187
1068
  createViewpoint(): IViewpoint {
1188
1069
  if (!this.visualizeJs) return {};
1189
1070
 
1190
- const viewpoint: IViewpoint = {};
1071
+ const visViewer = this.visViewer();
1072
+ const activeView = visViewer.activeView;
1073
+
1074
+ const getPoint3dFromArray = (array: number[]): IPoint => {
1075
+ return { x: array[0], y: array[1], z: array[2] };
1076
+ };
1077
+
1078
+ const getOrthogonalCamera = (): IOrthogonalCamera => {
1079
+ return {
1080
+ view_point: getPoint3dFromArray(activeView.viewPosition),
1081
+ direction: getPoint3dFromArray(activeView.viewTarget),
1082
+ up_vector: getPoint3dFromArray(activeView.upVector),
1083
+ field_width: activeView.viewFieldWidth,
1084
+ field_height: activeView.viewFieldHeight,
1085
+ view_to_world_scale: 1,
1086
+ };
1087
+ };
1088
+
1089
+ const getPerspectiveCamera = (): IPerspectiveCamera => {
1090
+ return undefined;
1091
+ };
1092
+
1093
+ const getClippingPlanes = (): IClippingPlane[] => {
1094
+ const clipping_planes = [];
1095
+ for (let i = 0; i < activeView.numCuttingPlanes(); i++) {
1096
+ const cuttingPlane = activeView.getCuttingPlane(i);
1097
+
1098
+ const clipping_plane = {
1099
+ location: getPoint3dFromArray(cuttingPlane.getOrigin()),
1100
+ direction: getPoint3dFromArray(cuttingPlane.normal()),
1101
+ };
1102
+
1103
+ clipping_planes.push(clipping_plane);
1104
+ }
1105
+
1106
+ return clipping_planes;
1107
+ };
1108
+
1109
+ const getSelection = (): IEntity[] => {
1110
+ return this.getSelected().map((handle) => ({ handle }));
1111
+ };
1112
+
1113
+ const getSelection2 = (): IEntity[] => {
1114
+ return this.getSelected2().map((handle) => ({ handle }));
1115
+ };
1116
+
1117
+ const viewpoint: IViewpoint = { custom_fields: {} };
1191
1118
 
1192
- viewpoint.orthogonal_camera = this.getOrthogonalCameraSettings();
1193
- viewpoint.clipping_planes = this.getClippingPlanes();
1194
- viewpoint.selection = this.getSelection();
1119
+ viewpoint.orthogonal_camera = getOrthogonalCamera();
1120
+ viewpoint.perspective_camera = getPerspectiveCamera();
1121
+ viewpoint.clipping_planes = getClippingPlanes();
1122
+ viewpoint.selection = getSelection();
1195
1123
  viewpoint.description = new Date().toDateString();
1196
1124
  this._markup.getViewpoint(viewpoint);
1197
1125
 
1126
+ viewpoint.custom_fields.selection2 = getSelection2();
1127
+
1198
1128
  this.emitEvent({ type: "createviewpoint", data: viewpoint });
1199
1129
 
1200
1130
  return viewpoint;
1201
1131
  }
1202
1132
 
1203
- private getPoint3dFromArray(array: number[]) {
1204
- return { x: array[0], y: array[1], z: array[2] };
1205
- }
1133
+ // IWorldTransform
1206
1134
 
1207
- private getLogicalPoint3dAsArray(point3d: IPoint) {
1208
- return [point3d.x, point3d.y, point3d.z];
1209
- }
1135
+ screenToWorld(position: { x: number; y: number }): { x: number; y: number; z: number } {
1136
+ if (!this.visualizeJs) return { x: position.x, y: position.y, z: 0 };
1210
1137
 
1211
- private getOrthogonalCameraSettings(): IOrthogonalCamera {
1212
- const visViewer = this.visViewer();
1213
- const activeView = visViewer.activeView;
1138
+ const activeView = this.visViewer().activeView;
1139
+ const worldPoint = activeView.transformScreenToWorld(
1140
+ position.x * window.devicePixelRatio,
1141
+ position.y * window.devicePixelRatio
1142
+ );
1214
1143
 
1215
- return {
1216
- view_point: this.getPoint3dFromArray(activeView.viewPosition),
1217
- direction: this.getPoint3dFromArray(activeView.viewTarget),
1218
- up_vector: this.getPoint3dFromArray(activeView.upVector),
1219
- field_width: activeView.viewFieldWidth,
1220
- field_height: activeView.viewFieldHeight,
1221
- view_to_world_scale: 1,
1222
- };
1223
- }
1144
+ const result = { x: worldPoint[0], y: worldPoint[1], z: worldPoint[2] };
1224
1145
 
1225
- private setOrthogonalCameraSettings(settings: IOrthogonalCamera) {
1226
- const visViewer = this.visViewer();
1227
- const activeView = visViewer.activeView;
1146
+ activeView.delete();
1228
1147
 
1229
- if (settings) {
1230
- activeView.setView(
1231
- this.getLogicalPoint3dAsArray(settings.view_point),
1232
- this.getLogicalPoint3dAsArray(settings.direction),
1233
- this.getLogicalPoint3dAsArray(settings.up_vector),
1234
- settings.field_width,
1235
- settings.field_height,
1236
- true
1237
- );
1238
- this.syncOverlay();
1239
- }
1148
+ return result;
1240
1149
  }
1241
1150
 
1242
- private getClippingPlanes(): IClippingPlane[] {
1243
- const visViewer = this.visViewer();
1244
- const activeView = visViewer.activeView;
1151
+ worldToScreen(position: { x: number; y: number; z: number }): { x: number; y: number } {
1152
+ if (!this.visualizeJs) return { x: position.x, y: position.y };
1245
1153
 
1246
- const clipping_planes = [];
1247
- for (let i = 0; i < activeView.numCuttingPlanes(); i++) {
1248
- const cuttingPlane = activeView.getCuttingPlane(i);
1154
+ const activeView = this.visViewer().activeView;
1155
+ const devicePoint = activeView.transformWorldToScreen(position.x, position.y, position.z);
1249
1156
 
1250
- const clipping_plane = {
1251
- location: this.getPoint3dFromArray(cuttingPlane.getOrigin()),
1252
- direction: this.getPoint3dFromArray(cuttingPlane.normal()),
1253
- };
1157
+ const result = { x: devicePoint[0] / window.devicePixelRatio, y: devicePoint[1] / window.devicePixelRatio };
1254
1158
 
1255
- clipping_planes.push(clipping_plane);
1256
- }
1159
+ activeView.delete();
1257
1160
 
1258
- return clipping_planes;
1161
+ return result;
1259
1162
  }
1260
1163
 
1261
- private setClippingPlanes(clipping_planes: IClippingPlane[]) {
1262
- if (clipping_planes) {
1263
- const visViewer = this.visViewer();
1264
- const activeView = visViewer.activeView;
1164
+ getScale(): { x: number; y: number; z: number } {
1165
+ const result = { x: 1.0, y: 1.0, z: 1.0 };
1265
1166
 
1266
- for (const clipping_plane of clipping_planes) {
1267
- const cuttingPlane = new (this.visLib().OdTvPlane)();
1268
- cuttingPlane.set(
1269
- this.getLogicalPoint3dAsArray(clipping_plane.location),
1270
- this.getLogicalPoint3dAsArray(clipping_plane.direction)
1271
- );
1167
+ const projMatrix = this.visViewer().activeView.projectionMatrix;
1168
+ const tolerance = 1.0e-6;
1272
1169
 
1273
- activeView.addCuttingPlane(cuttingPlane);
1274
- activeView.setEnableCuttingPlaneFill(true, 0x66, 0x66, 0x66);
1275
- }
1276
- }
1277
- }
1170
+ const x = projMatrix.get(0, 0);
1171
+ if (x > tolerance || x < -tolerance) result.x = 1 / x;
1278
1172
 
1279
- private getSelection(): IEntity[] {
1280
- return this.getSelected().map((handle) => ({ handle }));
1281
- }
1173
+ const y = projMatrix.get(1, 1);
1174
+ if (y > tolerance || y < -tolerance) result.y = 1 / y;
1175
+
1176
+ const z = projMatrix.get(2, 2);
1177
+ if (z > tolerance || z < -tolerance) result.z = 1 / z;
1282
1178
 
1283
- private setSelection(selection: IEntity[]) {
1284
- this.setSelected(selection?.map((component) => component.handle));
1179
+ return result;
1285
1180
  }
1286
1181
 
1182
+ // ICommandService
1183
+
1287
1184
  /**
1288
1185
  * Executes the command denoted by the given command. If the command is not found, tries to set active
1289
1186
  * dragger with the specified name.
@@ -1325,6 +1222,118 @@ export class Viewer
1325
1222
  return commands.executeCommand(id, this, ...args);
1326
1223
  }
1327
1224
 
1225
+ // VisualizeJS viewer specific
1226
+
1227
+ /**
1228
+ * Adds an empty `Visualize` markup entity to the VisualizeJS overlay.
1229
+ */
1230
+ addMarkupEntity(entityName: string) {
1231
+ if (!this.visualizeJs) return null;
1232
+
1233
+ this.syncOverlay();
1234
+
1235
+ const visViewer = this.visViewer();
1236
+ const model = visViewer.getMarkupModel();
1237
+ const entityId = model.appendEntity(entityName);
1238
+ const entityPtr = entityId.openObject();
1239
+
1240
+ const color = this.getMarkupColor();
1241
+ entityPtr.setColor(color.r, color.g, color.b);
1242
+ entityPtr.setLineWeight(2);
1243
+ entityPtr.delete();
1244
+
1245
+ this.update();
1246
+
1247
+ return entityId;
1248
+ }
1249
+
1250
+ /**
1251
+ * Deprecated since `25.11`. Use {@link IMarkup.getMarkupColor | markup.getMarkupColor()} instead.
1252
+ */
1253
+ getMarkupColor(): { r: number; g: number; b: number } {
1254
+ console.warn(
1255
+ "Viewer.getMarkupColor() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.getMarkupColor() instead."
1256
+ );
1257
+ return this._markup.getMarkupColor();
1258
+ }
1259
+
1260
+ /**
1261
+ * Deprecated since `25.11`. Use {@link IMarkup.setMarkupColor | markup.setMarkupColor()} instead.
1262
+ */
1263
+ setMarkupColor(r = 255, g = 0, b = 0): void {
1264
+ console.warn(
1265
+ "Viewer.setMarkupColor() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.setMarkupColor() instead."
1266
+ );
1267
+ this._markup.setMarkupColor(r, g, b);
1268
+ }
1269
+
1270
+ /**
1271
+ * Deprecated since `25.11`. Use {@link IMarkup.colorizeAllMarkup | markup.colorizeAllMarkup()} instead.
1272
+ */
1273
+ colorizeAllMarkup(r = 255, g = 0, b = 0): void {
1274
+ console.warn(
1275
+ "Viewer.colorizeAllMarkup() has been deprecated since 25.11 and will be removed in a future release, use Viewer.markup.colorizeAllMarkup() instead."
1276
+ );
1277
+ this._markup.colorizeAllMarkup(r, g, b);
1278
+ }
1279
+
1280
+ /**
1281
+ * Deprecated since `25.11`. Use
1282
+ * {@link IMarkup.colorizeSelectedMarkups | markup.colorizeSelectedMarkups()} instead.
1283
+ */
1284
+ colorizeSelectedMarkups(r = 255, g = 0, b = 0): void {
1285
+ this._markup.colorizeSelectedMarkups(r, g, b);
1286
+ }
1287
+
1288
+ private scheduleUpdateAsync(maxScheduleUpdateTimeInMs = 50): Promise<void> {
1289
+ return new Promise<void>((resolve, reject) => {
1290
+ setTimeout(() => {
1291
+ try {
1292
+ if (this._enableAutoUpdate) {
1293
+ this.visViewer()?.update(maxScheduleUpdateTimeInMs);
1294
+ this._activeDragger?.updatePreview?.();
1295
+ }
1296
+ this.emitEvent({ type: "update", data: false });
1297
+ resolve();
1298
+ } catch (e) {
1299
+ console.error(e);
1300
+ reject();
1301
+ }
1302
+ }, 0);
1303
+ });
1304
+ }
1305
+
1306
+ /**
1307
+ * Updates the viewer asynchronously without locking the user interface. Used to update the viewer
1308
+ * after changes that require a long rendering time.
1309
+ *
1310
+ * Do nothing if the auto-update mode is disabled in the constructor. In this case, register an
1311
+ * `update` event handler and update the `VisualizeJS` viewer and active dragger manually.
1312
+ *
1313
+ * Fires:
1314
+ *
1315
+ * - {@link UpdateEvent | update}
1316
+ *
1317
+ * @param maxScheduleUpdateTimeInMs - Maximum time for one update, default 30 ms.
1318
+ * @param maxScheduleUpdateCount - Maximum count of scheduled updates.
1319
+ */
1320
+ async updateAsync(maxScheduleUpdateTimeInMs = 50, maxScheduleUpdateCount = 50): Promise<void> {
1321
+ if (!this.visualizeJs) return;
1322
+
1323
+ this._isRunAsyncUpdate = true;
1324
+ try {
1325
+ const device = this.visViewer().getActiveDevice();
1326
+ for (let iterationCount = 0; !device.isValid() && iterationCount < maxScheduleUpdateCount; iterationCount++) {
1327
+ await this.scheduleUpdateAsync(maxScheduleUpdateTimeInMs);
1328
+ }
1329
+ await this.scheduleUpdateAsync(maxScheduleUpdateTimeInMs);
1330
+ } catch (e) {
1331
+ console.error(e);
1332
+ } finally {
1333
+ this._isRunAsyncUpdate = false;
1334
+ }
1335
+ }
1336
+
1328
1337
  public deviceAutoRegeneration() {
1329
1338
  const visViewer = this.visViewer();
1330
1339
  const device = visViewer.getActiveDevice();