@smarterplan/ngx-smarterplan-core 1.4.12 → 1.4.13
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.
- package/esm2022/lib/services/matterport-tag.service.mjs +169 -60
- package/esm2022/lib/services/matterport.service.mjs +222 -39
- package/esm2022/lib/services/viewer.service.mjs +8 -1
- package/esm2022/lib/types.service.mjs +9 -1
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs +404 -97
- package/fesm2022/smarterplan-ngx-smarterplan-core.mjs.map +1 -1
- package/lib/services/matterport-tag.service.d.ts +61 -7
- package/lib/services/matterport.service.d.ts +56 -1
- package/lib/types.service.d.ts +18 -0
- package/package.json +1 -1
|
@@ -426,6 +426,14 @@ var SpModule;
|
|
|
426
426
|
SpModule["HOTEL"] = "HOTEL";
|
|
427
427
|
SpModule["IMMO"] = "IMMO";
|
|
428
428
|
})(SpModule || (SpModule = {}));
|
|
429
|
+
var MatterportViewType;
|
|
430
|
+
(function (MatterportViewType) {
|
|
431
|
+
MatterportViewType["BASE"] = "viewtype.base";
|
|
432
|
+
MatterportViewType["DEFURNISH"] = "viewtype.defurnish";
|
|
433
|
+
MatterportViewType["LAYERED_BASE"] = "viewtype.layeredbase";
|
|
434
|
+
MatterportViewType["OTHER"] = "viewtype.other";
|
|
435
|
+
MatterportViewType["USER"] = "viewtype.user";
|
|
436
|
+
})(MatterportViewType || (MatterportViewType = {}));
|
|
429
437
|
|
|
430
438
|
/**
|
|
431
439
|
* The base of all `SceneComponent` created with the sdk.
|
|
@@ -3407,6 +3415,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
|
|
|
3407
3415
|
|
|
3408
3416
|
class MatterportTagService {
|
|
3409
3417
|
navigationService;
|
|
3418
|
+
/** Name of the common layer every Smarterplan tag is created in. */
|
|
3419
|
+
static SHARED_TAG_LAYER_NAME = 'smarterplan-shared-tags';
|
|
3410
3420
|
dictionnaryTags = new Map();
|
|
3411
3421
|
tagAddQueue = Promise.resolve();
|
|
3412
3422
|
mattertagToFollow = null;
|
|
@@ -3417,6 +3427,22 @@ class MatterportTagService {
|
|
|
3417
3427
|
tagService = null;
|
|
3418
3428
|
tagsCurrentOpacity = new Map();
|
|
3419
3429
|
tagsCurrentEnabled = new Map();
|
|
3430
|
+
/**
|
|
3431
|
+
* Single layer holding every Smarterplan tag, added to every view of the space so a
|
|
3432
|
+
* tag stays in place — same sid, same content — when the user switches between the
|
|
3433
|
+
* furnished and the Defurnished view. Tags added to the global sdk.Tag (or to a
|
|
3434
|
+
* view's own layer) belong to that view only, which is what made them pop in and out
|
|
3435
|
+
* on every view change.
|
|
3436
|
+
*
|
|
3437
|
+
* Deliberately NOT created with `{ common: true }`: in SDK 26.7.5 a common layer is
|
|
3438
|
+
* pushed into `getOrderedModelViews()` at creation time, and that call defaults to
|
|
3439
|
+
* `includeDefurnish: false`, so the Defurnished view never receives it — while
|
|
3440
|
+
* `View.addLayer()` refuses to repair it ("Layer is common. No need to add."). A
|
|
3441
|
+
* plain layer we attach to each view ourselves reaches every view, Defurnished
|
|
3442
|
+
* included. See attachSharedTagLayerToViews().
|
|
3443
|
+
*/
|
|
3444
|
+
sharedTagLayer = null;
|
|
3445
|
+
sharedTagLayerPromise = null;
|
|
3420
3446
|
constructor(navigationService) {
|
|
3421
3447
|
this.navigationService = navigationService;
|
|
3422
3448
|
}
|
|
@@ -3429,6 +3455,7 @@ class MatterportTagService {
|
|
|
3429
3455
|
return;
|
|
3430
3456
|
try {
|
|
3431
3457
|
this.onGoToTag.next(sid);
|
|
3458
|
+
// `open` only exists on the global Tag module, never on a layer-scoped one.
|
|
3432
3459
|
await sdk.Tag.open(sid);
|
|
3433
3460
|
}
|
|
3434
3461
|
catch (e) {
|
|
@@ -3436,6 +3463,102 @@ class MatterportTagService {
|
|
|
3436
3463
|
console.warn('Cannot open tag', sid, e);
|
|
3437
3464
|
}
|
|
3438
3465
|
}
|
|
3466
|
+
/**
|
|
3467
|
+
* Returns the SDK Tag module to use for an operation addressing an existing tag by ID
|
|
3468
|
+
* (icon, opacity, position, attachments, removal...): always the global sdk.Tag.
|
|
3469
|
+
*
|
|
3470
|
+
* A layer-scoped Tag module only exposes the *replayable* mutations, meant to build
|
|
3471
|
+
* the layer's own content; applying them to an already-created tag silently does
|
|
3472
|
+
* nothing — which is what left every pin white instead of carrying its icon. Only
|
|
3473
|
+
* `add` has to go through the layer, see getTagCreationModule().
|
|
3474
|
+
*/
|
|
3475
|
+
getTagModule(sdk, tagId) {
|
|
3476
|
+
return sdk?.Tag;
|
|
3477
|
+
}
|
|
3478
|
+
/**
|
|
3479
|
+
* Returns the Tag module every new tag must be created through: the shared layer
|
|
3480
|
+
* when the View API is available, the global sdk.Tag otherwise.
|
|
3481
|
+
*/
|
|
3482
|
+
async getTagCreationModule(sdk) {
|
|
3483
|
+
const layer = await this.ensureSharedTagLayer(sdk);
|
|
3484
|
+
return layer?.Tag || sdk?.Tag;
|
|
3485
|
+
}
|
|
3486
|
+
/**
|
|
3487
|
+
* Creates (once per SDK session) and returns the shared tag layer.
|
|
3488
|
+
* Resolves to null when the View API is unavailable, so callers transparently fall
|
|
3489
|
+
* back to the global sdk.Tag.
|
|
3490
|
+
*/
|
|
3491
|
+
async ensureSharedTagLayer(sdk) {
|
|
3492
|
+
if (this.sharedTagLayer)
|
|
3493
|
+
return this.sharedTagLayer;
|
|
3494
|
+
if (!sdk?.View?.createLayer)
|
|
3495
|
+
return null;
|
|
3496
|
+
if (!this.sharedTagLayerPromise) {
|
|
3497
|
+
this.sharedTagLayerPromise = Promise.resolve(sdk.View.createLayer(MatterportTagService.SHARED_TAG_LAYER_NAME))
|
|
3498
|
+
.then(async (layer) => {
|
|
3499
|
+
this.sharedTagLayer = layer;
|
|
3500
|
+
// A freshly created layer can come back toggled off, which hides its tags.
|
|
3501
|
+
if (layer && layer.toggled === false) {
|
|
3502
|
+
await layer.toggle(true).catch(() => { });
|
|
3503
|
+
}
|
|
3504
|
+
return layer;
|
|
3505
|
+
})
|
|
3506
|
+
.catch((e) => {
|
|
3507
|
+
// Allow a later retry (e.g. the SDK was not fully ready yet).
|
|
3508
|
+
this.sharedTagLayerPromise = null;
|
|
3509
|
+
if (isDevMode())
|
|
3510
|
+
console.warn('[MatterportTagService] Could not create the shared tag layer', e);
|
|
3511
|
+
return null;
|
|
3512
|
+
});
|
|
3513
|
+
}
|
|
3514
|
+
return this.sharedTagLayerPromise;
|
|
3515
|
+
}
|
|
3516
|
+
/**
|
|
3517
|
+
* Makes sure the shared layer is part of every view of the space, Defurnished
|
|
3518
|
+
* included. This is what actually shares the tags across views, and the reason the
|
|
3519
|
+
* layer must not be a common one: the SDK only performs the attachment for
|
|
3520
|
+
* non-common layers. Idempotent, so it can run on every view collection update.
|
|
3521
|
+
*/
|
|
3522
|
+
async attachSharedTagLayerToViews(sdk, views) {
|
|
3523
|
+
const layer = await this.ensureSharedTagLayer(sdk);
|
|
3524
|
+
if (!layer)
|
|
3525
|
+
return;
|
|
3526
|
+
for (const view of views) {
|
|
3527
|
+
if (!view?.addLayer || view.hasLayer?.(layer))
|
|
3528
|
+
continue;
|
|
3529
|
+
try {
|
|
3530
|
+
await view.addLayer(layer);
|
|
3531
|
+
}
|
|
3532
|
+
catch (e) {
|
|
3533
|
+
if (isDevMode())
|
|
3534
|
+
console.warn('[MatterportTagService] Cannot add the shared tag layer to view', view?.id, e);
|
|
3535
|
+
}
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
/**
|
|
3539
|
+
* Adds a tag through the shared layer so it exists in every view. Falls back
|
|
3540
|
+
* to the global sdk.Tag when the View API is unavailable; that call is raced against
|
|
3541
|
+
* a timeout as a safety net, since it never resolves while a Defurnished view is
|
|
3542
|
+
* active.
|
|
3543
|
+
*/
|
|
3544
|
+
async addTagToSdk(sdk, descriptor) {
|
|
3545
|
+
const sharedTagModule = await this.getTagCreationModule(sdk);
|
|
3546
|
+
try {
|
|
3547
|
+
const sidList = (await Promise.race([
|
|
3548
|
+
sharedTagModule.add(descriptor),
|
|
3549
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error('Tag.add timed out')), 4000)),
|
|
3550
|
+
]));
|
|
3551
|
+
if (sidList?.length)
|
|
3552
|
+
return sidList[0];
|
|
3553
|
+
}
|
|
3554
|
+
catch (error) {
|
|
3555
|
+
if (error?.message?.includes('already in use'))
|
|
3556
|
+
throw error;
|
|
3557
|
+
if (isDevMode())
|
|
3558
|
+
console.warn('[MatterportTagService] Tag.add failed/timed out', error?.message);
|
|
3559
|
+
}
|
|
3560
|
+
return null;
|
|
3561
|
+
}
|
|
3439
3562
|
/** Opens the most recently created tag in the viewer. */
|
|
3440
3563
|
async goToLastTag(sdk) {
|
|
3441
3564
|
if (!sdk || this.mattertagIDs.length === 0)
|
|
@@ -3450,36 +3573,40 @@ class MatterportTagService {
|
|
|
3450
3573
|
async addMattertagToViewer(sdk, mattertagData) {
|
|
3451
3574
|
if (!sdk)
|
|
3452
3575
|
return null;
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
console.log('sweep id: ', mattertagData.getSweepID());
|
|
3458
|
-
console.log('---------------');
|
|
3459
|
-
this.tagAddQueue = this.tagAddQueue.then(async () => {
|
|
3460
|
-
const data = mattertagData.getData();
|
|
3461
|
-
const existingId = data?.id || null;
|
|
3576
|
+
this.tagAddQueue = this.tagAddQueue
|
|
3577
|
+
.then(async () => {
|
|
3578
|
+
const descriptor = mattertagData.getMattertagDescriptor()[0];
|
|
3579
|
+
const existingId = descriptor?.id || null;
|
|
3462
3580
|
try {
|
|
3463
|
-
const
|
|
3464
|
-
if (
|
|
3465
|
-
|
|
3466
|
-
this.mattertagIDs.
|
|
3467
|
-
|
|
3468
|
-
|
|
3581
|
+
const sid = await this.addTagToSdk(sdk, descriptor);
|
|
3582
|
+
if (sid) {
|
|
3583
|
+
mattertagData.setMatterportSid(sid);
|
|
3584
|
+
if (!this.mattertagIDs.includes(sid)) {
|
|
3585
|
+
this.mattertagIDs.push(sid);
|
|
3586
|
+
}
|
|
3587
|
+
this.dictionnaryTags.set(sid, mattertagData);
|
|
3588
|
+
return sid;
|
|
3469
3589
|
}
|
|
3590
|
+
if (isDevMode())
|
|
3591
|
+
console.warn('[MatterportTagService] Tag.add returned no sid', descriptor);
|
|
3470
3592
|
}
|
|
3471
3593
|
catch (error) {
|
|
3472
3594
|
if (error?.message?.includes('already in use') && existingId) {
|
|
3473
3595
|
if (!this.dictionnaryTags.has(existingId)) {
|
|
3474
3596
|
this.mattertagIDs.push(existingId);
|
|
3475
|
-
this.dictionnaryTags.set(existingId, mattertagData);
|
|
3476
3597
|
}
|
|
3598
|
+
this.dictionnaryTags.set(existingId, mattertagData);
|
|
3477
3599
|
return existingId;
|
|
3478
3600
|
}
|
|
3479
3601
|
if (isDevMode())
|
|
3480
|
-
console.warn('
|
|
3602
|
+
console.warn('[MatterportTagService] addMattertagToViewer failed', error);
|
|
3481
3603
|
}
|
|
3482
3604
|
return null;
|
|
3605
|
+
})
|
|
3606
|
+
.catch((e) => {
|
|
3607
|
+
if (isDevMode())
|
|
3608
|
+
console.warn('[MatterportTagService] tagAddQueue rejected', e);
|
|
3609
|
+
return null;
|
|
3483
3610
|
});
|
|
3484
3611
|
return this.tagAddQueue;
|
|
3485
3612
|
}
|
|
@@ -3498,7 +3625,8 @@ class MatterportTagService {
|
|
|
3498
3625
|
}
|
|
3499
3626
|
this.tagAddQueue = this.tagAddQueue.then(async () => {
|
|
3500
3627
|
try {
|
|
3501
|
-
const
|
|
3628
|
+
const tagModule = await this.getTagCreationModule(sdk);
|
|
3629
|
+
const [createdSid] = await tagModule.add(...descriptor);
|
|
3502
3630
|
this.mattertagIDs.push(createdSid);
|
|
3503
3631
|
this.dictionnaryTags.set(createdSid, mattertagData);
|
|
3504
3632
|
await wait(100);
|
|
@@ -3545,36 +3673,6 @@ class MatterportTagService {
|
|
|
3545
3673
|
tagPos.z >= min.z - margin && tagPos.z <= max.z + margin);
|
|
3546
3674
|
});
|
|
3547
3675
|
}
|
|
3548
|
-
/**
|
|
3549
|
-
* Computes the final context-aware opacity for a single tag.
|
|
3550
|
-
* @param currentFloorSequence Authoritative current floor sequence from sdk.Floor.current
|
|
3551
|
-
* (null = single-floor model or unknown).
|
|
3552
|
-
* @param currentRooms Array of active rooms the camera is in.
|
|
3553
|
-
*/
|
|
3554
|
-
/*computeSingleTagContextOpacity(
|
|
3555
|
-
mattertagData: MattertagData,
|
|
3556
|
-
poseCamera: any,
|
|
3557
|
-
sweepCollection: any,
|
|
3558
|
-
currentFloorSequence: number | null,
|
|
3559
|
-
currentRooms: any[]
|
|
3560
|
-
): number {
|
|
3561
|
-
const mode = this.navigationService.currentCameraMode;
|
|
3562
|
-
|
|
3563
|
-
// 1. Check Floor
|
|
3564
|
-
const tagFloorId = this.getFloorIdForTag(mattertagData, sweepCollection);
|
|
3565
|
-
const currentFloorId = currentFloorSequence?.toString();
|
|
3566
|
-
if (tagFloorId && currentFloorId && tagFloorId !== currentFloorId) {
|
|
3567
|
-
return 0;
|
|
3568
|
-
}
|
|
3569
|
-
|
|
3570
|
-
// 2. Si Dollhouse -> Pleine opacité
|
|
3571
|
-
//if (mode !== CameraMode.INSIDE) return 1;
|
|
3572
|
-
|
|
3573
|
-
// 3. Si Inside -> Check pièce + Distance progressive
|
|
3574
|
-
//if (!this.isTagInRooms(mattertagData, currentRooms)) return 0;
|
|
3575
|
-
|
|
3576
|
-
return 1;
|
|
3577
|
-
}*/
|
|
3578
3676
|
/** Returns the ID of the most recently added tag. */
|
|
3579
3677
|
getLastTag() {
|
|
3580
3678
|
if (this.mattertagIDs.length === 0)
|
|
@@ -3624,10 +3722,11 @@ class MatterportTagService {
|
|
|
3624
3722
|
}
|
|
3625
3723
|
// Apply changes
|
|
3626
3724
|
// Tooltip and click management
|
|
3725
|
+
const tagModule = this.getTagModule(sdk, tagId);
|
|
3627
3726
|
const lastEnabled = this.tagsCurrentEnabled.get(tagId);
|
|
3628
3727
|
if (lastEnabled !== shouldBeEnabled) {
|
|
3629
3728
|
this.tagsCurrentEnabled.set(tagId, shouldBeEnabled);
|
|
3630
|
-
promises.push(
|
|
3729
|
+
promises.push(tagModule.allowAction(tagId, {
|
|
3631
3730
|
opening: shouldBeEnabled,
|
|
3632
3731
|
navigating: shouldBeEnabled,
|
|
3633
3732
|
docking: false
|
|
@@ -3637,16 +3736,26 @@ class MatterportTagService {
|
|
|
3637
3736
|
const lastOpacity = this.tagsCurrentOpacity.get(tagId) ?? -1;
|
|
3638
3737
|
if (Math.abs(lastOpacity - targetOpacity) > 0.05) {
|
|
3639
3738
|
this.tagsCurrentOpacity.set(tagId, targetOpacity);
|
|
3640
|
-
promises.push(
|
|
3739
|
+
promises.push(tagModule.editOpacity(tagId, targetOpacity).catch(() => { }));
|
|
3641
3740
|
}
|
|
3642
3741
|
}
|
|
3643
3742
|
await Promise.all(promises);
|
|
3644
3743
|
}
|
|
3744
|
+
/**
|
|
3745
|
+
* Drops the memoized opacity/enabled state so the next visibility pass re-applies it
|
|
3746
|
+
* to every tag. Needed after a view switch (furnished <-> defurnished): the SDK
|
|
3747
|
+
* re-renders the shared layer's tags and the cached values would otherwise make
|
|
3748
|
+
* updateTagsVisibilityForContext() skip them, leaving tags stuck invisible.
|
|
3749
|
+
*/
|
|
3750
|
+
resetVisibilityCache() {
|
|
3751
|
+
this.tagsCurrentOpacity.clear();
|
|
3752
|
+
this.tagsCurrentEnabled.clear();
|
|
3753
|
+
}
|
|
3645
3754
|
/** Removes a specific tag from the viewer and local dictionaries. */
|
|
3646
3755
|
async deleteMattertagFromId(sdk, mattertagID) {
|
|
3647
3756
|
try {
|
|
3648
3757
|
if (sdk)
|
|
3649
|
-
await sdk.
|
|
3758
|
+
await this.getTagModule(sdk, mattertagID).remove(mattertagID);
|
|
3650
3759
|
this.dictionnaryTags.delete(mattertagID);
|
|
3651
3760
|
const index = this.mattertagIDs.indexOf(mattertagID);
|
|
3652
3761
|
if (index > -1)
|
|
@@ -3669,7 +3778,7 @@ class MatterportTagService {
|
|
|
3669
3778
|
const sidsToRemove = [...this.mattertagIDs];
|
|
3670
3779
|
for (const sid of sidsToRemove) {
|
|
3671
3780
|
try {
|
|
3672
|
-
await sdk.
|
|
3781
|
+
await this.getTagModule(sdk, sid).remove(sid);
|
|
3673
3782
|
}
|
|
3674
3783
|
catch (e) { }
|
|
3675
3784
|
}
|
|
@@ -3680,7 +3789,7 @@ class MatterportTagService {
|
|
|
3680
3789
|
* Creates and configures a Mattertag from a POI, handling coordinates, normals, and sweep ID.
|
|
3681
3790
|
* Skips creation if a tag for the object already exists.
|
|
3682
3791
|
*/
|
|
3683
|
-
async createMattertagFromPOI(sdk, tagType, object, poi,
|
|
3792
|
+
async createMattertagFromPOI(sdk, tagType, object, poi, getTagFromElementId, setTagIconAndOpacity, injectHtmlInTag) {
|
|
3684
3793
|
const { tag } = getTagFromElementId(object.id);
|
|
3685
3794
|
if (tag)
|
|
3686
3795
|
return;
|
|
@@ -3742,10 +3851,11 @@ class MatterportTagService {
|
|
|
3742
3851
|
return;
|
|
3743
3852
|
try {
|
|
3744
3853
|
const iconName = `custom-icon-${mattertagID}`;
|
|
3854
|
+
const tagModule = this.getTagModule(sdk, mattertagID);
|
|
3745
3855
|
await sdk.Asset.registerTexture(iconName, iconPath);
|
|
3746
|
-
await
|
|
3856
|
+
await tagModule.editIcon(mattertagID, iconName);
|
|
3747
3857
|
if (applyOpacity) {
|
|
3748
|
-
await
|
|
3858
|
+
await tagModule.editOpacity(mattertagID, opacity);
|
|
3749
3859
|
}
|
|
3750
3860
|
}
|
|
3751
3861
|
catch (error) {
|
|
@@ -3809,16 +3919,17 @@ class MatterportTagService {
|
|
|
3809
3919
|
if (html && html.trim().length > 0 && sdk) {
|
|
3810
3920
|
const scriptTag = this.tagService.getScriptForTag(object, tagType);
|
|
3811
3921
|
html += `${scriptTag}`;
|
|
3922
|
+
const tagModule = this.getTagModule(sdk, tagID);
|
|
3812
3923
|
const [sandboxId, messenger] = await sdk.Tag.registerSandbox(html);
|
|
3813
3924
|
const attachmentID = this.tagsAttachments[tagID];
|
|
3814
3925
|
if (attachmentID) {
|
|
3815
3926
|
try {
|
|
3816
|
-
await
|
|
3927
|
+
await tagModule.detach(tagID, attachmentID);
|
|
3817
3928
|
}
|
|
3818
3929
|
catch (e) { }
|
|
3819
3930
|
}
|
|
3820
3931
|
this.tagsAttachments[tagID] = sandboxId;
|
|
3821
|
-
await
|
|
3932
|
+
await tagModule.attach(tagID, sandboxId);
|
|
3822
3933
|
// Attach the "View informations" handler in tooltip
|
|
3823
3934
|
messenger.on(TagAction.DETAIL_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
3824
3935
|
messenger.on(TagAction.TICKET_CLICK, this.tagService.onActionDetailClick.bind(this.tagService));
|
|
@@ -3831,11 +3942,12 @@ class MatterportTagService {
|
|
|
3831
3942
|
else if (sdk) {
|
|
3832
3943
|
const { comment, tagDescription } = this.tagService.getBillboardMediaToEmbed(object);
|
|
3833
3944
|
if (comment) {
|
|
3945
|
+
const tagModule = this.getTagModule(sdk, tagID);
|
|
3834
3946
|
// 1) Register the media attachment by passing the URL string(s).
|
|
3835
3947
|
// registerAttachment returns an array of attachment IDs.
|
|
3836
3948
|
const [attachmentID] = await sdk.Tag.registerAttachment(comment.externalLink);
|
|
3837
3949
|
// 2) Attach the registered media to the tag.
|
|
3838
|
-
await
|
|
3950
|
+
await tagModule.attach(tagID, attachmentID);
|
|
3839
3951
|
// 3) Determine media type for the billboard (PHOTO or VIDEO).
|
|
3840
3952
|
// Use a simple heuristic: YouTube/Vimeo -> VIDEO, otherwise PHOTO.
|
|
3841
3953
|
// The SDK exposes MediaType on the Tag namespace.
|
|
@@ -3843,7 +3955,7 @@ class MatterportTagService {
|
|
|
3843
3955
|
const mediaType = isVideo ? sdk.Mattertag.MediaType.VIDEO : sdk.Mattertag.MediaType.PHOTO;
|
|
3844
3956
|
// 4) Update the billboard text and media using editBillboard.
|
|
3845
3957
|
// editBillboard accepts Partial<Tag.EditableProperties> such as label, description, media.
|
|
3846
|
-
await
|
|
3958
|
+
await tagModule.editBillboard(tagID, {
|
|
3847
3959
|
label: object.title || 'Media',
|
|
3848
3960
|
description: tagDescription || '',
|
|
3849
3961
|
media: {
|
|
@@ -3869,9 +3981,14 @@ class MatterportTagService {
|
|
|
3869
3981
|
/** Clears all local tag data and resets the addition queue. */
|
|
3870
3982
|
clear() {
|
|
3871
3983
|
this.dictionnaryTags.clear();
|
|
3984
|
+
this.tagsCurrentOpacity.clear();
|
|
3985
|
+
this.tagsCurrentEnabled.clear();
|
|
3872
3986
|
this.tagAddQueue = Promise.resolve();
|
|
3873
3987
|
this.mattertagToFollow = null;
|
|
3874
3988
|
this.mattertagIDs = [];
|
|
3989
|
+
// A new space means a new SDK session, hence a new shared layer to create.
|
|
3990
|
+
this.sharedTagLayer = null;
|
|
3991
|
+
this.sharedTagLayerPromise = null;
|
|
3875
3992
|
}
|
|
3876
3993
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagService, deps: [{ token: MatterportNavigationService }], target: i0.ɵɵFactoryTarget.Injectable });
|
|
3877
3994
|
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: MatterportTagService, providedIn: 'root' });
|
|
@@ -3987,6 +4104,15 @@ class MatterportService {
|
|
|
3987
4104
|
this.navigationService.forbiddenSweeps = value;
|
|
3988
4105
|
}
|
|
3989
4106
|
tagAction = new Subject();
|
|
4107
|
+
/** Views (furnished, defurnished...) exposed by the SDK for the current space. */
|
|
4108
|
+
viewsByType = new Map();
|
|
4109
|
+
currentView = null;
|
|
4110
|
+
viewSubscriptions = [];
|
|
4111
|
+
/** Emits the active view every time the user switches between furnished/defurnished. */
|
|
4112
|
+
onViewChanged = new Subject();
|
|
4113
|
+
/** Delay left to the SDK to rebuild the layer's tags after a view switch. */
|
|
4114
|
+
static VIEW_SWITCH_REFRESH_DELAY_MS = 800;
|
|
4115
|
+
viewSwitchRestoreTimer = null;
|
|
3990
4116
|
get mattertagToFollow() {
|
|
3991
4117
|
return this.matterportTagService.mattertagToFollow;
|
|
3992
4118
|
}
|
|
@@ -4142,7 +4268,9 @@ class MatterportService {
|
|
|
4142
4268
|
default:
|
|
4143
4269
|
break;
|
|
4144
4270
|
}
|
|
4145
|
-
this.sdk.Asset.registerTexture('icon-position', this.config.my_config.icon_position)
|
|
4271
|
+
this.sdk.Asset.registerTexture('icon-position', this.config.my_config.icon_position)
|
|
4272
|
+
.catch((e) => { if (isDevMode())
|
|
4273
|
+
console.warn('icon-position texture registration failed', e); });
|
|
4146
4274
|
// Current Room (used for getting bounding box and eventually lazy load mattertag or object3D inside current Room)
|
|
4147
4275
|
this.sdk.Room.current.subscribe((currentRoom) => {
|
|
4148
4276
|
const rooms = Array.isArray(currentRoom) ? currentRoom : (currentRoom ? [currentRoom] : []);
|
|
@@ -4240,8 +4368,9 @@ class MatterportService {
|
|
|
4240
4368
|
if (!this.sdk || sid === this.mattertagToFollow)
|
|
4241
4369
|
return; // ignore when we are in positioning mode
|
|
4242
4370
|
try {
|
|
4243
|
-
|
|
4244
|
-
|
|
4371
|
+
const tagModule = this.matterportTagService.getTagModule(this.sdk, sid);
|
|
4372
|
+
if (tagModule?.allowAction) {
|
|
4373
|
+
tagModule.allowAction(sid, { opening: true, navigating: true, docking: false });
|
|
4245
4374
|
}
|
|
4246
4375
|
}
|
|
4247
4376
|
catch (e) {
|
|
@@ -4253,7 +4382,11 @@ class MatterportService {
|
|
|
4253
4382
|
};
|
|
4254
4383
|
// Wait for the application to reach PLAYING phase
|
|
4255
4384
|
if (this.sdk.App && this.sdk.App.state) {
|
|
4256
|
-
this.sdk.App.state.waitUntil((s) => s.phase === this.sdk.App.Phase.PLAYING).then(() => {
|
|
4385
|
+
this.sdk.App.state.waitUntil((s) => s.phase === this.sdk.App.Phase.PLAYING).then(async () => {
|
|
4386
|
+
// Create the common layer holding every tag before any tag is added, so that
|
|
4387
|
+
// tags are shared between the furnished and the defurnished views.
|
|
4388
|
+
await this.matterportTagService.ensureSharedTagLayer(this.sdk);
|
|
4389
|
+
this.initViews();
|
|
4257
4390
|
this.sdk.Camera.pose.subscribe((pose) => {
|
|
4258
4391
|
this.poseCamera = pose;
|
|
4259
4392
|
this.matterportTagService.updateTagsVisibilityForContext(this.sdk, this.sweepCollection, this.navigationService.currentCameraMode, this.mattertagToFollow, this.navigationService.currentFloorSequence, this.navigationService.currentRooms);
|
|
@@ -4393,7 +4526,7 @@ class MatterportService {
|
|
|
4393
4526
|
*/
|
|
4394
4527
|
enable_following_tag(mattertag) {
|
|
4395
4528
|
const OFFSET = 0.0001; // quasi-invisible mais suffit à éviter l'interception
|
|
4396
|
-
this.sdk.
|
|
4529
|
+
this.matterportTagService.getTagModule(this.sdk, mattertag).editPosition(mattertag, {
|
|
4397
4530
|
anchorPosition: {
|
|
4398
4531
|
x: this.poseMatterport.position.x + OFFSET,
|
|
4399
4532
|
y: this.poseMatterport.position.y,
|
|
@@ -4420,28 +4553,42 @@ class MatterportService {
|
|
|
4420
4553
|
//
|
|
4421
4554
|
/** Creates a temporary Mattertag that follows the user's cursor for positioning. */
|
|
4422
4555
|
async addCursorMattertag(mattertagData) {
|
|
4556
|
+
if (!this.poseMatterport && this.poseCamera) {
|
|
4557
|
+
this.poseMatterport = {
|
|
4558
|
+
position: { ...this.poseCamera.position },
|
|
4559
|
+
normal: { x: 0, y: -0.15, z: 0 },
|
|
4560
|
+
time: new Date().getTime()
|
|
4561
|
+
};
|
|
4562
|
+
}
|
|
4423
4563
|
if (!this.poseMatterport)
|
|
4424
4564
|
return;
|
|
4425
4565
|
this.mattertagToFollow = await this.addMattertagToViewer(mattertagData);
|
|
4566
|
+
if (!this.mattertagToFollow) {
|
|
4567
|
+
if (isDevMode())
|
|
4568
|
+
console.warn('addCursorMattertag: tag creation failed, mattertagToFollow is null');
|
|
4569
|
+
return;
|
|
4570
|
+
}
|
|
4426
4571
|
await wait(50);
|
|
4427
|
-
this.
|
|
4428
|
-
this.sdk.Tag.editOpacity(this.mattertagToFollow, 1);
|
|
4429
|
-
this.sdk.Tag.editPosition(this.mattertagToFollow, {
|
|
4430
|
-
anchorPosition: { ...this.poseMatterport.position },
|
|
4431
|
-
stemVector: {
|
|
4432
|
-
x: this.poseMatterport.normal.x * 0.3,
|
|
4433
|
-
y: this.poseMatterport.normal.y * 0.3,
|
|
4434
|
-
z: this.poseMatterport.normal.z * 0.3,
|
|
4435
|
-
}
|
|
4436
|
-
});
|
|
4572
|
+
const tagModule = this.matterportTagService.getTagModule(this.sdk, this.mattertagToFollow);
|
|
4437
4573
|
try {
|
|
4438
|
-
await
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4574
|
+
await tagModule.editIcon(this.mattertagToFollow, 'icon-position');
|
|
4575
|
+
await tagModule.editOpacity(this.mattertagToFollow, 1);
|
|
4576
|
+
await tagModule.editPosition(this.mattertagToFollow, {
|
|
4577
|
+
anchorPosition: { ...this.poseMatterport.position },
|
|
4578
|
+
stemVector: {
|
|
4579
|
+
x: (this.poseMatterport.normal?.x ?? 0) * 0.3,
|
|
4580
|
+
y: (this.poseMatterport.normal?.y ?? -0.15) * 0.3,
|
|
4581
|
+
z: (this.poseMatterport.normal?.z ?? 0) * 0.3,
|
|
4582
|
+
}
|
|
4442
4583
|
});
|
|
4584
|
+
await tagModule.allowAction(this.mattertagToFollow, {
|
|
4585
|
+
opening: true, navigating: false, docking: false
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4588
|
+
catch (e) {
|
|
4589
|
+
if (isDevMode())
|
|
4590
|
+
console.warn('addCursorMattertag: error configuring cursor tag', e);
|
|
4443
4591
|
}
|
|
4444
|
-
catch (e) { }
|
|
4445
4592
|
}
|
|
4446
4593
|
get tagAddQueue() {
|
|
4447
4594
|
return this.matterportTagService.tagAddQueue;
|
|
@@ -4470,7 +4617,7 @@ class MatterportService {
|
|
|
4470
4617
|
/** Applies a pre-registered icon to a Mattertag. */
|
|
4471
4618
|
async setRegistredIconForTag(mattertagID, iconName) {
|
|
4472
4619
|
try {
|
|
4473
|
-
this.sdk.
|
|
4620
|
+
this.matterportTagService.getTagModule(this.sdk, mattertagID).editIcon(mattertagID, iconName);
|
|
4474
4621
|
}
|
|
4475
4622
|
catch (e) {
|
|
4476
4623
|
if (isDevMode())
|
|
@@ -4488,7 +4635,7 @@ class MatterportService {
|
|
|
4488
4635
|
else {
|
|
4489
4636
|
iconName = `${iconName}_unavailable`;
|
|
4490
4637
|
}
|
|
4491
|
-
this.
|
|
4638
|
+
await this.editTagIcon(mattertagID, iconName);
|
|
4492
4639
|
return;
|
|
4493
4640
|
}
|
|
4494
4641
|
const stringTagType = poiTypeToString(mattertagData.getType());
|
|
@@ -4520,11 +4667,19 @@ class MatterportService {
|
|
|
4520
4667
|
opacity = tagIcon.opacity;
|
|
4521
4668
|
}
|
|
4522
4669
|
}
|
|
4670
|
+
await this.editTagIcon(mattertagID, iconName);
|
|
4671
|
+
}
|
|
4672
|
+
/**
|
|
4673
|
+
* Applies an icon to a tag. The call is awaited and its rejection reported: a
|
|
4674
|
+
* silently dropped promise here leaves the pin with its default white look.
|
|
4675
|
+
*/
|
|
4676
|
+
async editTagIcon(mattertagID, iconName) {
|
|
4523
4677
|
try {
|
|
4524
|
-
this.sdk.
|
|
4678
|
+
await this.matterportTagService.getTagModule(this.sdk, mattertagID).editIcon(mattertagID, iconName);
|
|
4525
4679
|
}
|
|
4526
4680
|
catch (error) {
|
|
4527
|
-
|
|
4681
|
+
if (isDevMode())
|
|
4682
|
+
console.warn('[MatterportService] editIcon failed for', mattertagID, iconName, error);
|
|
4528
4683
|
}
|
|
4529
4684
|
}
|
|
4530
4685
|
/** Navigates the camera to the most recently created tag. */
|
|
@@ -4545,12 +4700,9 @@ class MatterportService {
|
|
|
4545
4700
|
await this.sdk.Camera.lookAt(position, {
|
|
4546
4701
|
transition: this.sdk.Camera.TransitionType.FLY
|
|
4547
4702
|
});
|
|
4548
|
-
await this.sdk.Tag.open(mattertagID);
|
|
4549
|
-
}
|
|
4550
|
-
else {
|
|
4551
|
-
// Fallback for cases where we don't have local data yet
|
|
4552
|
-
await this.sdk.Tag.open(mattertagID);
|
|
4553
4703
|
}
|
|
4704
|
+
// `open` only exists on the global Tag module, never on a layer-scoped one.
|
|
4705
|
+
await this.sdk.Tag.open(mattertagID);
|
|
4554
4706
|
}
|
|
4555
4707
|
catch (error) {
|
|
4556
4708
|
if (isDevMode())
|
|
@@ -4634,6 +4786,9 @@ class MatterportService {
|
|
|
4634
4786
|
.logo-link,
|
|
4635
4787
|
.footer-logo,
|
|
4636
4788
|
.bottom-ui,
|
|
4789
|
+
img.logo-image,
|
|
4790
|
+
img[class^="logo-image"],
|
|
4791
|
+
img[class*=" logo-image"],
|
|
4637
4792
|
[data-testid="showcase-footer"] {
|
|
4638
4793
|
opacity: 0 !important;
|
|
4639
4794
|
visibility: hidden !important;
|
|
@@ -4660,7 +4815,7 @@ class MatterportService {
|
|
|
4660
4815
|
*/
|
|
4661
4816
|
async updateMatterTagContentForTagID(mattertagID, object = null, tagType = null) {
|
|
4662
4817
|
if (this.sdk) {
|
|
4663
|
-
await this.sdk.
|
|
4818
|
+
await this.matterportTagService.getTagModule(this.sdk, mattertagID).editBillboard(mattertagID, this.dictionnaryTags.get(mattertagID).getData());
|
|
4664
4819
|
}
|
|
4665
4820
|
// Mise à jour de l'icône immédiate
|
|
4666
4821
|
await this.matterportTagService.updateMatterTagContentForTagID(this.sdk, mattertagID, object, tagType, this.setTagIconAndOpacity.bind(this),
|
|
@@ -4703,7 +4858,7 @@ class MatterportService {
|
|
|
4703
4858
|
* @returns
|
|
4704
4859
|
*/
|
|
4705
4860
|
async createMattertagFromPOI(tagType, object, poi) {
|
|
4706
|
-
return this.matterportTagService.createMattertagFromPOI(this.sdk, tagType, object, poi, this.
|
|
4861
|
+
return this.matterportTagService.createMattertagFromPOI(this.sdk, tagType, object, poi, this.getTagFromElementId.bind(this), this.setTagIconAndOpacity.bind(this), this.injectHtmlInTag.bind(this));
|
|
4707
4862
|
}
|
|
4708
4863
|
/**
|
|
4709
4864
|
* Inject custom HTML as Mattertag content
|
|
@@ -4768,6 +4923,10 @@ class MatterportService {
|
|
|
4768
4923
|
const mattertagData = new MattertagData(poiType);
|
|
4769
4924
|
mattertagData.setSweepID(this.navigationService.resolveSweepUuid(this.poseCamera.sweep));
|
|
4770
4925
|
mattertagData.setRotation(this.poseCamera.rotation);
|
|
4926
|
+
const initialPosition = this.poseMatterport?.position ?? this.poseCamera.position;
|
|
4927
|
+
const initialNormal = this.poseMatterport?.normal ?? { x: 0, y: -0.15, z: 0 };
|
|
4928
|
+
mattertagData.setPosition({ ...initialPosition });
|
|
4929
|
+
mattertagData.setNormal({ ...initialNormal });
|
|
4771
4930
|
this.setInteractionMode(ViewerInteractions.ADDING);
|
|
4772
4931
|
await this.addCursorMattertag(mattertagData);
|
|
4773
4932
|
}
|
|
@@ -4885,8 +5044,14 @@ class MatterportService {
|
|
|
4885
5044
|
}
|
|
4886
5045
|
}
|
|
4887
5046
|
async updateMatterTagPosInSdkViewer(mattertagID, object, poiType, poi = null) {
|
|
4888
|
-
|
|
4889
|
-
|
|
5047
|
+
if (!poi || !poi.coordinate) {
|
|
5048
|
+
console.warn('updateMatterTagPosInSdkViewer: poi or poi.coordinate is missing', poi);
|
|
5049
|
+
return;
|
|
5050
|
+
}
|
|
5051
|
+
const IndexToUpdate = object.pois?.items ? object.pois.items.findIndex((u) => u?.id === poi.id) : -1;
|
|
5052
|
+
if (IndexToUpdate !== -1 && object.pois?.items) {
|
|
5053
|
+
object.pois.items[IndexToUpdate] = poi;
|
|
5054
|
+
}
|
|
4890
5055
|
const { x, y, z } = JSON.parse(poi.coordinate);
|
|
4891
5056
|
const newPosition = {
|
|
4892
5057
|
anchorPosition: {
|
|
@@ -4901,8 +5066,7 @@ class MatterportService {
|
|
|
4901
5066
|
z: 0,
|
|
4902
5067
|
},
|
|
4903
5068
|
};
|
|
4904
|
-
|
|
4905
|
-
this.sdk.Tag.editPosition(mattertagID, newPosition);
|
|
5069
|
+
this.matterportTagService.getTagModule(this.sdk, mattertagID).editPosition(mattertagID, newPosition);
|
|
4906
5070
|
this.dictionnaryTags
|
|
4907
5071
|
.get(mattertagID)
|
|
4908
5072
|
.setPosition(newPosition.anchorPosition);
|
|
@@ -4912,8 +5076,7 @@ class MatterportService {
|
|
|
4912
5076
|
continue;
|
|
4913
5077
|
}
|
|
4914
5078
|
if (currentTag.elementID === object.id && tagId !== mattertagID) {
|
|
4915
|
-
this.
|
|
4916
|
-
this.sdk.Tag.remove(tagId);
|
|
5079
|
+
await this.matterportTagService.deleteMattertagFromId(this.sdk, tagId);
|
|
4917
5080
|
break;
|
|
4918
5081
|
}
|
|
4919
5082
|
}
|
|
@@ -4955,6 +5118,140 @@ class MatterportService {
|
|
|
4955
5118
|
return null;
|
|
4956
5119
|
}
|
|
4957
5120
|
//
|
|
5121
|
+
// ---------- Views (furnished / defurnished) ----------
|
|
5122
|
+
//
|
|
5123
|
+
/**
|
|
5124
|
+
* Subscribes to the SDK View API to keep track of the views available for the space
|
|
5125
|
+
* and of the active one. Tags live in a shared common layer, so a view change only
|
|
5126
|
+
* requires re-applying their visibility, never re-creating them.
|
|
5127
|
+
*/
|
|
5128
|
+
initViews() {
|
|
5129
|
+
this.clearViewSubscriptions();
|
|
5130
|
+
this.viewsByType.clear();
|
|
5131
|
+
this.currentView = null;
|
|
5132
|
+
if (!this.sdk?.View?.views) {
|
|
5133
|
+
if (isDevMode())
|
|
5134
|
+
console.warn('[MatterportService] View API unavailable on this SDK version');
|
|
5135
|
+
return;
|
|
5136
|
+
}
|
|
5137
|
+
this.viewSubscriptions.push(this.sdk.View.views.subscribe({
|
|
5138
|
+
onCollectionUpdated: (collection) => {
|
|
5139
|
+
// SDK callbacks run outside Angular: re-enter the zone so the views made
|
|
5140
|
+
// available here (defurnish button...) are picked up by change detection.
|
|
5141
|
+
this.ngZone.run(() => {
|
|
5142
|
+
this.viewsByType.clear();
|
|
5143
|
+
for (const view of Object.values(collection)) {
|
|
5144
|
+
this.viewsByType.set(view.type, view);
|
|
5145
|
+
}
|
|
5146
|
+
});
|
|
5147
|
+
// Views are discovered progressively: make sure each one carries the shared
|
|
5148
|
+
// tag layer, otherwise its tags would not exist in that view.
|
|
5149
|
+
this.matterportTagService.attachSharedTagLayerToViews(this.sdk, Object.values(collection));
|
|
5150
|
+
},
|
|
5151
|
+
}));
|
|
5152
|
+
this.viewSubscriptions.push(this.sdk.View.current.subscribe((view) => {
|
|
5153
|
+
const changed = this.currentView?.id !== view?.id;
|
|
5154
|
+
this.currentView = view;
|
|
5155
|
+
if (!changed)
|
|
5156
|
+
return;
|
|
5157
|
+
this.restoreTagsForActiveView(view);
|
|
5158
|
+
this.ngZone.run(() => this.onViewChanged.next(view));
|
|
5159
|
+
}));
|
|
5160
|
+
}
|
|
5161
|
+
/**
|
|
5162
|
+
* Forces the opacity/enabled state to be pushed again to every tag. The SDK
|
|
5163
|
+
* re-renders the shared layer's tags on a view swap, and the memoized values would
|
|
5164
|
+
* otherwise make updateTagsVisibilityForContext() skip them, leaving tags invisible.
|
|
5165
|
+
*/
|
|
5166
|
+
reapplyTagsVisibility() {
|
|
5167
|
+
this.matterportTagService.resetVisibilityCache();
|
|
5168
|
+
this.refreshTagsVisibility();
|
|
5169
|
+
}
|
|
5170
|
+
/**
|
|
5171
|
+
* Puts the tags back in shape in the view that just became active.
|
|
5172
|
+
*
|
|
5173
|
+
* Activating a view re-materializes the shared layer's tags from the descriptors
|
|
5174
|
+
* recorded when they were added, so everything applied to a tag *afterwards* through
|
|
5175
|
+
* the global Tag module is dropped along the way: the custom icon (the pin falls back
|
|
5176
|
+
* to the descriptor's white) and the sandbox carrying the hover content. They have to
|
|
5177
|
+
* be applied again on the freshly rebuilt tags.
|
|
5178
|
+
*
|
|
5179
|
+
* Visibility is refreshed straight away so the tags show up without waiting, then
|
|
5180
|
+
* content is re-applied once the transition is over — re-applying it too early would
|
|
5181
|
+
* target tags the SDK has not rebuilt yet.
|
|
5182
|
+
*/
|
|
5183
|
+
restoreTagsForActiveView(view) {
|
|
5184
|
+
// A view only materializes its layers once activated: (re)attach the shared one.
|
|
5185
|
+
this.matterportTagService.attachSharedTagLayerToViews(this.sdk, [view])
|
|
5186
|
+
.then(() => this.reapplyTagsVisibility());
|
|
5187
|
+
this.reapplyTagsVisibility();
|
|
5188
|
+
clearTimeout(this.viewSwitchRestoreTimer);
|
|
5189
|
+
this.viewSwitchRestoreTimer = setTimeout(() => {
|
|
5190
|
+
this.refreshTagsContent()
|
|
5191
|
+
.catch((e) => {
|
|
5192
|
+
if (isDevMode())
|
|
5193
|
+
console.warn('[MatterportService] Cannot restore tags for view', view?.id, e);
|
|
5194
|
+
})
|
|
5195
|
+
.then(() => this.reapplyTagsVisibility());
|
|
5196
|
+
}, MatterportService.VIEW_SWITCH_REFRESH_DELAY_MS);
|
|
5197
|
+
}
|
|
5198
|
+
/**
|
|
5199
|
+
* Re-applies the icon and the injected HTML of every tag we own. Used after a view
|
|
5200
|
+
* switch, see restoreTagsForActiveView().
|
|
5201
|
+
*/
|
|
5202
|
+
async refreshTagsContent() {
|
|
5203
|
+
if (!this.sdk)
|
|
5204
|
+
return;
|
|
5205
|
+
// Snapshot: the dictionary can be mutated while the awaits below are pending.
|
|
5206
|
+
for (const [sid, mattertagData] of [...this.dictionnaryTags]) {
|
|
5207
|
+
if (sid === this.mattertagToFollow)
|
|
5208
|
+
continue;
|
|
5209
|
+
await this.setTagIconAndOpacity(sid, mattertagData);
|
|
5210
|
+
this.injectHtmlInTag(mattertagData.getType(), mattertagData.getObject(), sid)
|
|
5211
|
+
.catch((err) => {
|
|
5212
|
+
if (isDevMode())
|
|
5213
|
+
console.warn('[MatterportService] HTML re-injection failed for', sid, err);
|
|
5214
|
+
});
|
|
5215
|
+
}
|
|
5216
|
+
}
|
|
5217
|
+
clearViewSubscriptions() {
|
|
5218
|
+
clearTimeout(this.viewSwitchRestoreTimer);
|
|
5219
|
+
this.viewSwitchRestoreTimer = null;
|
|
5220
|
+
for (const subscription of this.viewSubscriptions) {
|
|
5221
|
+
try {
|
|
5222
|
+
subscription.cancel();
|
|
5223
|
+
}
|
|
5224
|
+
catch (e) {
|
|
5225
|
+
if (isDevMode())
|
|
5226
|
+
console.warn('[MatterportService] Cannot cancel view subscription', e);
|
|
5227
|
+
}
|
|
5228
|
+
}
|
|
5229
|
+
this.viewSubscriptions = [];
|
|
5230
|
+
}
|
|
5231
|
+
/** True when the space provides a defurnished view. */
|
|
5232
|
+
get hasDefurnishView() {
|
|
5233
|
+
return this.viewsByType.has(MatterportViewType.DEFURNISH);
|
|
5234
|
+
}
|
|
5235
|
+
/** True when the defurnished view is the active one. */
|
|
5236
|
+
get isDefurnishedView() {
|
|
5237
|
+
return this.currentView?.type === MatterportViewType.DEFURNISH;
|
|
5238
|
+
}
|
|
5239
|
+
/**
|
|
5240
|
+
* Switches between the defurnished view and the furnished one.
|
|
5241
|
+
* @param returnToStart Move the camera back to the view's start location.
|
|
5242
|
+
*/
|
|
5243
|
+
async toggleDefurnishView(returnToStart = false) {
|
|
5244
|
+
const target = this.isDefurnishedView
|
|
5245
|
+
? this.viewsByType.get(MatterportViewType.LAYERED_BASE) ?? this.viewsByType.get(MatterportViewType.BASE)
|
|
5246
|
+
: this.viewsByType.get(MatterportViewType.DEFURNISH);
|
|
5247
|
+
if (!target) {
|
|
5248
|
+
if (isDevMode())
|
|
5249
|
+
console.warn('[MatterportService] No target view to switch to');
|
|
5250
|
+
return;
|
|
5251
|
+
}
|
|
5252
|
+
await target.setActive(returnToStart);
|
|
5253
|
+
}
|
|
5254
|
+
//
|
|
4958
5255
|
// ---------- Viewer related (switch views, go to) ----------
|
|
4959
5256
|
//
|
|
4960
5257
|
async action_toolbox_floorplan() {
|
|
@@ -5006,6 +5303,9 @@ class MatterportService {
|
|
|
5006
5303
|
*/
|
|
5007
5304
|
async clearAll() {
|
|
5008
5305
|
console.log('removing viewer');
|
|
5306
|
+
this.clearViewSubscriptions();
|
|
5307
|
+
this.viewsByType.clear();
|
|
5308
|
+
this.currentView = null;
|
|
5009
5309
|
await this.action_delete_all_mattertags();
|
|
5010
5310
|
this.floors = null;
|
|
5011
5311
|
this.sweeps = null;
|
|
@@ -5253,6 +5553,13 @@ class ViewerService {
|
|
|
5253
5553
|
await this.actionAddObjectFromPOI(object, poi);
|
|
5254
5554
|
}
|
|
5255
5555
|
}));
|
|
5556
|
+
// Newly created tags have no opacity/allowAction applied yet (only set by
|
|
5557
|
+
// updateTagsVisibilityForContext, which runs on Mode/Sweep/Floor/Room/Camera
|
|
5558
|
+
// events). If this batch loaded after those fired, the tags stay in whatever
|
|
5559
|
+
// default state the SDK gave them until something else nudges a refresh.
|
|
5560
|
+
if (this.checkMode('Matterport')) {
|
|
5561
|
+
this.matterportService.refreshTagsVisibility();
|
|
5562
|
+
}
|
|
5256
5563
|
}
|
|
5257
5564
|
async actionAddObjectFromPOI(object, poi) {
|
|
5258
5565
|
if (this.checkMode('Matterport')) {
|
|
@@ -14840,5 +15147,5 @@ function floatValidator() {
|
|
|
14840
15147
|
* Generated bundle index. Do not edit.
|
|
14841
15148
|
*/
|
|
14842
15149
|
|
|
14843
|
-
export { AffectationService, AvatarComponent, BaseLateralTabService, BaseTagService, BaseUserService, BaseVisibilityService, CameraMode, CaptureService, CaptureViewer, CommentService, CommentType, Config, ContentService, CsvExportComponent, DomainService, DomainType, DurationToStringPipe, EmailStatus, EquipmentService, EventService, EventStatus, EventType, FeatureService, FeatureType, FilterService, HashtagFromIdPipe, HashtagService, InterventionService, InventoryStatus, LayerService, LevelStatus, LoaderComponent, Locale, LocaleService, MATTERPORT_SDK_KEY, MatterportImportService, MatterportService, MatterportTagCopyService, MattertagActionMode, MattertagData, MeasurementService, MenuBarComponent, MissionService, NavigationService, NavigatorService, NgxSmarterplanCoreModule, NgxSmarterplanCoreService, NodeService, Object3DService, OperationService, OrganisationService, PaymentStatus, PlanService, PoiService, PoiType, ProfileEntity, ProfileService, ProfileStatus, PropertyService, PropertyType, RoleStatus, SafeUrlPipe, SearchBarComponent, SearchObjectType, SearchService, SpModule, SpaceService, SpaceStatus, StatusEquipment, SupportModalComponent, SupportService, TagAction, TemplateService, TicketPriority, TicketStatus, TicketType, TicketsService, TimeDateToLocalStringPipe, TypeNote, UsernameFromIdPipe, ValidatorsService, ViewerInteractions, ViewerService, VisitService, ZoneChangeService, ZoneService, applyRigidTransformToPoint, applyRigidTransformToYRotationDeg, arraysContainSameElements, checkElementById, computeRigidTransform, convertTimestampToLocalZone, copyFileInS3, dateHasExpired, dateTimeToLocalString, deleteFromS3, distance, downloadBlob, downloadEquipmentDocument, downloadFile, downloadFileAsObject, durationToString, emailValidator, enumToArray, filterUniqueArrayByID, floatValidator, getBufferForFileFromS3, getCoefficientsForImage, getCurrentLang, getDistanceBetweenTwoPoints, getHighestLevelForMissions, getHighestRoleForMissions, getLevelsBelow, getLocaleLong, getLocaleShort, getMetaForImage, getRolesBelowForManager, getSignedFile, getSignedImageUrlForEquipment, getSignedImageUrlForProfile, getSignedImageUrlForSpace, getSpaceIDFromUrl, getVisitUrl, isEmptyObject, listFilesInFolder, mean, noEmptyValidator, numberToDateString, openDocument, openModalForVisitSwitch, poiTypeToString, pointToString, removeAllFilesFromFolderS3, removeNullKeysFromObject, showScanPointsOnPlanInDiv, shuffleArray, sortAlphabeticallyOnName, stringLocaleToEnum, stringToLowercaseNoSpaces, styleButton, textValidator, translateDatePeriod, uploadBase64Image, uploadBase64ImageWithRetry, uploadFileToS3, uploadJsonToS3, validEmail, wait, waitUntil };
|
|
15150
|
+
export { AffectationService, AvatarComponent, BaseLateralTabService, BaseTagService, BaseUserService, BaseVisibilityService, CameraMode, CaptureService, CaptureViewer, CommentService, CommentType, Config, ContentService, CsvExportComponent, DomainService, DomainType, DurationToStringPipe, EmailStatus, EquipmentService, EventService, EventStatus, EventType, FeatureService, FeatureType, FilterService, HashtagFromIdPipe, HashtagService, InterventionService, InventoryStatus, LayerService, LevelStatus, LoaderComponent, Locale, LocaleService, MATTERPORT_SDK_KEY, MatterportImportService, MatterportService, MatterportTagCopyService, MatterportViewType, MattertagActionMode, MattertagData, MeasurementService, MenuBarComponent, MissionService, NavigationService, NavigatorService, NgxSmarterplanCoreModule, NgxSmarterplanCoreService, NodeService, Object3DService, OperationService, OrganisationService, PaymentStatus, PlanService, PoiService, PoiType, ProfileEntity, ProfileService, ProfileStatus, PropertyService, PropertyType, RoleStatus, SafeUrlPipe, SearchBarComponent, SearchObjectType, SearchService, SpModule, SpaceService, SpaceStatus, StatusEquipment, SupportModalComponent, SupportService, TagAction, TemplateService, TicketPriority, TicketStatus, TicketType, TicketsService, TimeDateToLocalStringPipe, TypeNote, UsernameFromIdPipe, ValidatorsService, ViewerInteractions, ViewerService, VisitService, ZoneChangeService, ZoneService, applyRigidTransformToPoint, applyRigidTransformToYRotationDeg, arraysContainSameElements, checkElementById, computeRigidTransform, convertTimestampToLocalZone, copyFileInS3, dateHasExpired, dateTimeToLocalString, deleteFromS3, distance, downloadBlob, downloadEquipmentDocument, downloadFile, downloadFileAsObject, durationToString, emailValidator, enumToArray, filterUniqueArrayByID, floatValidator, getBufferForFileFromS3, getCoefficientsForImage, getCurrentLang, getDistanceBetweenTwoPoints, getHighestLevelForMissions, getHighestRoleForMissions, getLevelsBelow, getLocaleLong, getLocaleShort, getMetaForImage, getRolesBelowForManager, getSignedFile, getSignedImageUrlForEquipment, getSignedImageUrlForProfile, getSignedImageUrlForSpace, getSpaceIDFromUrl, getVisitUrl, isEmptyObject, listFilesInFolder, mean, noEmptyValidator, numberToDateString, openDocument, openModalForVisitSwitch, poiTypeToString, pointToString, removeAllFilesFromFolderS3, removeNullKeysFromObject, showScanPointsOnPlanInDiv, shuffleArray, sortAlphabeticallyOnName, stringLocaleToEnum, stringToLowercaseNoSpaces, styleButton, textValidator, translateDatePeriod, uploadBase64Image, uploadBase64ImageWithRetry, uploadFileToS3, uploadJsonToS3, validEmail, wait, waitUntil };
|
|
14844
15151
|
//# sourceMappingURL=smarterplan-ngx-smarterplan-core.mjs.map
|